Proposal
Add a Verification Discipline section to AGENTS.md covering the checks that separate work actually done from work that merely reports success. Implemented and in use at ptr727/ESPHome-NonRoot#165; raising it here because none of it is repo-specific.
The unifying property: each failure below is green. A skipped job and a passing job are indistinguishable in the aggregator; a pattern that matches less still exits zero; a gate that stops gating still reports success. Nothing in the existing lint, review, or status-check layers catches any of them.
Where it fits against what already exists
Three adjacent rules already cover narrower cases, so this complements rather than duplicates them:
- "Running the Linters Locally" documents how to invoke each linter, not the rule that all of them run before every push.
- The
changes-job note ("must succeed, not just not-fail... silently skipped") is the aggregator-specific instance of the general "green is not evidence" rule.
- The line-endings section covers preserving endings and notes
file is unreliable, but not the regex mechanism that corrupts them.
Proposed rules
New, not covered anywhere today:
- A test must assert the mechanism it names. Label each case by the behavior it proves, and satisfy yourself it would fail if that mechanism broke. A case that passes for an incidental reason - the right answer reached by the wrong path - is worse than no case, because it is later cited as evidence. (This one caused a real defect: a gate test passed because the branch happened to contain a matching file, not because the fail-open path worked. It was cited twice as proof before review found the gap.)
- Gates, filters, and gate-like watchers must fail loud, never narrow quietly. A pattern that silently matches less, an allowlist that silently stops matching, or a gate that silently stops gating all report success while doing nothing. When a construct exists to notice something, make the not-noticing case produce an error or an annotation.
- Run the repo's whole lint gate before every push, not the parts that look relevant. CI runs all of them, so a partial local run only defers the failure - and the tool most likely to catch a given change is often the one it seems least about (an edit that manipulates line endings is exactly when
editorconfig-checker matters).
- Editing CRLF files programmatically:
. matches \r in a regex, so a captured line keeps its carriage return and rejoining with \r\n yields CRCRLF. Prefer line-based edits (splitlines(keepends=True)) or literal replacement over regex reassembly. This is the mechanism behind the existing "a programmatic edit can silently flip endings" warning, and it is worth naming because the corruption is invisible in a diff.
Generalizations of rules that exist in narrower form:
- A green check is not evidence the work happened. A skipped job and a passing job are indistinguishable in the aggregated required check. When a job exists to exercise something, confirm from its log that it ran and produced the output it promises. (Generalizes the
changes-job note beyond that one job.)
- A workflow change is only fully exercised by CI. Extracting a
run: block and executing it locally validates the script and nothing else - secrets: inherit, permissions:, needs: wiring, and reusable-workflow inputs are only resolved by a real run. (Complements the existing permissions-before-if: and success/skipped allowlist notes, which are instances of the same class.)
Also worth considering
The README Rules index could carry one or two of these under Always - "Run the full lint gate before pushing" and "Make gates fail loud, never narrow quietly" are the two that read as fleet-wide invariants rather than technique. That would need the Table of Contents updated to match.
Reference implementation
ptr727/ESPHome-NonRoot#165 has the wording as merged, if it is easier to adapt than to rewrite.
Proposal
Add a
Verification Disciplinesection toAGENTS.mdcovering the checks that separate work actually done from work that merely reports success. Implemented and in use at ptr727/ESPHome-NonRoot#165; raising it here because none of it is repo-specific.The unifying property: each failure below is green. A skipped job and a passing job are indistinguishable in the aggregator; a pattern that matches less still exits zero; a gate that stops gating still reports success. Nothing in the existing lint, review, or status-check layers catches any of them.
Where it fits against what already exists
Three adjacent rules already cover narrower cases, so this complements rather than duplicates them:
changes-job note ("must succeed, not just not-fail... silently skipped") is the aggregator-specific instance of the general "green is not evidence" rule.fileis unreliable, but not the regex mechanism that corrupts them.Proposed rules
New, not covered anywhere today:
editorconfig-checkermatters)..matches\rin a regex, so a captured line keeps its carriage return and rejoining with\r\nyieldsCRCRLF. Prefer line-based edits (splitlines(keepends=True)) or literal replacement over regex reassembly. This is the mechanism behind the existing "a programmatic edit can silently flip endings" warning, and it is worth naming because the corruption is invisible in a diff.Generalizations of rules that exist in narrower form:
changes-job note beyond that one job.)run:block and executing it locally validates the script and nothing else -secrets: inherit,permissions:,needs:wiring, and reusable-workflow inputs are only resolved by a real run. (Complements the existing permissions-before-if:andsuccess/skippedallowlist notes, which are instances of the same class.)Also worth considering
The README
Rulesindex could carry one or two of these underAlways- "Run the full lint gate before pushing" and "Make gates fail loud, never narrow quietly" are the two that read as fleet-wide invariants rather than technique. That would need theTable of Contentsupdated to match.Reference implementation
ptr727/ESPHome-NonRoot#165 has the wording as merged, if it is easier to adapt than to rewrite.