Skip to content
4 changes: 3 additions & 1 deletion AUDIT.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ Per dimension, record `operational | not-operational | N/A`, each with a letter

A repo is **operational** only if every applicable check passes. A single applicable defect makes it not operational, regardless of how clean the rest looks. N/A items are excluded, never counted as failures.

An intent staleness advisory (`files.intent`) verified with nothing to adopt is recorded, not left standing. Record it as a registry `driftNote` naming `(files.intent)`. Name each verified copy as a code span joining its path and the hub sha the finding cites, such as `` `.editorconfig@<sha>` ``. The audit then clears that copy until its intent canonical changes again. It reports as stale an acknowledgement the advisory no longer raises at that sha, and a note naming no such span.

## 8. Report

Write `reports/<repo>/audit.md` from [`reports/_template.md`][template]. The report is a dimension x {letter, intent, verdict, evidence} table with `file:line` citations (WORKFLOW.md 5A style). It also has a drift section, and a list of proposed registry/spec updates (e.g. a resolved `classificationPending`). Rank findings most severe first.
Expand All @@ -212,7 +214,7 @@ A downstream repo uses its context where it is worth most. It **files findings a

**Re-running the audit needs a full hub clone with git history.** The verbatim stale-vs-modified classification and the intent staleness advisory walk the canonical's history (`git log` / `git show` from the hub root). A shallow hub clone cannot answer "matches a past hub revision". In one, `spec/audit.py` reports a single ERROR per repo and exits non-zero. `spec/audit.py --issue` exits 2 with the error on stderr. `spec/fidelity_honesty.py` stops before writing a report. Each error says to run `git fetch --unshallow origin` in that checkout. A downstream agent verifying one finding without the full history can instead compare against the current hub canonical on `main`. That canonical is the whole file for a file-level unit, or the named `## heading` block for a verbatim section. The comparison decides current-match but not stale-vs-modified. An agent picking up such an issue **re-runs the audit first and acts on the live result, not the pasted findings**. A repo moves between filing and pickup, so a stale block leads an agent to "fix" what is already fixed. Examples are re-requesting secrets that exist and attempting a no-op forward-sync. State the findings as evidence for *why* the issue was filed, never as the current state.

**Reconcile `driftNotes` in the same pass.** A registry `driftNote` records a *current* deviation from the baseline. Once the deviation is resolved the note is deleted, not left describing finished work, since hand-maintained prose drifts silently otherwise. `spec/audit.py` flags two shapes of note, neither of them gated on the rest of the audit being clean. A note asserting outstanding work in prose ("pending", "not yet", "missing", "behind", ...) is contradicted outright by a clean audit. Where findings are open it is raised as a question of which one it means. It is raised because gating the check on a clean audit meant one standing finding a repo could not clear exempted its whole note list. It is also raised because the repo carrying open findings is where a stale note is most likely. A note naming the check that would retire it, as an id in parentheses, is the mechanically checkable shape. Such a note is matched with the parentheses (`(hugo.generator.pinned)`, the bare id is not detected). It is surfaced on **every** run. The audit resolves the id against the catalog and confirms the repo declares its type. It then hands the check itself to the auditor, since section 4 above is judged by hand. **So a note naming a check id is retired by a person, not by a run.** For an id only `spec/checks.json` defines, the finding says the audit evaluates it, and the note goes once that check reports nothing. Write it that way anyway. The id says exactly what would close the note. The surfaced finding puts that decision in front of whoever runs the audit rather than leaving the note to sit until someone rereads it. A note naming a suppression id is not surfaced this way, since it suppresses a finding rather than naming a check to judge. The check it suppresses reports it once stale. A note naming `(python.directories.declared)` on a repo without the `python` type suppresses the Python discovery advisory. It is stale once no `.py` file remains. A note naming `(filenaming.scripts)` exempts each path it names as a code span from the file-naming dimension. A named path the check no longer flags is stale, and so is a note naming no path. The pending-marker check above still reads either.
**Reconcile `driftNotes` in the same pass.** A registry `driftNote` records a *current* deviation from the baseline. Once the deviation is resolved the note is deleted, not left describing finished work, since hand-maintained prose drifts silently otherwise. `spec/audit.py` flags two shapes of note, neither of them gated on the rest of the audit being clean. A note asserting outstanding work in prose ("pending", "not yet", "missing", "behind", ...) is contradicted outright by a clean audit. Where findings are open it is raised as a question of which one it means. It is raised because gating the check on a clean audit meant one standing finding a repo could not clear exempted its whole note list. It is also raised because the repo carrying open findings is where a stale note is most likely. A note naming the check that would retire it, as an id in parentheses, is the mechanically checkable shape. Such a note is matched with the parentheses (`(hugo.generator.pinned)`, the bare id is not detected). It is surfaced on **every** run. The audit resolves the id against the catalog and confirms the repo declares its type. It then hands the check itself to the auditor, since section 4 above is judged by hand. **So a note naming a check id is retired by a person, not by a run.** For an id only `spec/checks.json` defines, the finding says the audit evaluates it, and the note goes once that check reports nothing. Write it that way anyway. The id says exactly what would close the note. The surfaced finding puts that decision in front of whoever runs the audit rather than leaving the note to sit until someone rereads it. A note naming a suppression id is not surfaced this way, since it suppresses a finding rather than naming a check to judge. The check it suppresses reports it once stale. A note naming `(python.directories.declared)` on a repo without the `python` type suppresses the Python discovery advisory. It is stale once no `.py` file remains. A note naming `(filenaming.scripts)` exempts each path it names as a code span from the file-naming dimension. A named path the check no longer flags is stale, and so is a note naming no path. A note naming `(files.intent)` acknowledges a verified intent advisory, per section 7. The pending-marker check above still reads each of them.

## 9. Escalate

Expand Down
2 changes: 1 addition & 1 deletion registry/repos.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@
"consumerModel": "pull",
"releaseTrigger": "two-phase",
"pythonDirectories": ["RegressionTests"],
"driftNotes": ["Carries ARCHITECTURE.md and codecov.yml beyond the baseline.", "First csharp+python repo: a .NET application at the root plus a stdlib-only Python tooling subtree (RegressionTests/, uvx scripts profile - no uv.lock, pyproject carries only ruff+mypy config, PlexCleaner#855). python.uvlock.pinned is N/A for that subtree (no uv project). The subtree has no tests yet and its validator callers pass no python-directories input, both owed on adoption (python.directories.declared). codecov.yml stays required for the C# side. Reference for the csharp+python shape (issue #339)."]
"driftNotes": ["Carries ARCHITECTURE.md and codecov.yml beyond the baseline.", "First csharp+python repo: a .NET application at the root plus a stdlib-only Python tooling subtree (RegressionTests/, uvx scripts profile - no uv.lock, pyproject carries only ruff+mypy config, PlexCleaner#855). python.uvlock.pinned is N/A for that subtree (no uv project). codecov.yml stays required for the C# side. Reference for the csharp+python shape (issue #339)."]
},
{
"name": "ESPHome-NonRoot",
Expand Down
Loading
Loading