Concise rules the codebase and all agent suggestions should follow.
isValid... functions.strict typing; no any unless justified: // oxlint-disable-next-line typescript/no-explicit-any -- reason.readonly or as const) for constant structures / lookup tables.as X unless unavoidable.const enum (lint error).createDevice, updateState).is/has/can/should._ only when it is intentionally unused (the linter ignores it and reports it once used); otherwise use it or remove it.UPPER_SNAKE_CASE only for process env or true constants; otherwise camelCase.For every public/exported function or public methods (and important internal helpers):
/**
* One-line summary (starts with a verb, ends without period if short)
*
* Longer description (optional) explaining rationale or algorithm. Mention spec refs if relevant.
*
* Edge cases:
* - bullet 1
* - bullet 2
*
* @param {Type} name Description (units, accepted range, behavior on bounds)
* @returns {Type} Description (units, range, side effects)
* @throws {ErrorType} When it is thrown (only if the function throws)
*/
Rules:
@param and @returns with explicit types and descriptions (even if TS can infer): the linter requires them.@throws with its type and description for every error the function throws on purpose.°C * 100, lux, mireds, Pa).@returns {Promise<Type>}.Number.isFinite(n); clamp with Math.min/Math.max.In Matterbridge and its plugins the logger is always AnsiLogger.
log.debug for verbose internal transitions.log.info for state changes & received commands.log.notice for notices.log.warn for recoverable anomalies (out-of-range adjusted, missing optional attribute).log.error only for failed operations that stop progress.log.fatal only for failed operations that are not recoverable.node: prefix), external packages, internal and subpath imports, relative imports, styles.import { type Foo, bar } from './bar.js'.converts 100 lux to encoded value).Every source and test file starts with a JSDoc header block, before anything else except a shebang.
@file, @description, @author, @created, @version, @license. @file is the path relative to the repository root, with forward slashes (@file src/module.ts).Copyright <years> <owner>. line (add the current year when missing, never remove a year) and the license text./* oxlint-disable rule */ comments (one rule per line), one empty line, then the code.@file, @description and @author.@version only on functional changes, not style edits.@deprecated tag explaining alternative and planned removal version.Follow Conventional Commits. The full rules are in .github/commit-message-instructions.html.
<type>(<optional scope>): <subject>, with type one of feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert.The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
CHANGELOG.html under the current ## [x.y.z] - Dev branch heading.### Added, ### Changed, ### Deprecated, ### Removed, ### Fixed or ### Security.- [scope]: Description./**
* Convert lux to the Matter encoded illuminance value
*
* Matter spec § 2.2.5.1: MeasuredValue = 10,000 x log10(illuminance) + 1, in the range 1 to 0xFFFE.
*
* Edge cases:
* - < 1 or non-finite -> 0 (too low to be measured)
* - Caps at 0xFFFE
*
* @param {number} lux Illuminance in lux (>= 0).
* @returns {number} Encoded value (0, or 1..0xFFFE)
*/
function luxToMatterExample(lux: number): number {
if (!Number.isFinite(lux) || lux < 1) return 0;
return Math.min(Math.round(10000 * Math.log10(lux) + 1), 0xfffe);
}
Short, opinionated. If a rule isn't helping, propose a PR to adjust.