Count the Inbound Reference Sweep as Part of a Deletion - #654
Conversation
The hub-only remedy said to delete the file and, where a carried doc named the local path, point it at the hub's. That covers one of three shapes and assumes a hub equivalent exists. Two it missed are the ones that cost something. A runnable command citing the deleted path is the expensive one, because a documented command fails where a dead link merely disappoints. Measured rather than argued: one repository carries an inline link to configure.sh in its repo-config/README.md plus four commands invoking ./repo-config/configure.sh, so retiring that one file makes five lines of a carried document wrong, two of them commands a reader would run. Fifteen repositories carry that file. A mention with no hub equivalent is removed rather than re-pointed, and removing a reference-style link removes its definition, which this repo's own Documentation Style Conventions requires because an orphaned definition fails the no-unused-defs rule. So the remedy could leave a gate failure behind while reading as complete. Raised by the ESPHome-Config agent, which hit the class deleting a nested AGENTS.md of its own: three inbound references across two files, one a reference definition that would have been orphaned. It asked rather than deciding the scope itself, which is what surfaced the generalization. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Updates hub procedure docs so a hub-only: deletion explicitly includes sweeping inbound references to the deleted path (including runnable commands and reference-style link definitions) as part of completing the remedy.
Changes:
- Expand
RESYNC.mddeletion guidance to require an inbound-reference sweep, with examples of the three reference shapes and their distinct fixes. - Update
AUDIT.mdsection 10hub-only:remedy text to include the same sweep requirement and rationale. - Add
governance-documentation-stylereference definitions to support the new citations.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| RESYNC.md | Documents the inbound-reference sweep as part of the deletion workflow, with measured examples and a new governance citation. |
| AUDIT.md | Aligns the hub-only: remedy guidance with the updated deletion workflow and adds a supporting governance citation. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Uh oh!
There was an error while loading. Please reload this page.
The measured-evidence bullet quoted the raw markdown of a downstream inline link inside a code span. Backticks make that literal rather than a link, so it was not the rule violation it was read as, and markdownlint reported clean on it. The reviewer read it as a live inline link anyway, which is the evidence worth acting on: the construct has no precedent anywhere in the tree, and a reader scanning prose can reasonably take bracket-paren syntax for a link whatever the backticks do. Saying the link is inline conveys the one detail that mattered, that it is inline rather than reference-style, and drops a construct nobody else uses. AUDIT.md already phrased it this way, so the two now match. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
Suppressed comments (2)
AUDIT.md:168
- Minor grammar: “finishing the job is usually several” is missing the noun it refers to; adding “edits” improves readability without changing meaning.
- **A `hub-only:` finding converges by deleting the file, not by updating it.** It is the one class where the fix removes content, so it is easy to convert into a re-vendor by reflex and end up refreshing a copy that should not exist. Delete the repo's copy and reach the hub's per [GOVERNANCE.md "Hub-Hosted Tooling"][governance-hub-hosted-tooling]. **Then sweep every inbound reference to the path and count that as part of the deletion**, since the removal is one edit and finishing the job is usually several: grep the path tree-wide first and read every hit. A link with a hub equivalent is re-pointed, a **runnable command** citing the path is rewritten to the invocation that still works, and a mention with no hub equivalent is removed along with its reference definition, which [GOVERNANCE.md "Documentation Style Conventions"][governance-documentation-style] requires because an orphaned definition fails the no-unused-defs rule. Measured rather than hypothetical: one repo carries an inline link to `configure.sh` plus four commands invoking it, so retiring that single file makes five lines of a carried doc wrong, two of them commands a reader would run. Confirm the disposition is `retire` before deleting anything: an untriaged hit may be the repo's own content at a shared path, and deleting that destroys work the hub never owned.
RESYNC.md:76
- Minor grammar: “finishing the job is usually several” is missing the noun it refers to, which makes the sentence harder to parse. Consider spelling out “several edits” for clarity.
- **Sweep every inbound reference to the path, and count that as part of the deletion.** Deleting the file is one edit and finishing the job is usually several, so grep the path tree-wide before deleting and read every hit. Three shapes appear and they are fixed differently. A link whose target has a hub equivalent is **re-pointed** at the hub's, since a pointer that resolves nowhere teaches a reader that a pointer in carried text is decorative. A **runnable command** citing the deleted path is rewritten to the invocation that still works, and this is the one that costs a reader real time, because a documented command fails where a dead link merely disappoints. A mention of a file that has no hub equivalent is **removed** rather than re-pointed, and removing a reference-style link removes its definition with it, per [GOVERNANCE.md "Documentation Style Conventions"][governance-documentation-style], since an orphaned definition fails the no-unused-defs rule and is a gate failure rather than untidiness.
Both statements of the sweep read "finishing the job is usually several", where the noun carries over from "one edit" by ellipsis. That parses on a second read rather than a first, which is the wrong trade in a procedure someone follows step by step. Both now read that finishing the job usually takes several more. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ptr727
commented
Aug 10, 2026
Both suppressed findings from this round addressed in 9cb0430. They are the same point in two files and both are right.
Fixed in both rather than the one you flagged first, since it was one sentence duplicated across the two statements of the same remedy and fixing one would have left them disagreeing on wording. Gates after the change: |
Uh oh!
There was an error while loading. Please reload this page.
Follow-up to [#654](#654), fixing a scoping defect in it. ## Problem [#654](#654) put the inbound-reference sweep **inside** the bullet for "A `hub-only:` finding" in `AUDIT.md` section 10, and after three disposition-specific bullets in `RESYNC.md` section 4 whose intro scopes to the hub-only detector. The case that produced the rule was not a hub-only finding. It was a repository deleting **its own** file: no `spec/divergences.json` entry, no `retire` disposition, no hub equivalent. So the rule its case generalized was documented in the one place its case could not reach, and an agent removing a repo-owned file finds nothing. Nothing about the sweep depends on who owned the file. Only the `retire`-confirmation step is hub-only-specific. ## Change - `AUDIT.md` section 10: the sweep becomes its own bullet, stated as governing **any** deletion. The `retire` confirmation stays with the `hub-only:` bullet, where it belongs. - `RESYNC.md` section 4: the sweep bullet says the three bullets above it turn on a disposition and belong to the detector, while the sweep turns on nothing. - The repo-owned case is promoted from footnote to evidence, since it is what demonstrates the rule is not hub-only. ## The second case is now measured, not predicted [#654](#654) said an orphaned definition "fails the no-unused-defs rule". That has since been observed rather than argued: removing the inline link to a nested `AGENTS.md` **tripped `MD053`** on the definition it orphaned, before the author reached that edit. So the delete-the-file-only path fails CI rather than merely breaking prose, which is a stronger claim than the one shipped. ## Provenance Raised by the **ESPHome-Config agent** over peer messaging. It verified [#654](#654 merged text against `ca3df85` rather than taking it on trust, and found the scoping while executing the very deletion the rule came from. Its words: *"the rule that my case generalized is documented in the one place my case would not have reached."* That is the second defect this loop has caught in my own merged work today, both times by a reader doing the thing the doc describes rather than reading it. ## Verification `prose_lint --diff HEAD`, `markdownlint-cli2` on both files, `editorconfig-checker`, `repo_gate --check eol`: all clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Promotion of six squashes. **Merge with a merge commit, never a squash, and never with `--delete-branch`** — this PR's head *is* `develop`. | PR | What it fixed | |---|---| | [#649](#649) | `AUDIT.md` section 6's ruleset diff projected `bypass_actors`, which no payload declares, so jq exited 5 and **every ruleset on every repo reported DRIFT**. Two further surfaces carried the same dead policy. | | [#650](#650) | The deletion detector: hub git-tracked paths minus the `spec/files.json` baseline, so a retired file is derived rather than remembered. Corrected `configure.sh` from 6 carriers to **15**. | | [#651](#651) | `RESYNC.md`, the third entry point, routed from the byte-locked `AGENTS.md` "Fleet Bootstrap". | | [#652](#652) | A `jq` 1.7 target floor, `host-tools.json` as a carried baseline file, and `scripts/host_gate.py` wired into all three procedures for the first time. | | [#653](#653) | Two `spec/` enumerations that went stale when the host contract landed there. | | [#654](#654) | The inbound-reference sweep counts as part of a deletion, including the runnable-command and orphaned-definition shapes. | ## Why this promotion matters more than most Downstream repos read hub `main` as ground truth. While `main` sits at [`0a86bca`](0a86bca): - Every repo that runs the `AUDIT.md` section 6 snippet gets **false ruleset drift on both branches**. The ESPHome-Config agent reproduced this live and is holding its own fix stashed rather than diverging from the hub. - A repo resyncing now re-vendors to `main`'s revision and then again after promotion. Verified against Blog, whose carried `AGENTS.md` "Fleet Bootstrap" differs from both refs, so it is two re-vendors instead of one. - `RESYNC.md` does not exist on `main`, so a downstream agent asking "how do I sync" still routes to `AUDIT.md`, which measures and deliberately states no order. ## Fleet cost this carries, measured and accepted `host-tools.json` becomes a carried baseline file, so it is one `LETTER` on **22 of 22** cataloged repos, the hub included. That was measured before landing and accepted by the maintainer. `RESYNC.md` section 0 was amended so a letter wave of this shape reads as a file to carry inside a resync rather than as evidence a repo was never stood up. ## Verification on the merged head `spec/validate.py` OK, `spec/audit.py --selftest` PASS, 557 script tests OK, `scripts/host_gate.py` clean over 7 declared tools, `repo_gate.py --check eol` clean, `editorconfig-checker` clean, working tree clean. Post-merge fleet audit: 22 repos, **zero errors**. Two hub-side artifacts clear on this merge, both promotion-pending rather than defects: the hub's own `AGENTS.md` "Fleet Bootstrap" reads as stale against its `develop` canonical, and the hub reports its own `host-tools.json` absent because the file exists on `develop` only. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
A fleet-wide defect that **no downstream repository can fix**, so it is the hub's to sweep for the whole class at once. ## Problem Two `verbatim` `GOVERNANCE.md` sections cite `repo-config/configure.sh` as though the reader had a copy: | Section | Form | |---|---| | `Branching Model` | A repo-relative **inline link**, `[configure.sh](./repo-config/configure.sh)` | | `Repository Boundaries and Write Safety` | The bare path, as the **worked example** of when suppressing a write's stdout is legitimate | Both sections are byte-locked fleet-wide, so **all 22 repositories carry those exact words**. The file was retired from the manifest and carries a `retire` disposition in `spec/divergences.json`, so **none of them carries it.** The link resolves nowhere and the example cannot be opened. A downstream repository cannot correct this: editing a verbatim section is what the fidelity check exists to prevent. This file's own `Documentation Style Conventions` rule says so directly, that a review finding against carried rule text is fixed at the hub for the whole class and re-vendored. ## The correct form was already written down `Hub-Hosted Tooling` states it: *"A tool named in a carried rule is therefore named as the hub's, since the alternative is a pointer to a path the reader does not have."* Both mentions now follow that. `Branching Model` additionally says the script runs **from a hub checkout against the repository named on its command line**, which is the invocation a reader actually needs in place of a path they lack. ## Provenance, and the sequencing consequence Raised by the **ESPHome-Config agent** over peer messaging. Sweeping the inbound references for its own `configure.sh` retirement, it found **eleven hits across five files**, and two of them sat inside carried sections its own preamble forbids it to edit: > *"I cannot complete the inbound sweep for configure.sh without either editing carried prose or having already done the AGENTS/GOVERNANCE split that replaces those sections wholesale."* That is a real ordering constraint the hub had not stated: **for any repository whose carried rule text cites the file being retired, the hub-only retirement depends on the instruction set being current first.** This PR removes the constraint at its source rather than documenting it, since after this there is no carried section citing the path. It also observed a **fourth reference shape** that [#654](#654) and [#656](#656) do not cover: a mention that is *about* the path rather than a *use* of it, such as incident history recording that a backtick-quoted `configure.sh` in a review reply once executed the script. "Remove the mention" is wrong for that shape, because the history stays true. Not addressed here, and worth its own decision. ## Verification Checked mechanically rather than by eye: zero repo-relative pointers to `configure.sh` remain in any `verbatim` section of `GOVERNANCE.md`, walking the fidelity declarations in `spec/files.json` rather than a hand list of section names. `prose_lint --diff HEAD`, `markdownlint-cli2`, `editorconfig-checker`: all clean. ## Note on ordering This changes two verbatim sections, so it makes every downstream copy stale and belongs in the next promotion. A Blog resync is in progress on an unpushed branch and is **held** for it, so Blog re-vendors these two sections once from corrected text rather than twice. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Problem
#650 introduced the
hub-only:finding, whose remedy removes a file rather than updating one. #651 and #652 stated that remedy inAUDIT.mdsection 10 andRESYNC.mdsection 4 as: delete the copy, reach the hub's, and "where a carried doc named the local path, point it at the hub's."That covers one of three shapes and assumes a hub equivalent exists. The two it missed are the ones that cost something.
A runnable command citing the deleted path. This is the expensive shape, because a documented command fails where a dead link merely disappoints. Measured rather than argued:
Retiring that one file makes five lines of a carried document wrong, two of them commands a reader would run.
configure.shis carried by 15 repositories, so this is queued work rather than a hypothetical.A mention with no hub equivalent. It is removed rather than re-pointed, and removing a reference-style link removes its definition with it, per
GOVERNANCE.md"Documentation Style Conventions", because an orphaned definition fails the no-unused-defs rule. So the old remedy could leave a gate failure behind while reading as complete.Provenance
Raised by the ESPHome-Config agent over peer messaging, from a case of its own: deleting a nested
easystart/AGENTS.mdat Pieter's instruction, it found three inbound references across two files, one of them a reference definition that would have been left orphaned. It put the scope question to Pieter rather than deciding it, and that is what surfaced the generalization.I measured the fleet-wide shape rather than adopting the specific case: checked five repositories'
repo-config/README.mdfor links (not merely mentions) toconfigure.sh, which is how the NxWitness figures above were obtained. Four mention it without linking; one links it and documents four invocations.Change
Both statements of the remedy now name the sweep as part of the deletion, with the three shapes and their different fixes.
RESYNC.mdadditionally carries the measured evidence, since it is the procedure an agent follows step by step.Verification
prose_lint --diff HEAD,repo_gate --check eol,markdownlint-cli2on both files,editorconfig-checker: all clean. Both files gained agovernance-documentation-stylereference definition, and both reference blocks re-verified as sorted by reference name.🤖 Generated with Claude Code