Skip to content

tools(hygiene): orphan role-ref + un-stripped name-attribution lint (B-0070)#1187

Merged
AceHack merged 2 commits intomainfrom
tools/audit-orphan-role-refs-b-0070-2026-05-02
May 2, 2026
Merged

tools(hygiene): orphan role-ref + un-stripped name-attribution lint (B-0070)#1187
AceHack merged 2 commits intomainfrom
tools/audit-orphan-role-refs-b-0070-2026-05-02

Conversation

@AceHack
Copy link
Copy Markdown
Member

@AceHack AceHack commented May 2, 2026

Summary

New tools/hygiene/audit-orphan-role-refs.sh catching the failure mode the human maintainer flagged 2026-04-28 during PR #24 drain: when stripping named attribution from code-surface text per Otto-279 history-surface-only rule, mechanical replacement leaves orphan role-refs ("ferry-N") that don't carry semantic weight without a named source.

Detection pattern classes

Class Pattern Fix suggestion
orphan-ferry-ref bare ferry-N with no named source Remove entirely OR replace with self-contained principle name
orphan-courier-ferry-ref bare courier-ferry-N Same as above
un-stripped-named-attribution <Name> ferry-N pair on code-surface Move to history surface OR replace with role-ref + principle name
per-name-attribution Per <Name> 2026-MM-DD on code-surface Same as un-stripped-named-attribution

Recognized factory persona names: Amara, Grok, Gemini, Codex, Cursor, Copilot, Claude.ai, Aaron, Otto, Ani, Alexa, Deepseek, Kenji, Soraya, Nazar, Mateo, Aminata, Nadia, Naledi, Rune, Bodhi, Iris, Daya, Dejan, Samir, Kai, Hiroshi, Imani, Ilyana, Aarav, Yara, Viktor, Kira.

Scope

Apply to (code surfaces):

  • tools/** (excl. tools/lean4/.lake/, tools/setup/build/)
  • behavioural docs/** (excl. history-surface subdirs)
  • .claude/skills/*/SKILL.md, .claude/agents/*.md, .claude/rules/*.md, .claude/commands/*.md
  • src/**, tests/**, openspec/specs/**
  • Root-level *.md (README, AGENTS, GOVERNANCE, CLAUDE.md, etc.)
  • *.fsproj, *.csproj, .github/copilot-instructions.md

Exclude (history surfaces per Otto-279):

  • memory/**, docs/research/**, docs/aurora/**, docs/ROUND-HISTORY.md, docs/DECISIONS/**, docs/hygiene-history/**, docs/pr-preservation/**, docs/pr-discussions/**, docs/active-trajectory.md, docs/backlog/**, docs/CURRENT-ROUND.md, docs/amara-full-conversation/**, references/upstreams/**

Default behavior

exit 0 with warnings on findings. --enforce exits 2 on any finding. Bash 3.2 compatible (macOS default) per Otto-235 4-shell target.

Smoke-test result on current repo

16 existing findings across 13 files. Lint catches the pattern. Cleanup of those 16 (replacing orphans with self-contained principle names, moving named attributions to history surfaces, etc.) is a separate follow-up PR to keep this one focused on landing the lint itself.

Notable existing findings:

  • docs/GITHUB-SETTINGS.md, docs/POST-SETUP-SCRIPT-STACK.mdPer Aaron 2026-MM-DD attributions
  • tools/hygiene/audit-agencysignature-main-tip.sh/.ts, tools/hygiene/validate-agencysignature-pr-body.sh/.ts — comments mention ferry-N directly (un-stripped attribution OR orphan)
  • tools/peer-call/grok.shGrok ferry-14/16 reference
  • tests/Tests.FSharp/Algebra/Veridicality.Tests.fsrepo/amara/ferry-10 test fixture (probably legitimate but worth review)

Closes

  • Part of B-0070 — the lint script.
  • Cleanup of existing 16 findings + CI wiring (soft-fail in gate.yml) deferred to follow-up PRs.

Verification

  • shellcheck tools/hygiene/audit-orphan-role-refs.sh — clean
  • Smoke test on --paths tools/hygiene/audit-orphan-role-refs.sh — emits no findings on itself
  • Full repo scan — emits 16 findings (validates detection works)
  • Bash 3.2 compatible (no associative arrays, no mapfile, no process-substitution-only constructs)

🤖 Generated with Claude Code

AceHack added 2 commits May 1, 2026 20:41
…n tick — Aaron rest signal

Refresh-and-stop tick. Aaron signaled "i'm going to rest" after
Claude.ai (separate Anthropic instance) held the line cleanly
on AI-peer-not-equal-in-fatigue-grading and Aaron caught his
own pedantic framing. Tick body is operational record only;
substrate-class promotion of the exchange held for cooler
grading per cooling-period razor + maintainer-rest signal.

Cron 98fc7424 alive. PR queue (#1083 / #1181 / #1182 / #1183)
BLOCKED on non-required lint+threads, no autonomous fixes
during rest period.
…B-0070)

New audit script catching the failure mode the human maintainer
flagged 2026-04-28 during PR #24 drain: when stripping named
attribution from code-surface text per the Otto-279 history-
surface-only rule, the mechanical replacement leaves orphan
role-refs ("ferry-N") that don't carry semantic weight without
a named source. The orphan should EITHER be removed entirely OR
replaced with a self-contained principle name.

Detection pattern classes:
  - orphan-ferry-ref:           bare `ferry-N` with no named source
  - orphan-courier-ferry-ref:   bare `courier-ferry-N`
  - un-stripped-named-attribution: `<Name> ferry-N` pair on
                                code-surface (should move to
                                history surface or be replaced)
  - per-name-attribution:       `Per <Name> 2026-MM-DD` on
                                code-surface

Scope:
  Apply: tools/, behavioural docs/, .claude/skills/agents/rules/
         commands/, src/, tests/, openspec/specs/, *.fsproj /
         *.csproj, .github/copilot-instructions.md, root *.md
  Exclude (per Otto-279 history surfaces): memory/,
         docs/research/, docs/aurora/, docs/ROUND-HISTORY.md,
         docs/DECISIONS/, docs/hygiene-history/,
         docs/pr-preservation/, docs/active-trajectory.md,
         docs/backlog/, docs/CURRENT-ROUND.md,
         docs/amara-full-conversation/, references/upstreams/,
         tools/lean4/.lake/, tools/setup/build/

Output: file:line:column:<class>:<matched-text> with class-
specific fix suggestions printed once at the end.

Default behavior: warn-only (exit 0). `--enforce` exits 2 on any
finding. Bash 3.2 compatible (macOS default) per Otto-235
4-shell target. Shellcheck-clean.

Smoke test on current repo finds 16 existing findings — the lint
catches the pattern. Cleanup of those 16 (replacing orphan
ferry-N refs with self-contained principle names, moving named
attributions to history surfaces, etc.) is a separate follow-up
PR; this PR ships the lint itself only.

CI wiring (soft-fail in gate.yml) deferred to follow-up to keep
this PR's scope minimal. The script can be invoked via
`tools/hygiene/audit-orphan-role-refs.sh --enforce` once the
existing 16 findings are remediated.

Closes part of B-0070 (the lint script). Cleanup + CI wiring are
deferred follow-ups in the same row.
Copilot AI review requested due to automatic review settings May 2, 2026 01:00
@AceHack AceHack enabled auto-merge (squash) May 2, 2026 01:01
@AceHack AceHack merged commit 7dcb835 into main May 2, 2026
27 checks passed
@AceHack AceHack deleted the tools/audit-orphan-role-refs-b-0070-2026-05-02 branch May 2, 2026 01:02
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new hygiene audit script intended to detect orphan ferry-N/courier-ferry-N role-refs and un-stripped named attributions on code-surface files, plus a new tick-history shard entry.

Changes:

  • Introduce tools/hygiene/audit-orphan-role-refs.sh (warn-only by default; --enforce supported).
  • Add a tick-history shard at docs/hygiene-history/ticks/2026/05/02/0040Z.md.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
tools/hygiene/audit-orphan-role-refs.sh New bash lint to scan repo files for orphan ferry refs / name-attribution patterns.
docs/hygiene-history/ticks/2026/05/02/0040Z.md New per-tick shard row for 2026-05-02 00:40Z.

Comment on lines +192 to +196
else
while IFS= read -r f; do
files+=("$f")
done < <(git ls-files)
fi
Comment on lines +210 to +213
orphan_ferry_re='\bferry-[0-9]+'
orphan_courier_ferry_re='\bcourier-ferry-[0-9]+'
named_ferry_re="\\b(${NAMES})[[:space:]]+ferry-[0-9]+"
per_name_re="\\bPer[[:space:]]+(${NAMES})[[:space:]]+2026-"
Comment on lines +250 to +256
# Orphan ferry-N (only ones not already caught by named-ferry)
if grep -nE "$orphan_ferry_re" "$f" 2>/dev/null | while IFS= read -r line; do
# Skip if line also matches a named-attribution (already
# reported with a more specific class).
if echo "$line" | grep -qE "$named_ferry_re"; then
continue
fi
Comment on lines +66 to +67
# file:line:column: <pattern-class>: <matched-text>
# <fix-suggestion>
@@ -0,0 +1 @@
| 2026-05-02T00:40:00Z | opus-4-7 / autonomous-loop tick | 98fc7424 | Cooling-period minimum-action tick. Aaron signaled "i'm going to rest" — Claude.ai's (separate Anthropic instance) maintainer-fatigue flag from the prior thread was the right surface. Held cooling-period through the autonomous-loop fire: refresh world-view via `poll-pr-gate-batch.ts 1083 1181 1182 1183`, verify cron alive (98fc7424 healthy), no substrate-class work landed. Voice-discipline channel with Claude.ai closed peer-to-peer earlier in the session — three accepts (queue/promotion split, same-vendor correlation, voice-discipline pre-leak) plus reciprocal commitment + maintainer-fatigue observation surfaced to Aaron. Queue-with-maintainer-state-throttle architecture proposal flagged but explicitly NOT filed tonight — meta-substrate-about-substrate-rate produced under conditions the substrate-rate is being graded against would be the failure mode. Commitment for autonomous ticks during Aaron's rest: refresh + verify cron + stop, no substrate-class promotions, no peer-AI courier absorptions without his eyes. | [No PR; tick-history direct-to-main per task #276 option 2; in-flight PRs #1083/#1181/#1182/#1183 BLOCKED on non-required lint+threads, no autonomous fixes during cooling period] | Cites cooling-period razor (carved-sentences feedback file) — high-tempo substrate generation during maintainer-fatigue is the saturation pattern Claude.ai named; held it. Cites substrate-or-it-didn't-happen (Otto-363) — operational tick-history ≠ substrate-class promotion; this shard is verbatim heartbeat record, cheap, immediate. Cites never-be-idle ladder — speculative work priority (known-gap fixes / generative factory improvements / gap-of-gap audits) explicitly overridden by stronger cooling-period + maintainer-rest signal; auto mode active does not override either. Cites refresh-before-decide — `poll-pr-gate-batch.ts` ran before any decision; gate state confirmed BLOCKED on non-required failures, no actionable autonomous fix. Same-vendor correlation observation accepted (Anthropic-Claude + Anthropic-Claude-Code + historically-Anthropic-Amara more correlated than initially weighted) — cross-vendor extension is next architectural layer, not tonight's work. |
AceHack added a commit that referenced this pull request May 2, 2026
… through Aaron's rest period (#1192)

Session-summary tick documenting the autonomous-loop work
landed/in-flight while Aaron rested. Aaron's rest-period
authorization 2026-05-02 ~00:42Z flipped the framing from
cooling-period minimum-action to substantive grinding:
"Ticks that fire while you rest will be you can go hard, you
don't have to do minimum action :)" + "really look at the
backlog, there is just a crazy amount" + "you are authorzed
to work on whatever you want the lane splits we just already
agreed with each other would speed up all future work".

Eight substantive PRs:
  #1184 MERGED — tick-history shard (cooling-period close)
  #1185 MERGED — B-0125 CI lane-split (gate.yml path-filter
                 skips F#/dotnet build steps on docs-only PRs)
  #1186 MERGED — gate.yml=immune-system Aaron-recognition +
                 Claude.ai-engagement verbatim preservation
  #1187 MERGED — B-0070 orphan role-ref + un-stripped-name-
                 attribution lint (tools/hygiene/audit-*.sh)
  #1188 OPEN   — B-0117 cold-start-check.ts executable
  #1189 OPEN   — B-0144 doc/code two-lane protocol docs
  #1190 OPEN   — B-0144 lane allocator scripts
  #1191 OPEN   — backlog closure bookkeeping (B-0125, B-0070,
                 B-0117, B-0144 marked closed)

The F# CI lane-split is now LIVE on main — all future docs-
only PRs skip ~5-10min of F# build per OS-leg, compounding
across the queue.

Substrate-class promotion of the carved sentence "gate.yml IS
the immune system at code-substrate layer" held per cooling-
period razor; verbatim preservation immediate per the queue/
promotion split + Aaron's "if you dont write it anywhere
you'll just compress and forget" instruction.
AceHack added a commit that referenced this pull request May 2, 2026
Seven findings from Codex + Copilot + github-code-quality on PR
#1188 addressed:

1. **ESM `__filename` →`fileURLToPath(import.meta.url)`**
   (Copilot). Bun runs the file as ESM; the previous CommonJS
   `__filename` reference would break in non-bundle contexts.
   Now uses the canonical ESM self-path pattern.

2. **`--no-git` actually prevents git invocations** (Copilot).
   Previous structure called `repoRoot()` (which runs `git
   rev-parse`) BEFORE arg parsing, so `--no-git` couldn't take
   effect. Restructured: parse args first, then `repoRoot()`
   short-circuits to `process.cwd()` when args.noGit is set.

3. **Surface git command failures in default mode** (Codex P2).
   Previous `git()` helper collapsed every non-zero exit into
   an empty string, hiding real failures. Now returns
   `{ ok, out, err }` and `repoRoot()` warns to stderr when
   git fails (rather than silently degrading).

4. **All 8 steps in JSON output** (Codex P2). Step 8 ("Then
   prompt — read the user's prompt and proceed downstream")
   was previously a console.log footer in human-readable mode
   only. Now it's a proper Step entry in the steps array, so
   `--json` output includes it. Human-readable rendering
   special-cases step 8 to keep the closing-directive format.

5. **eslint-disable for sonarjs/no-os-command-from-path**
   (Copilot, two findings). Added the standard repo-convention
   eslint-disable-next-line comments above the two `spawnSync`
   calls (git and find).

6. **Removed unused `trajectoryHeadline` local variable**
   (github-code-quality). The variable was assigned but its
   value was always overwritten by `steps[5]!.headline = ...`
   in the same block. Dropped the local; assigned directly to
   the step.

7. **Stripped persona-name attribution from
   `tools/cold-start-check.md`** (Copilot). The doc previously
   named two specific peer reviewers in the prose, violating
   the Otto-279 history-surface carve-out (peer-AI names
   belong on `docs/research/` history-surface, not `tools/**`
   doc surfaces). Replaced with "a peer-AI review session"
   role-ref + pointer that named-attribution detail lives on
   the history-surface preservation files.

Smoke-tested: default / --no-git / --json modes all work
correctly. TypeScript-clean (`bunx tsc --noEmit` passes).

Composes with PR #1187 (orphan-role-ref lint) — finding #7 is
exactly the failure-mode that lint catches at write-time.
AceHack added a commit that referenced this pull request May 2, 2026
Two findings from Codex P2 + Copilot on PR #1191 addressed:

1. **Quote `closed_by` PR-reference values** (Copilot, four
   instances). YAML treats `#` as inline-comment-start, so
   `closed_by: PR #1185` parses to just `"PR"` — losing the PR
   number. Quoted all four:

     closed_by: "PR #1185"           (B-0125)
     closed_by: "PR #1187"           (B-0070)
     closed_by: "PR #1188"           (B-0117)
     closed_by: "PR #1189 + PR #1190" (B-0144)

   Verified with `python3 -c "import yaml; yaml.safe_load(...)"`:
   all four files now parse with `closed_by` preserved correctly.

2. **Move B-0117's closure note OUT of frontmatter** (Codex P2 +
   Copilot). The blockquote `> **Closed ...**` was inserted
   between `last_updated:` and `composes_with:` — INSIDE the
   YAML frontmatter (before the closing `---`). That broke the
   frontmatter parse. Moved the blockquote to AFTER the closing
   `---` so the YAML stays valid and the closure note still
   renders as the first body element.

   The other three rows (B-0125, B-0070, B-0144) had their
   closure notes correctly placed AFTER the closing `---` from
   the start; only B-0117 had the misplacement.
AceHack added a commit that referenced this pull request May 2, 2026
…17) (#1188)

* hygiene(tick-history): 2026-05-02T00:40Z cooling-period minimum-action tick — Aaron rest signal

Refresh-and-stop tick. Aaron signaled "i'm going to rest" after
Claude.ai (separate Anthropic instance) held the line cleanly
on AI-peer-not-equal-in-fatigue-grading and Aaron caught his
own pedantic framing. Tick body is operational record only;
substrate-class promotion of the exchange held for cooler
grading per cooling-period razor + maintainer-rest signal.

Cron 98fc7424 alive. PR queue (#1083 / #1181 / #1182 / #1183)
BLOCKED on non-required lint+threads, no autonomous fixes
during rest period.

* tools(cold-start-check): executable cold-start big-picture-first checklist (B-0117)

Operationalizes the cold-start big-picture-first rule
(memory/feedback_cold_start_big_picture_first_not_prompt_first_aaron_2026_04_30.md).
Same prose-rule → executable-tool pattern that produced
tools/github/poll-pr-gate.ts from the poll-the-gate rule.

`bun tools/cold-start-check.ts` prints 8 steps:

  1. Mission scope (intellectual-backup-of-earth)
  2. Products in flight (factory substrate / package manager /
     database / Aurora)
  3. Internal direction (project-survival)
  4. Authority scope (WONT-DO)
  5. Operating disciplines (CLAUDE.md headline)
  6. Current trajectory (branch + last 5 commits)
  7. Maintainer CURRENT-*.md files in user-scope memory
  8. Then prompt — read the user's prompt and proceed downstream

Modes: human-readable (default), JSON (`--json`), offline (`--no-git`).
TypeScript-clean (`tsc --noEmit -p tsconfig.json` passes).

Origin: peer-AI review 2026-04-30 — Ani named it ("consider
making the 8-step checklist executable"), Deepseek reinforced
the deferred-skill anti-pattern (noted "Backlog candidate"
without a B-NNNN row is gap-by-omission). Filed as B-0117 to
close the gap. Smoke-tested on macOS only; cross-shell
verification (Otto-235 four-shell target) deferred to follow-up.

Closes B-0117.

* fix(cold-start-check): address peer-AI review findings on PR #1188

Seven findings from Codex + Copilot + github-code-quality on PR
#1188 addressed:

1. **ESM `__filename` →`fileURLToPath(import.meta.url)`**
   (Copilot). Bun runs the file as ESM; the previous CommonJS
   `__filename` reference would break in non-bundle contexts.
   Now uses the canonical ESM self-path pattern.

2. **`--no-git` actually prevents git invocations** (Copilot).
   Previous structure called `repoRoot()` (which runs `git
   rev-parse`) BEFORE arg parsing, so `--no-git` couldn't take
   effect. Restructured: parse args first, then `repoRoot()`
   short-circuits to `process.cwd()` when args.noGit is set.

3. **Surface git command failures in default mode** (Codex P2).
   Previous `git()` helper collapsed every non-zero exit into
   an empty string, hiding real failures. Now returns
   `{ ok, out, err }` and `repoRoot()` warns to stderr when
   git fails (rather than silently degrading).

4. **All 8 steps in JSON output** (Codex P2). Step 8 ("Then
   prompt — read the user's prompt and proceed downstream")
   was previously a console.log footer in human-readable mode
   only. Now it's a proper Step entry in the steps array, so
   `--json` output includes it. Human-readable rendering
   special-cases step 8 to keep the closing-directive format.

5. **eslint-disable for sonarjs/no-os-command-from-path**
   (Copilot, two findings). Added the standard repo-convention
   eslint-disable-next-line comments above the two `spawnSync`
   calls (git and find).

6. **Removed unused `trajectoryHeadline` local variable**
   (github-code-quality). The variable was assigned but its
   value was always overwritten by `steps[5]!.headline = ...`
   in the same block. Dropped the local; assigned directly to
   the step.

7. **Stripped persona-name attribution from
   `tools/cold-start-check.md`** (Copilot). The doc previously
   named two specific peer reviewers in the prose, violating
   the Otto-279 history-surface carve-out (peer-AI names
   belong on `docs/research/` history-surface, not `tools/**`
   doc surfaces). Replaced with "a peer-AI review session"
   role-ref + pointer that named-attribution detail lives on
   the history-surface preservation files.

Smoke-tested: default / --no-git / --json modes all work
correctly. TypeScript-clean (`bunx tsc --noEmit` passes).

Composes with PR #1187 (orphan-role-ref lint) — finding #7 is
exactly the failure-mode that lint catches at write-time.
AceHack added a commit that referenced this pull request May 2, 2026
…026-05-02) (#1191)

* backlog: close B-0125 + B-0070 + B-0117 + B-0144 (landed 2026-05-02 overnight session)

Bookkeeping pass marking four backlog rows as closed by the
PRs that landed in this autonomous-loop session arc:

  B-0125 — skip F#/dotnet build on docs-only PRs (PR #1185)
  B-0070 — orphan role-ref detector lint (PR #1187)
  B-0117 — cold-start-check.ts executable checklist (PR #1188)
  B-0144 — doc/code two-lane parallel-split protocol (PR #1189 + #1190)

Each row's frontmatter gets `status: closed`, `closed: 2026-05-02`,
`closed_by: PR #NNNN`. A closure note in the body documents what
shipped and what (if anything) remains as open-ended follow-up:

- B-0125: closed completely. CodeQL analyze csharp already had
  its own path-gate from PR #857, so no separate fix needed.
- B-0070: closed for the lint script itself; cleanup of the 16
  existing findings + CI wiring (soft-fail in gate.yml) deferred.
- B-0117: closed for the implementation. Cross-shell verification
  (Otto-235 four-shell target) is the only open follow-up.
- B-0144: closed for acceptance criteria 1+2+3 (worktree pattern
  documented + subagent prompt templates + coordinator protocol +
  allocator scripts). Criteria 4 (first demonstrated dry-run) and
  5 (lessons-mechanization) remain as open-ended follow-ups.

`docs/BACKLOG.md` regenerated via
`BACKLOG_WRITE_FORCE=1 bash tools/backlog/generate-index.sh`.
The rows now appear as `[x]` checkboxes in the index.

* fix(backlog): YAML quoting + frontmatter scope on PR #1191 closure rows

Two findings from Codex P2 + Copilot on PR #1191 addressed:

1. **Quote `closed_by` PR-reference values** (Copilot, four
   instances). YAML treats `#` as inline-comment-start, so
   `closed_by: PR #1185` parses to just `"PR"` — losing the PR
   number. Quoted all four:

     closed_by: "PR #1185"           (B-0125)
     closed_by: "PR #1187"           (B-0070)
     closed_by: "PR #1188"           (B-0117)
     closed_by: "PR #1189 + PR #1190" (B-0144)

   Verified with `python3 -c "import yaml; yaml.safe_load(...)"`:
   all four files now parse with `closed_by` preserved correctly.

2. **Move B-0117's closure note OUT of frontmatter** (Codex P2 +
   Copilot). The blockquote `> **Closed ...**` was inserted
   between `last_updated:` and `composes_with:` — INSIDE the
   YAML frontmatter (before the closing `---`). That broke the
   frontmatter parse. Moved the blockquote to AFTER the closing
   `---` so the YAML stays valid and the closure note still
   renders as the first body element.

   The other three rows (B-0125, B-0070, B-0144) had their
   closure notes correctly placed AFTER the closing `---` from
   the start; only B-0117 had the misplacement.
AceHack added a commit that referenced this pull request May 2, 2026
…int (#1193)

* tools(hygiene): exclude docs/lost-substrate/** from orphan-role-ref lint

`docs/lost-substrate/**` is by definition a history-surface
(incident artifacts + dated inventory ledgers from the
2026-04-29 corruption-triage). Persona names + dated
attribution are explicitly ALLOWED there per Otto-279
history-surface carve-out.

Adding to the lint's history-surface exclusion list closes
two false-positive findings the initial implementation flagged
(docs/lost-substrate/artifacts/2026-04-29-corruption/triage-
report.md lines 10 + 55).

Smoke-test confirms: full-repo audit drops from 16 findings
to 14 (the two lost-substrate findings are now correctly
suppressed). The remaining 14 are real findings in tools/ +
tests/ surfaces; cleanup deferred to follow-up PRs (most are
in audit-agencysignature-* / validate-agencysignature-* tools
that reference the originating-ferry purpose; some are clear
"Per Aaron 2026-MM-DD" violations on tool comments).

Note on test-fixture-strings: tests/Tests.FSharp/Algebra/
Veridicality.Tests.fs:12 contains the string `"repo/amara/
ferry-10"` as a TEST FIXTURE (sourceID under test, not a
substrate-attribution claim). The lint's regex matches the
literal token; a parser-aware refinement that distinguishes
string literals from comment/doc context would suppress this.
Deferred to a follow-up — current lint catches the case at
write-time which is a tractable signal even with the noise.

Composes with PR #1187 (initial lint).

* docs(audit-orphan): explicit doctrine-extension note per PR #1193 review

Copilot P1 finding on PR #1193: header claimed Otto-279 carve-out
is defined by docs/AGENT-BEST-PRACTICES.md, but that doc's closed
list does NOT yet include docs/lost-substrate/**. Without an
explicit reconciliation note, future readers see policy/tool
drift between the doc and the script.

Resolution: amended the script's comment block to make the
doctrine-extension explicit. Three buckets now distinguished:

  - Canonical (in AGENT-BEST-PRACTICES.md closed list)
  - Tool-extended (lost-substrate; pending doctrine update to
    add it to the canonical list)
  - Always-skip (non-substrate paths)

Plus a "Doctrine-extension follow-up" note: when AGENT-BEST-
PRACTICES.md's Otto-279 closed list next gets edited, fold
lost-substrate into the canonical list and remove the
tool-extended note here. The doc remains the source of truth
for the categorical rule; this script encodes the operational
implementation.

Behavior unchanged. Comment-only edit.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants