|
| 1 | +--- |
| 2 | +name: 'Verify Server Endpoint Context' |
| 3 | +description: 'Verify that behavior server logs and thrown errors start with the server name and end with the Matter endpoint id and number' |
| 4 | +argument-hint: 'Optional scope, notes, or request to fix violations' |
| 5 | +agent: 'agent' |
| 6 | +--- |
| 7 | + |
| 8 | +Verify endpoint context in Matterbridge behavior server implementations. |
| 9 | + |
| 10 | +Scope: |
| 11 | + |
| 12 | +- Inspect all server implementations in [packages/core/src/behaviors](../../packages/core/src/behaviors). |
| 13 | +- Inspect all server classes declared in files under [packages/core/src/devices](../../packages/core/src/devices), including files that also contain device classes or helper code. |
| 14 | +- In device files, limit the check to server class bodies. Do not report logs or throws belonging only to device classes or unrelated helpers. |
| 15 | + |
| 16 | +Checks: |
| 17 | + |
| 18 | +- Verify every textual log and throw message in scope starts with the exact name of its enclosing server class followed by a colon and one space. For example: |
| 19 | + |
| 20 | + ```typescript |
| 21 | + MatterbridgeBooleanStateConfigurationServer: |
| 22 | + ``` |
| 23 | + |
| 24 | +- Verify every textual log and throw message in scope ends with this exact fragment: |
| 25 | + |
| 26 | + ```typescript |
| 27 | + (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber}) |
| 28 | + ``` |
| 29 | + |
| 30 | +- Treat calls to every log level as logs, including `debug`, `info`, `notice`, `warn`, `error`, and `fatal`, whether the logger is accessed through `device.log`, `this.state.log`, `this.log`, or another local reference. |
| 31 | +- Verify every error message created by a `throw` statement in scope follows the same prefix and suffix rules, including errors constructed directly in the `throw` and errors assigned to a variable before being thrown. |
| 32 | +- Follow local variables and simple helper methods when needed so multiline calls, template literals, and indirectly constructed error messages are not missed. |
| 33 | +- Do not accept a missing or abbreviated server name, text before the server name, or a prefix that does not match the enclosing server class name exactly. |
| 34 | +- Do not accept alternate endpoint formats, missing parentheses, a colon separator, `endpoint.id`, `endpoint.number`, messages containing only one endpoint component, or any text after the endpoint fragment's closing parenthesis. |
| 35 | +- Do not require the fragment in a log or thrown value that has no textual message, but report that case separately for manual review. |
| 36 | +- Ignore comments, JSDoc examples, tests, generated output, and imported server implementations. |
| 37 | + |
| 38 | +Plugin forwarding contract: |
| 39 | + |
| 40 | +- For every overridden Matter command handler in scope, verify that forwarding to the plugin through `device.commandHandler.executeHandler(...)` occurs immediately after the command-entry log. |
| 41 | +- Before the forwarding call, allow only the minimal local lookup required to access the logger and command handler, such as `const device = this.endpoint.stateOf(MatterbridgeServer)`, followed by the command-entry log. |
| 42 | +- Verify only the command-entry log immediately before forwarding uses the `info` level, for example `device.log.info(...)`. A command-entry log at `debug`, `notice`, `warn`, `error`, `fatal`, or any other level is not compliant. |
| 43 | +- Do not require any other log to use `info`. Logs outside the command-entry position may use any appropriate log level, but their messages must still satisfy the server-name prefix and endpoint suffix rules. |
| 44 | +- The forwarding call must be awaited before execution continues. |
| 45 | +- Do not allow request validation, assertions, conditionals, early returns, thrown errors, state reads used for decisions, state changes, event emission, additional logging, or other side effects between the command-entry log and completion of the awaited forwarding call. |
| 46 | +- Verify all validation and state mutation occur only after the awaited forwarding call. |
| 47 | +- Report a missing command-entry log, command-entry log at a level other than `info`, missing forwarding call, non-awaited forwarding call, or any disallowed operation before forwarding completes as a plugin forwarding contract violation. |
| 48 | + |
| 49 | +Compliant examples from [booleanStateConfigurationServer.ts](../../packages/core/src/behaviors/booleanStateConfigurationServer.ts): |
| 50 | + |
| 51 | +```typescript |
| 52 | +throw new StatusResponseError( |
| 53 | + `MatterbridgeBooleanStateConfigurationServer: requested alarm mode is not supported (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`, |
| 54 | + Status.ConstraintError, |
| 55 | +); |
| 56 | + |
| 57 | +override async suppressAlarm(request: BooleanStateConfiguration.SuppressAlarmRequest): Promise<void> { |
| 58 | + const device = this.endpoint.stateOf(MatterbridgeServer); |
| 59 | + device.log.info( |
| 60 | + `MatterbridgeBooleanStateConfigurationServer: suppressing alarm ${debugStringify(request.alarmsToSuppress)}${nf} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`, |
| 61 | + ); |
| 62 | + await device.commandHandler.executeHandler('BooleanStateConfiguration.suppressAlarm', { |
| 63 | + command: 'suppressAlarm', |
| 64 | + request, |
| 65 | + cluster: BooleanStateConfigurationServer.id, |
| 66 | + attributes: this.state as unknown as ClusterAttributeValues<(typeof BooleanStateConfiguration)['attributes']>, |
| 67 | + endpoint: this.endpoint as MatterbridgeEndpoint, |
| 68 | + context: this.context, |
| 69 | + }); |
| 70 | + this.#assertAlarmModesSupported(request.alarmsToSuppress); |
| 71 | +} |
| 72 | +``` |
| 73 | + |
| 74 | +Output requirements: |
| 75 | + |
| 76 | +- List each violation with a concise file and line reference, the log or throw kind, and the current message. |
| 77 | +- For each violation, identify whether the server-name prefix, endpoint suffix, or both are invalid. |
| 78 | +- List each plugin forwarding contract violation with the command handler, the invalid operation or ordering, and whether the command-entry log is missing or uses the wrong level, the forwarding call is missing, or forwarding is not awaited. |
| 79 | +- Group results by `behaviors` and `devices`. |
| 80 | +- If no violations are found, explicitly state that every in-scope log and thrown error starts with the enclosing server name and ends with the required endpoint fragment, and every command handler respects the plugin forwarding contract. |
| 81 | +- Do not modify files unless I explicitly ask you to fix the violations. |
| 82 | +- If fixes are requested, preserve each existing message where practical, prepend the exact enclosing server class name and `: `, append the exact endpoint fragment as the final message content, move awaited plugin forwarding before validation and state changes, then re-run the full verification and report any remaining violations. |
| 83 | + |
| 84 | +Post-edit validation: |
| 85 | + |
| 86 | +- After making any edits, run `npm run format`, `npm run build`, and `npm run lint` from the repository root. |
| 87 | +- Always run tests after making any edits. Use `npm run test` for the full test suite or `npm run test -- <testfile>` for a single relevant test file. |
| 88 | +- When using a single test file, run the complete file that covers every edited server. Do not rely only on a test-name filter, editor test adapter, source scan, type check, or previously completed test run. |
| 89 | +- Treat a test regression as a failed verification. Investigate whether the edit caused the failure and fix edit-related failures before completing the task. |
| 90 | +- Re-run any failed edit-related command or test after fixing it. |
| 91 | +- Report the result of formatting, build, lint, and tests. If any command cannot be run or any failure remains, report that explicitly with the failing command or test. |
0 commit comments