Skip to content

chore(repo): untrack generated artifacts and anchor the evidence ignore rule - #210

Merged
cryptoxdog merged 12 commits into
mainfrom
claude/audit-hygiene-untrack-generated-v2
Sep 19, 2026
Merged

cryptoxdog merged 12 commits into
mainfrom
claude/audit-hygiene-untrack-generated-v2

Conversation

@cryptoxdog

@cryptoxdog cryptoxdog commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

Repository hygiene. Untracks 105 generated artifacts whose directories .gitignore already names, removes four orphaned files, and — first — fixes the ignore rule that made a mechanical cleanup dangerous.

Type of change

  • type:refactor — no behavior change

Area

  • area:infrastructure — config

Checklist

  • npm run verify:all passes locally
  • npx tsc --noEmit passes (no type errors)
  • No secrets or credentials committed
  • ADR added/updated — not applicable
  • VALIDATION.md updated — not applicable
  • DECISION_LOG.md updated — not applicable

Reading this PR

Stacked on #208; it currently shows 9 commits and only the last three are this PR's. This branch is cut from #208's head because it needs that PR's validation/validation_report.yaml untracking in order to publish at all — site:validate rewrote a tracked file mid-gate, which invalidated the release receipt. Once #208 merges, this diff collapses to its own three commits. Merge order: #208#209 → this.

Commit Change
9e8dc7a Anchor evidence/ so it stops matching real source
9f03ad3 Untrack 105 generated build/evidence/per-run artifacts
011f3e1 Remove orphaned root run-artifacts and a duplicated doc

The anchoring commit is the important one

.gitignore:45 was evidence/ — unanchored, so it matched a directory of that name at any depth. git ls-files -ci --exclude-standard reported 255 tracked files as ignored, and 148 of those were not debris:

  • src/pipeline/evidence/*.ts — 21 files, the pipeline's evidence layer (EvidenceStore, ReleaseReceipt, RedesignExecutionIntegrityReceipt, …)
  • docs/reports_and_test_results/**/evidence/** — 127 files, dated report bundles committed deliberately

Nothing was broken while they stayed tracked, because .gitignore does not apply to files already in the index. The hazard was the cleanup: a mechanically derived git rm --cached $(git ls-files -ci) would have untracked the pipeline's evidence layer, and local validation would still have passed, because the files remain on disk. Only a fresh clone would have failed.

Anchoring to /evidence/ confines the rule to the repository root, where the Safe Haven per-run evidence it was written for actually lives. 255 → 107, and every remaining entry is genuine generated output.

What was untracked

105 files, index-only — everything stays on disk and regenerates from its own tooling:

  • build/** — 99 files across 61 golden run directories (~9.2 MB): 62 pipeline.log files and 20 PNG captures, several over 1 MB. .gitignore:12 says build/; README.md:193 says the same in prose.
  • evidence/** — 4 files, per-run Safe Haven output.
  • astro_template/validation/*.jsonl — 2 files, named at .gitignore:23. Write-only; nothing reads them.

The list was derived mechanically from git ls-files -ci --exclude-standard rather than hand-written — that is what makes a 105-file delete reviewable, since it is exactly the set git itself reports. Two entries are excluded deliberately: .l9/ci.json (re-included by !.l9/ci.json as the CI class declaration org-ci.yml reads) and tests/golden/safehaven/fixtures/positive-receipt.json (documented as a built fixture in tests/golden/safehaven/RUNBOOK.md).

Orphaned files removed

validation_node_check.txt (0 bytes — the only empty tracked file in the repo), validation_command_results.txt (30 bytes, one captured exit code), launch_env_fail_closed_output.json (a dated per-run report; .gitignore:21 already ignores the same class from the same tool under validation/), and docs/recursive_optimization_report.md — a duplicate of an archived copy that is indexed in docs/archive/README.md, referenced by nothing, and opens by naming /home/ubuntu/l9-website-bot, a path that does not exist in this repository.

Two things deliberately not done

No biome.json change. The plan called for adding a generated-tree exclusion beside the existing !**/build. I could not verify whether a bare !evidence anchors to the root or behaves like !**/evidence — which would silently drop those same 21 source files from linting. Explicit file paths bypass Biome's includes filter and its summary reporter emits no file count in this version, so the check was not decidable here. The benefit was four now-untracked files; the risk was the exact failure the first commit exists to prevent. Left for someone who can verify it.

ROOT_FILE_VALIDATION.md not updated. Its "Files in final pack: 19" counts a curated documentation pack, not tracked root files (the real root count was already 35 before this PR), and none of the removed files are enumerated in it. It is a dated point-in-time record; editing its numbers would falsify it rather than correct it.

Verification

npm run verify:all passes on 011f3e1, and the working tree stays clean through the entire run — which is the evidence that #208's untracking fix holds.

Remaining tracked-but-ignored after this PR:

.l9/ci.json
tests/golden/safehaven/fixtures/positive-receipt.json

Both deliberate, both verified.

Publication note

make pr ran the full gate — L4 release check, pr-check, main-bound ancestry and the overlap probe — and pushed this branch. It could not compose the PR body: open_pr_after_gate.sh requires ops/config/root-file-protection.json under the workspace root, and Website-Bot has no ops/ directory. Same consumer-side governance wiring gap as #208 and #209.


Generated by Claude Code


Correction — stack topology (audit website-bot-all-open-prs-2026-09-17, F3)

An earlier version of this description claimed a linear chain #208 → #209 → #210 → #211. That was wrong, and Git disproves it. Verified with git rev-list --left-right --count:

#209 vs #208 → behind 1 / ahead 2   diverged
#210 vs #209 → behind 2 / ahead 5   diverged
#210 vs #208 → behind 0 / ahead 4   true child
#211 vs #210 → behind 0 / ahead 3   true child

#210 was cut from #208's head, not #209's, so it never contained #209's normalizer delta. The accurate dependency model is:

#208 first. #209 and #210 are sibling deltas off #208. #211 depends on #210.

#209 and #210 do not require a linear relationship with each other.

#209 is additionally one commit behind #208 — it lacks the fixture fix f67f02d, which I merged forward into #210 and #211 but not #209, while stating it had reached all of them. #209 does not touch build-fixtures.mjs, so nothing there is functionally wrong; the claim was simply inaccurate. #209 should be refreshed against #208 once that lands.


Generated by Claude Code

buildFactoryExecutionPlan pushed RedesignIntegrityReceiptStage after
ReleaseReceiptFinalizerStage and HandoffEmitterStage. For an end-to-end
REDESIGN_IMPROVE run the emitted order was:

  ... visual-qa, release-receipt-finalizer, handoff-emitter,
      redesign-integrity-receipt, terminal-convergence

The finalizer writes status: "succeeded" to the release receipt and the
emitter performs the external POST to SEO-Bot plus recordWebsiteRelease
(externalMutation: true). A gate in that position can only reject a run
that has already been recorded as successful and handed off — it cannot
prevent one. An invalid redesign was therefore publishable.

The gate now runs after visual-qa, whose ctx.qualityEvidence.visualQa it
reads, and before the finalizer and emitter. It stays outside the
end-to-end guard on purpose: REDESIGN_ADDED_MANDATORY makes
redesign-integrity-receipt mandatory in every mode, so folding it into
that branch would make requireMandatoryConvergence throw on plan,
local-proof and publish-proof redesign runs.

No stage, receipt type, or handoff contract is added — this is a reorder.
The gate reads only context produced upstream of its new position and
declares no evidence block, so it imposes no runner ordering constraint.
The COPY end-to-end stage list is unchanged; the existing deepEqual
assertion in tests/unit/factory-execution-plan.test.ts passes unmodified.

Two intended consequences:

- On the visual-QA-not-passed path a redesign end-to-end run now fails as
  REDESIGN_PIPELINE_INCOMPLETE rather than RELEASE_EVIDENCE_INCOMPLETE.
  That is the fail-closed-earlier behaviour, not a regression.
- executed_stages in the emitted receipt no longer lists
  release-receipt-finalizer or handoff-emitter, since it snapshots
  ctx.stageResults at emit time. Nothing validates that field.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L
…plan

The durable path computed ctx.buildIntent from the spec and then built its
execution plan without it, so buildFactoryExecutionPlan always derived
redesign === false there.

A REDESIGN_IMPROVE spec submitted through Inngest therefore ran the COPY
topology: no seo-build-intelligence-preflight, no competitive-intelligence,
the legacy content/schema stages instead of the redesign authority chain,
and no redesign-integrity-receipt stage at all. The build context said one
thing and the plan built another.

This also bounds the preceding commit. Reordering the integrity gate ahead
of the finalizer and emitter fixes the plan builder, but on this path the
gate was never in the plan to begin with, so that fix would have been inert
here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L
There was no regression coverage for the terminal ordering of a redesign
plan. The two existing REDESIGN_IMPROVE tests assert only the head of the
pipeline (preflight before competitive-intelligence, competitive-intelligence
before design-intelligence), and redesign-integrity-receipt.test.ts asserts
that the stage is present, not where. All of them passed with the gate sitting
after the finalizer and the external handoff.

This asserts the chain that actually matters:

  visual-qa < redesign-integrity-receipt < release-receipt-finalizer
            < handoff-emitter < terminal-convergence

Verified to discriminate: against the parent commit's plan builder it fails
(8 pass / 1 fail); against the reordered one it passes (9 pass). A test that
cannot fail proves nothing, so it was run both ways before being committed.

The COPY end-to-end deepEqual assertion is deliberately left untouched — it
is the byte-identity guard proving the reorder did not disturb the non-redesign
topology, and editing it would destroy the evidence.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L
executed_stages and the STAGES list that drives synthetic checkpoint
timestamps both hard-code the pipeline's terminal order as static data
rather than deriving it from buildFactoryExecutionPlan. They still carried
the pre-fix tail, with redesign-integrity-receipt trailing the finalizer
and the handoff emitter.

Nothing fails as a result — the golden oracle checks a relative ordered
subsequence that omits both of those stages, so it is satisfied by either
order. That is precisely the problem: the fixtures would have gone on
describing an ordering the code no longer has, and a reviewer re-deriving
a fixture would have been misled by it.

Data-only; no generator logic changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L
validation/validation_report.yaml is per-run output of
scripts/validation-executor.ts, but it was tracked. Every `npm run
site:validate` — and therefore every `verify:all` and every `make pr` —
rewrote it with a fresh run_id, fresh timestamps, the local absolute
target_roots and the running user's git identity.

That is not cosmetic. It hard-blocks the sanctioned publish path: the L4
release receipt is bound to a tree digest, so `make pr` runs `pr-check`,
`pr-check` dirties this file, and the L4 remote check then rejects the
push as a stale receipt. The gate invalidates the authorization it is
about to verify, and no amount of re-authorizing escapes it, because the
next run dirties the tree again.

Untracking it is the repo's own established convention, not a new one:
.gitignore already ignores validation/launch_env_report.json and
validation/deploy_secrets_report.json, which are the same class of
per-run artifact from the same directory.

Nothing consumes the committed copy. scripts/validation-executor.ts only
writes it, no test or script reads it, and build-and-validate.yml
generates its own at the repository root and uploads that as a workflow
artifact.

The file stays on disk; only the index entry is removed. As a side
benefit the committed copy stops leaking one contributor's worktree path
and email address into the repository.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L
This repo is npm-only: .github/workflows/l9-lint-test.yml and
l9-lint-test-node.yml both pin PACKAGE_MANAGER="npm", regen-lockfile.yml
knows only `npm install --package-lock-only`, and four package-lock.json
files are tracked. .gitignore carried no lockfile entries at all, so a
stray pnpm-lock.yaml sat untracked and committable.

It is container debris — never tracked on any ref, and its mtime matches
every other file in the clone rather than any commit. Left unignored it is
one `git add -A` away from landing, and the dormant pnpm/yarn arms of the
lint workflows would treat it as load-bearing the moment PACKAGE_MANAGER
moved.

Appended at end of file rather than in the secrets block: PR #207 deletes
.gitignore:41, and a hunk there would overlap one written nearby.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L
(cherry picked from commit 3bf384caca440a43d4e5466957c671b35c353057)
`evidence/` was unanchored, so it matched a directory of that name at any
depth. `git ls-files -ci --exclude-standard` therefore reported 255 tracked
files as ignored, and 148 of those were not debris at all:

  - src/pipeline/evidence/*.ts — 21 files, the pipeline's evidence layer
    (EvidenceStore, ReleaseReceipt, RedesignExecutionIntegrityReceipt, ...)
  - docs/reports_and_test_results/**/evidence/** — 127 files, dated report
    bundles someone committed deliberately

Nothing was broken while they stayed tracked, because .gitignore does not
apply to files already in the index. The hazard is the cleanup: a
mechanically derived `git rm --cached $(git ls-files -ci)` would have
untracked the pipeline's evidence layer, and local validation would still
have passed because the files remain on disk. Only a fresh clone would have
failed.

Anchoring to /evidence/ confines the rule to the repository root, which is
where the Safe Haven per-run evidence it was written for actually lives. The
count drops 255 -> 107, and every remaining entry is genuine generated
output.

This lands as its own commit, before any untracking, so the delete list in
the next commit can be derived mechanically from a rule that is already
correct.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L
105 files whose directories .gitignore already names, but which were added
to the index before or despite those rules. Ignore rules do not apply to
tracked files, so they kept accumulating:

  - build/**  99 files across 61 golden run directories (~9.2 MB): 62
    pipeline.log files and 20 PNG captures, several over 1 MB. .gitignore:12
    says `build/` and README.md:193 says the same in prose.
  - evidence/**  4 files. .gitignore:45 names the directory as per-run Safe
    Haven output.
  - astro_template/validation/*.jsonl  2 files, named at .gitignore:23.
    Write-only: nothing reads them.

The list was derived mechanically from `git ls-files -ci --exclude-standard`
rather than hand-written, which is what makes a 105-file delete reviewable —
it is exactly the set git itself reports as tracked-but-ignored. That is only
safe because the preceding commit anchored `evidence/`; run against the old
rule the same command would have removed src/pipeline/evidence/*.ts.

Two entries are excluded deliberately, both tracked on purpose:
  - .l9/ci.json, re-included by `!.l9/ci.json` as the consumer-owned CI class
    declaration org-ci.yml reads
  - tests/golden/safehaven/fixtures/positive-receipt.json, which
    tests/golden/safehaven/RUNBOOK.md documents as a built fixture

Index-only: every file stays on disk and regenerates from its own tooling.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L
Four files, none referenced by any script, test, workflow or document.

Root run-artifacts, captured from one local run and committed:

  - validation_node_check.txt — 0 bytes, the only empty tracked file in the
    repository
  - validation_command_results.txt — 30 bytes, entirely
    `verify_launch_env_exit_code=1`
  - launch_env_fail_closed_output.json — a dated per-run report
    (timestamp_utc 2026-06-13). .gitignore:21 already ignores
    validation/launch_env_report.json, the same class of artifact from the
    same tool; this one just happened to be written at the repository root
    instead.

docs/recursive_optimization_report.md — a duplicate. docs/archive/ holds a
copy with different content that was archived deliberately in #125 and is
listed in docs/archive/README.md against ADR-0017. This root copy carries no
archive banner, is referenced by nothing, arrived incidentally in an
unrelated llm-router commit, and opens by naming a path that does not exist
in this repository:

    ## Artifact Group: /home/ubuntu/l9-website-bot (full repo)

The archived copy is the one the index points at and is untouched.

ROOT_FILE_VALIDATION.md is deliberately NOT updated. Its "Files in final
pack: 19" counts a curated documentation pack rather than tracked root files
(the real root count was already 35 before this commit), and none of the
files removed here are enumerated in it. It is a dated point-in-time record;
editing its numbers to match today would falsify it rather than correct it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L
Copilot AI lite review requested due to automatic review settings September 17, 2026 20:40
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

The safehaven golden fixture builder’s stage lists are inconsistent with the real REDESIGN_IMPROVE plan (missing design-reference-acquisition), so fixtures can diverge from actual stage history/order.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Repository hygiene work to ensure generated/per-run artifacts aren’t tracked and that ignore rules don’t accidentally sweep real source files (notably anchoring the root evidence/ ignore). In the currently-shown diff (because this PR is stacked), there are also pipeline-plan ordering updates and a regression test/fixture update around the redesign integrity gate.

Changes:

  • Update .gitignore to anchor /evidence/, ignore the validation report output under validation/, and ignore non-npm lockfiles.
  • Remove tracked generated artifacts (validation reports, golden evidence bundles/logs, astro template validation JSONL outputs, and an orphaned doc).
  • (Stacked changes) Ensure redesign integrity gating is ordered before success finalization/handoff, propagate buildIntent into the durable plan builder, and update related tests/fixtures.
File summaries
File Description
.gitignore Anchors root evidence ignore and expands ignore coverage for generated artifacts / non-npm lockfiles.
astro_template/validation/preflight_checks.jsonl Removes tracked generated Astro template validation output.
astro_template/validation/source_checks.jsonl Removes tracked generated Astro template validation output.
build/golden/golden-20260824-r12/pipeline.log Removes tracked golden run log artifact under build/.
build/golden/golden-20260824-r13/pipeline.log Removes tracked golden run log artifact under build/.
build/golden/golden-20260824-r2/pipeline.log Removes tracked golden run log artifact under build/.
build/golden/golden-20260824-r27/pipeline.log Removes tracked golden run log artifact under build/.
build/golden/golden-20260824-r3/pipeline.log Removes tracked golden run log artifact under build/.
build/golden/golden-20260824-r35/pipeline.log Removes tracked golden run log artifact under build/.
build/golden/golden-20260824-r36/pipeline.log Removes tracked golden run log artifact under build/.
build/golden/golden-20260824-r37/pipeline.log Removes tracked golden run log artifact under build/.
build/golden/golden-20260824-r4/pipeline.log Removes tracked golden run log artifact under build/.
build/golden/golden-20260824/pipeline.log Removes tracked golden run log artifact under build/.
build/golden/golden-20260825-r59/pipeline.log Removes tracked golden run log artifact under build/.
build/golden/golden-20260825-r61/GOLDEN-REPORT.md Removes tracked golden run report artifact under build/.
build/golden/golden-20260825-r61/candidate-serve.log Removes tracked local serve log artifact under build/.
build/golden/golden-20260825-r61/golden-oracle-result.json Removes tracked golden oracle output artifact under build/.
build/golden/golden-20260825-r61/seo-bot-evidence/fetch-meta.json Removes tracked golden SEO-Bot evidence artifact under build/.
build/golden/golden-20260825-r61/seo-bot-evidence/health.json Removes tracked golden SEO-Bot evidence artifact under build/.
build/golden/golden-20260825-r61/seo-bot-evidence/identity-snapshot.json Removes tracked golden SEO-Bot evidence artifact under build/.
build/golden/golden-20260825-r61/seo-bot-evidence/missing.json Removes tracked golden SEO-Bot evidence artifact under build/.
build/golden/golden-20260825-r61/seo-bot-evidence/preflight.json Removes tracked golden SEO-Bot evidence artifact under build/.
build/golden/golden-20260825-r61/seo-bot-evidence/sequence.json Removes tracked golden SEO-Bot evidence artifact under build/.
build/golden/golden-20260825-r61/site-integrity.json Removes tracked golden site-integrity output artifact under build/.
build/golden/golden-20260825-r61/visual/aggregated/aggregate.json Removes tracked golden visual aggregation artifact under build/.
build/golden/golden-20260825-r61/visual/manifest.json Removes tracked golden visual manifest artifact under build/.
docs/recursive_optimization_report.md Removes an orphaned/duplicated report doc.
evidence/golden-negative-controls.json Removes tracked per-run evidence output under root evidence/.
evidence/golden-positive-control.json Removes tracked per-run evidence output under root evidence/.
evidence/synthetic-real-mode-rejection.json Removes tracked per-run evidence output under root evidence/.
launch_env_fail_closed_output.json Removes tracked per-run launch-env output artifact from repo root.
scripts/golden-safehaven/fixtures/build-fixtures.mjs Updates safehaven golden fixture stage ordering to match pipeline ordering changes.
src/inngest/website-pipeline.ts Passes buildIntent into plan builder for durable pipeline execution.
src/pipeline/FactoryExecutionPlan.ts Reorders redesign-integrity gating to occur before success finalization and handoff emission.
tests/unit/factory-execution-plan.test.ts Adds a regression test to enforce redesign gate ordering relative to finalization/handoff.
validation/validation_report.yaml Removes tracked validation report output (generated per-run).
validation_command_results.txt Removes orphaned validation output artifact.
validation_node_check.txt Removes orphaned validation output artifact.
Review details
  • Files reviewed: 10/115 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread scripts/golden-safehaven/fixtures/build-fixtures.mjs
Comment thread scripts/golden-safehaven/fixtures/build-fixtures.mjs
Both hard-coded stage lists in the safehaven fixture builder went
seo-build-intelligence-preflight -> competitive-intelligence, skipping
design-reference-acquisition. The real REDESIGN_IMPROVE plan puts it between
those two (FactoryExecutionPlan.ts:275-279), and it is listed in
REDESIGN_ADDED_MANDATORY, so it is mandatory for every redesign run in every
mode.

The fixture declares mode: "end-to-end" with build_intent:
"REDESIGN_IMPROVE" and claims to represent a green run of exactly that plan,
so a stage the plan cannot omit was missing from the record. executed_stages
fed the emitted receipt and STAGES drives the synthetic checkpoint files and
the SQLite stage_runs rows, so both the receipt and the simulated stage
history described a run that could not occur.

Verified against the plan builder rather than by eye: an end-to-end
REDESIGN_IMPROVE plan emits ["seo-build-intelligence-preflight",
"design-reference-acquisition", "competitive-intelligence"] at that point,
which is now what both lists contain.

Found by Copilot's review on the stacked PR #210. It is a pre-existing gap
rather than one the preceding fixture commit introduced — that commit
corrected the tail of these lists — but the file is this PR's to get right,
and a fixture that misdescribes the pipeline is worse than no fixture.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L
Audit finding F2 of website-bot-all-open-prs-2026-09-17, against this PR.

docs/reports_and_test_results/08-18-2026/GOLDEN_E2E_FINAL_REPORT.md is a
retained report that cites two artifacts as its evidence — and calls them
"never hand-edited" and "never edited by hand", which is the whole point of
citing them:

  build/golden/golden-20260825-r61/pipeline.log
  build/golden/golden-20260825-r61/golden-oracle-result.json

This PR untracked both as generated output under build/, so the report's
evidence trail resolved to nothing. Before untracking I checked that no
script, test or workflow READS those files, and none does. I never checked
whether a retained document CITES them, which is exactly what a golden-run
proof report does. That was the gap.

Both are relocated verbatim from origin/main into evidence/ beside the report
that depends on them, and the three citations are repointed. Byte-identity is
the property that matters here, so it was verified rather than assumed: the
recovered files hash to 3b52732 and eeba265, the same blobs origin/main
carries. A regenerated substitute would have satisfied the link and destroyed
the claim.

docs/reports_and_test_results/**/evidence/ is the existing home for this
(08-15-2026 already uses it) and is tracked again since this PR anchored the
`evidence/` rule, so no new evidence location is introduced.

.gitignore needed one addition: `*.log` at line 11 matches at any depth, so
the relocated pipeline.log was silently not staged. `git add -f` would have
tracked it while leaving it ignored — precisely the tracked-but-ignored state
this PR exists to eliminate, and how 255 files accumulated in the first place.
The negation instead follows the repo's own precedent for retained logs
(!reports/test-runs/**/*.log) and is scoped to report evidence: build/,
root evidence/ and astro_template/ stay ignored, and `git ls-files -ci`
still returns only the two deliberate re-inclusions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L

Copy link
Copy Markdown
Collaborator Author

SCOPE_EXTENSION_REQUIRED — F2 is larger than the audit found

Finding F2 is fixed for the two artifacts the audit named, in 9007b4c. Checking whether they were the only broken citations turned up four more, and they fall outside this remediation contract's write surfaces, so per the contract I am reporting rather than editing them.

Method: every build/ or evidence/ path cited by a retained tracked document, intersected with what was tracked on main but is absent at this head — i.e. citations this PR actually broke, as distinct from the many documented runtime output paths that were never committed.

Broken artifact Cited by
evidence/oracle-coverage.json docs/reports_and_test_results/08-18-2026/ORACLE_COVERAGE_AND_SOUNDNESS.md, …/08-18-2026/README.md, tests/golden/safehaven/RUNBOOK.md
evidence/golden-positive-control.json tests/golden/safehaven/RUNBOOK.md
evidence/golden-negative-controls.json tests/golden/safehaven/RUNBOOK.md
evidence/synthetic-real-mode-rejection.json tests/golden/safehaven/RUNBOOK.md

The contract's F2 write surfaces are GOLDEN_E2E_FINAL_REPORT.md and the two build/golden/golden-20260825-r61/ artifacts. Neither these four files nor their three citing documents are listed, and the contract says to stop with SCOPE_EXTENSION_REQUIRED when a required path falls outside them.

Proposed remedy, identical in shape to the one already applied — recover each artifact verbatim from origin/main, relocate to an evidence/ directory beside the document that cites it, repoint the citation, and verify byte-identity by git blob hash. No new evidence subsystem; the .gitignore negation added in 9007b4c already covers docs/reports_and_test_results/**/evidence/. tests/golden/safehaven/RUNBOOK.md would need its own decision, since it is not under docs/.

Granting the extension is a human call. I have not touched those paths.

Note on my own diligence

Before untracking, I verified that no script, test or workflow reads the removed artifacts — none does. I never checked whether a retained document cites them as proof, which is exactly what a golden-run report does. The audit caught the first instance; the sweep above is me checking the rest of my own work rather than waiting to be told again.


Generated by Claude Code

@sonarqubecloud

Copy link
Copy Markdown

cryptoxdog added a commit that referenced this pull request Sep 19, 2026
* fix(pipeline): gate redesign integrity before success and handoff

buildFactoryExecutionPlan pushed RedesignIntegrityReceiptStage after
ReleaseReceiptFinalizerStage and HandoffEmitterStage. For an end-to-end
REDESIGN_IMPROVE run the emitted order was:

  ... visual-qa, release-receipt-finalizer, handoff-emitter,
      redesign-integrity-receipt, terminal-convergence

The finalizer writes status: "succeeded" to the release receipt and the
emitter performs the external POST to SEO-Bot plus recordWebsiteRelease
(externalMutation: true). A gate in that position can only reject a run
that has already been recorded as successful and handed off — it cannot
prevent one. An invalid redesign was therefore publishable.

The gate now runs after visual-qa, whose ctx.qualityEvidence.visualQa it
reads, and before the finalizer and emitter. It stays outside the
end-to-end guard on purpose: REDESIGN_ADDED_MANDATORY makes
redesign-integrity-receipt mandatory in every mode, so folding it into
that branch would make requireMandatoryConvergence throw on plan,
local-proof and publish-proof redesign runs.

No stage, receipt type, or handoff contract is added — this is a reorder.
The gate reads only context produced upstream of its new position and
declares no evidence block, so it imposes no runner ordering constraint.
The COPY end-to-end stage list is unchanged; the existing deepEqual
assertion in tests/unit/factory-execution-plan.test.ts passes unmodified.

Two intended consequences:

- On the visual-QA-not-passed path a redesign end-to-end run now fails as
  REDESIGN_PIPELINE_INCOMPLETE rather than RELEASE_EVIDENCE_INCOMPLETE.
  That is the fail-closed-earlier behaviour, not a regression.
- executed_stages in the emitted receipt no longer lists
  release-receipt-finalizer or handoff-emitter, since it snapshots
  ctx.stageResults at emit time. Nothing validates that field.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L

* fix(inngest): pass buildIntent into the durable pipeline's execution plan

The durable path computed ctx.buildIntent from the spec and then built its
execution plan without it, so buildFactoryExecutionPlan always derived
redesign === false there.

A REDESIGN_IMPROVE spec submitted through Inngest therefore ran the COPY
topology: no seo-build-intelligence-preflight, no competitive-intelligence,
the legacy content/schema stages instead of the redesign authority chain,
and no redesign-integrity-receipt stage at all. The build context said one
thing and the plan built another.

This also bounds the preceding commit. Reordering the integrity gate ahead
of the finalizer and emitter fixes the plan builder, but on this path the
gate was never in the plan to begin with, so that fix would have been inert
here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L

* test(pipeline): lock the redesign gate ahead of the success receipt

There was no regression coverage for the terminal ordering of a redesign
plan. The two existing REDESIGN_IMPROVE tests assert only the head of the
pipeline (preflight before competitive-intelligence, competitive-intelligence
before design-intelligence), and redesign-integrity-receipt.test.ts asserts
that the stage is present, not where. All of them passed with the gate sitting
after the finalizer and the external handoff.

This asserts the chain that actually matters:

  visual-qa < redesign-integrity-receipt < release-receipt-finalizer
            < handoff-emitter < terminal-convergence

Verified to discriminate: against the parent commit's plan builder it fails
(8 pass / 1 fail); against the reordered one it passes (9 pass). A test that
cannot fail proves nothing, so it was run both ways before being committed.

The COPY end-to-end deepEqual assertion is deliberately left untouched — it
is the byte-identity guard proving the reorder did not disturb the non-redesign
topology, and editing it would destroy the evidence.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L

* chore(golden): correct the hard-coded stage tail in the fixture builder

executed_stages and the STAGES list that drives synthetic checkpoint
timestamps both hard-code the pipeline's terminal order as static data
rather than deriving it from buildFactoryExecutionPlan. They still carried
the pre-fix tail, with redesign-integrity-receipt trailing the finalizer
and the handoff emitter.

Nothing fails as a result — the golden oracle checks a relative ordered
subsequence that omits both of those stages, so it is satisfied by either
order. That is precisely the problem: the fixtures would have gone on
describing an ordering the code no longer has, and a reviewer re-deriving
a fixture would have been misled by it.

Data-only; no generator logic changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L

* fix(repo): stop site:validate dirtying a tracked report

validation/validation_report.yaml is per-run output of
scripts/validation-executor.ts, but it was tracked. Every `npm run
site:validate` — and therefore every `verify:all` and every `make pr` —
rewrote it with a fresh run_id, fresh timestamps, the local absolute
target_roots and the running user's git identity.

That is not cosmetic. It hard-blocks the sanctioned publish path: the L4
release receipt is bound to a tree digest, so `make pr` runs `pr-check`,
`pr-check` dirties this file, and the L4 remote check then rejects the
push as a stale receipt. The gate invalidates the authorization it is
about to verify, and no amount of re-authorizing escapes it, because the
next run dirties the tree again.

Untracking it is the repo's own established convention, not a new one:
.gitignore already ignores validation/launch_env_report.json and
validation/deploy_secrets_report.json, which are the same class of
per-run artifact from the same directory.

Nothing consumes the committed copy. scripts/validation-executor.ts only
writes it, no test or script reads it, and build-and-validate.yml
generates its own at the repository root and uploads that as a workflow
artifact.

The file stays on disk; only the index entry is removed. As a side
benefit the committed copy stops leaking one contributor's worktree path
and email address into the repository.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L

* chore(gitignore): ignore non-npm lockfiles

This repo is npm-only: .github/workflows/l9-lint-test.yml and
l9-lint-test-node.yml both pin PACKAGE_MANAGER="npm", regen-lockfile.yml
knows only `npm install --package-lock-only`, and four package-lock.json
files are tracked. .gitignore carried no lockfile entries at all, so a
stray pnpm-lock.yaml sat untracked and committable.

It is container debris — never tracked on any ref, and its mtime matches
every other file in the clone rather than any commit. Left unignored it is
one `git add -A` away from landing, and the dormant pnpm/yarn arms of the
lint workflows would treat it as load-bearing the moment PACKAGE_MANAGER
moved.

Appended at end of file rather than in the secrets block: PR #207 deletes
.gitignore:41, and a hunk there would overlap one written nearby.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L
(cherry picked from commit 3bf384caca440a43d4e5466957c671b35c353057)

* fix(golden): add the missing mandatory redesign stage to the fixture

Both hard-coded stage lists in the safehaven fixture builder went
seo-build-intelligence-preflight -> competitive-intelligence, skipping
design-reference-acquisition. The real REDESIGN_IMPROVE plan puts it between
those two (FactoryExecutionPlan.ts:275-279), and it is listed in
REDESIGN_ADDED_MANDATORY, so it is mandatory for every redesign run in every
mode.

The fixture declares mode: "end-to-end" with build_intent:
"REDESIGN_IMPROVE" and claims to represent a green run of exactly that plan,
so a stage the plan cannot omit was missing from the record. executed_stages
fed the emitted receipt and STAGES drives the synthetic checkpoint files and
the SQLite stage_runs rows, so both the receipt and the simulated stage
history described a run that could not occur.

Verified against the plan builder rather than by eye: an end-to-end
REDESIGN_IMPROVE plan emits ["seo-build-intelligence-preflight",
"design-reference-acquisition", "competitive-intelligence"] at that point,
which is now what both lists contain.

Found by Copilot's review on the stacked PR #210. It is a pre-existing gap
rather than one the preceding fixture commit introduced — that commit
corrected the tail of these lists — but the file is this PR's to get right,
and a fixture that misdescribes the pipeline is worse than no fixture.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L

---------

Co-authored-by: Claude <noreply@anthropic.com>
@cryptoxdog
cryptoxdog merged commit 9d51a04 into main Sep 19, 2026
18 checks passed
@cryptoxdog
cryptoxdog deleted the claude/audit-hygiene-untrack-generated-v2 branch September 19, 2026 15:20
cryptoxdog added a commit that referenced this pull request Sep 19, 2026
* fix(pipeline): gate redesign integrity before success and handoff

buildFactoryExecutionPlan pushed RedesignIntegrityReceiptStage after
ReleaseReceiptFinalizerStage and HandoffEmitterStage. For an end-to-end
REDESIGN_IMPROVE run the emitted order was:

  ... visual-qa, release-receipt-finalizer, handoff-emitter,
      redesign-integrity-receipt, terminal-convergence

The finalizer writes status: "succeeded" to the release receipt and the
emitter performs the external POST to SEO-Bot plus recordWebsiteRelease
(externalMutation: true). A gate in that position can only reject a run
that has already been recorded as successful and handed off — it cannot
prevent one. An invalid redesign was therefore publishable.

The gate now runs after visual-qa, whose ctx.qualityEvidence.visualQa it
reads, and before the finalizer and emitter. It stays outside the
end-to-end guard on purpose: REDESIGN_ADDED_MANDATORY makes
redesign-integrity-receipt mandatory in every mode, so folding it into
that branch would make requireMandatoryConvergence throw on plan,
local-proof and publish-proof redesign runs.

No stage, receipt type, or handoff contract is added — this is a reorder.
The gate reads only context produced upstream of its new position and
declares no evidence block, so it imposes no runner ordering constraint.
The COPY end-to-end stage list is unchanged; the existing deepEqual
assertion in tests/unit/factory-execution-plan.test.ts passes unmodified.

Two intended consequences:

- On the visual-QA-not-passed path a redesign end-to-end run now fails as
  REDESIGN_PIPELINE_INCOMPLETE rather than RELEASE_EVIDENCE_INCOMPLETE.
  That is the fail-closed-earlier behaviour, not a regression.
- executed_stages in the emitted receipt no longer lists
  release-receipt-finalizer or handoff-emitter, since it snapshots
  ctx.stageResults at emit time. Nothing validates that field.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L

* fix(inngest): pass buildIntent into the durable pipeline's execution plan

The durable path computed ctx.buildIntent from the spec and then built its
execution plan without it, so buildFactoryExecutionPlan always derived
redesign === false there.

A REDESIGN_IMPROVE spec submitted through Inngest therefore ran the COPY
topology: no seo-build-intelligence-preflight, no competitive-intelligence,
the legacy content/schema stages instead of the redesign authority chain,
and no redesign-integrity-receipt stage at all. The build context said one
thing and the plan built another.

This also bounds the preceding commit. Reordering the integrity gate ahead
of the finalizer and emitter fixes the plan builder, but on this path the
gate was never in the plan to begin with, so that fix would have been inert
here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L

* test(pipeline): lock the redesign gate ahead of the success receipt

There was no regression coverage for the terminal ordering of a redesign
plan. The two existing REDESIGN_IMPROVE tests assert only the head of the
pipeline (preflight before competitive-intelligence, competitive-intelligence
before design-intelligence), and redesign-integrity-receipt.test.ts asserts
that the stage is present, not where. All of them passed with the gate sitting
after the finalizer and the external handoff.

This asserts the chain that actually matters:

  visual-qa < redesign-integrity-receipt < release-receipt-finalizer
            < handoff-emitter < terminal-convergence

Verified to discriminate: against the parent commit's plan builder it fails
(8 pass / 1 fail); against the reordered one it passes (9 pass). A test that
cannot fail proves nothing, so it was run both ways before being committed.

The COPY end-to-end deepEqual assertion is deliberately left untouched — it
is the byte-identity guard proving the reorder did not disturb the non-redesign
topology, and editing it would destroy the evidence.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L

* chore(golden): correct the hard-coded stage tail in the fixture builder

executed_stages and the STAGES list that drives synthetic checkpoint
timestamps both hard-code the pipeline's terminal order as static data
rather than deriving it from buildFactoryExecutionPlan. They still carried
the pre-fix tail, with redesign-integrity-receipt trailing the finalizer
and the handoff emitter.

Nothing fails as a result — the golden oracle checks a relative ordered
subsequence that omits both of those stages, so it is satisfied by either
order. That is precisely the problem: the fixtures would have gone on
describing an ordering the code no longer has, and a reviewer re-deriving
a fixture would have been misled by it.

Data-only; no generator logic changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L

* fix(repo): stop site:validate dirtying a tracked report

validation/validation_report.yaml is per-run output of
scripts/validation-executor.ts, but it was tracked. Every `npm run
site:validate` — and therefore every `verify:all` and every `make pr` —
rewrote it with a fresh run_id, fresh timestamps, the local absolute
target_roots and the running user's git identity.

That is not cosmetic. It hard-blocks the sanctioned publish path: the L4
release receipt is bound to a tree digest, so `make pr` runs `pr-check`,
`pr-check` dirties this file, and the L4 remote check then rejects the
push as a stale receipt. The gate invalidates the authorization it is
about to verify, and no amount of re-authorizing escapes it, because the
next run dirties the tree again.

Untracking it is the repo's own established convention, not a new one:
.gitignore already ignores validation/launch_env_report.json and
validation/deploy_secrets_report.json, which are the same class of
per-run artifact from the same directory.

Nothing consumes the committed copy. scripts/validation-executor.ts only
writes it, no test or script reads it, and build-and-validate.yml
generates its own at the repository root and uploads that as a workflow
artifact.

The file stays on disk; only the index entry is removed. As a side
benefit the committed copy stops leaking one contributor's worktree path
and email address into the repository.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L

* chore(gitignore): ignore non-npm lockfiles

This repo is npm-only: .github/workflows/l9-lint-test.yml and
l9-lint-test-node.yml both pin PACKAGE_MANAGER="npm", regen-lockfile.yml
knows only `npm install --package-lock-only`, and four package-lock.json
files are tracked. .gitignore carried no lockfile entries at all, so a
stray pnpm-lock.yaml sat untracked and committable.

It is container debris — never tracked on any ref, and its mtime matches
every other file in the clone rather than any commit. Left unignored it is
one `git add -A` away from landing, and the dormant pnpm/yarn arms of the
lint workflows would treat it as load-bearing the moment PACKAGE_MANAGER
moved.

Appended at end of file rather than in the secrets block: PR #207 deletes
.gitignore:41, and a hunk there would overlap one written nearby.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L
(cherry picked from commit 3bf384caca440a43d4e5466957c671b35c353057)

* fix(gitignore): anchor evidence/ so it stops matching real source

`evidence/` was unanchored, so it matched a directory of that name at any
depth. `git ls-files -ci --exclude-standard` therefore reported 255 tracked
files as ignored, and 148 of those were not debris at all:

  - src/pipeline/evidence/*.ts — 21 files, the pipeline's evidence layer
    (EvidenceStore, ReleaseReceipt, RedesignExecutionIntegrityReceipt, ...)
  - docs/reports_and_test_results/**/evidence/** — 127 files, dated report
    bundles someone committed deliberately

Nothing was broken while they stayed tracked, because .gitignore does not
apply to files already in the index. The hazard is the cleanup: a
mechanically derived `git rm --cached $(git ls-files -ci)` would have
untracked the pipeline's evidence layer, and local validation would still
have passed because the files remain on disk. Only a fresh clone would have
failed.

Anchoring to /evidence/ confines the rule to the repository root, which is
where the Safe Haven per-run evidence it was written for actually lives. The
count drops 255 -> 107, and every remaining entry is genuine generated
output.

This lands as its own commit, before any untracking, so the delete list in
the next commit can be derived mechanically from a rule that is already
correct.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L

* chore(repo): untrack generated build, evidence and per-run artifacts

105 files whose directories .gitignore already names, but which were added
to the index before or despite those rules. Ignore rules do not apply to
tracked files, so they kept accumulating:

  - build/**  99 files across 61 golden run directories (~9.2 MB): 62
    pipeline.log files and 20 PNG captures, several over 1 MB. .gitignore:12
    says `build/` and README.md:193 says the same in prose.
  - evidence/**  4 files. .gitignore:45 names the directory as per-run Safe
    Haven output.
  - astro_template/validation/*.jsonl  2 files, named at .gitignore:23.
    Write-only: nothing reads them.

The list was derived mechanically from `git ls-files -ci --exclude-standard`
rather than hand-written, which is what makes a 105-file delete reviewable —
it is exactly the set git itself reports as tracked-but-ignored. That is only
safe because the preceding commit anchored `evidence/`; run against the old
rule the same command would have removed src/pipeline/evidence/*.ts.

Two entries are excluded deliberately, both tracked on purpose:
  - .l9/ci.json, re-included by `!.l9/ci.json` as the consumer-owned CI class
    declaration org-ci.yml reads
  - tests/golden/safehaven/fixtures/positive-receipt.json, which
    tests/golden/safehaven/RUNBOOK.md documents as a built fixture

Index-only: every file stays on disk and regenerates from its own tooling.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L

* chore(repo): remove orphaned root run-artifacts and a duplicated doc

Four files, none referenced by any script, test, workflow or document.

Root run-artifacts, captured from one local run and committed:

  - validation_node_check.txt — 0 bytes, the only empty tracked file in the
    repository
  - validation_command_results.txt — 30 bytes, entirely
    `verify_launch_env_exit_code=1`
  - launch_env_fail_closed_output.json — a dated per-run report
    (timestamp_utc 2026-06-13). .gitignore:21 already ignores
    validation/launch_env_report.json, the same class of artifact from the
    same tool; this one just happened to be written at the repository root
    instead.

docs/recursive_optimization_report.md — a duplicate. docs/archive/ holds a
copy with different content that was archived deliberately in #125 and is
listed in docs/archive/README.md against ADR-0017. This root copy carries no
archive banner, is referenced by nothing, arrived incidentally in an
unrelated llm-router commit, and opens by naming a path that does not exist
in this repository:

    ## Artifact Group: /home/ubuntu/l9-website-bot (full repo)

The archived copy is the one the index points at and is untouched.

ROOT_FILE_VALIDATION.md is deliberately NOT updated. Its "Files in final
pack: 19" counts a curated documentation pack rather than tracked root files
(the real root count was already 35 before this commit), and none of the
files removed here are enumerated in it. It is a dated point-in-time record;
editing its numbers to match today would falsify it rather than correct it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L

* docs: point every numbered-ADR reference at docs/adr

Audit finding F4. The numbered ADR series lives in docs/adr/, and
ARCHITECTURE.md:7 says so — "That directory is the only canonical ADR
location". Eighteen references across ten files said otherwise, and fourteen
of them were not merely misleading but dead: every
docs/architecture/ADR-XXXX-*.md target was verified absent. docs/architecture/
holds four design notes and no numbered ADR at all.

Dead links repointed (docs/architecture/ADR-* -> docs/adr/ADR-*): the five
archived-doc banner lines under docs/archive/, the five-row extraction table in
docs/archive/README.md, TODO.md:49 and :51, and MANIFEST.md:30 — the last
being the worst of them, since MANIFEST.md presents that block as the overlay's
file inventory and so asserted the existence of a file the repository does not
contain. All nine distinct targets now resolve; zero dead.

Prose pointers corrected:

  - ARCHITECTURE.md:67 contradicted its own line 7, sixty lines apart
  - AGENTS.md:5 — the highest blast radius of the set: the Mission line calls
    itself "binding guidance for AI coding agents", so every agent entering
    this repository was handed the wrong ADR home in its first instruction,
    while AGENTS.md:74 cited docs/adr correctly
  - README.md:198 named docs/architecture as the ADR home and omitted
    docs/adr from the repository layout entirely, so a README reader could
    not learn the canonical directory exists
  - docs/archive/README.md:4 said "the numbered ADRs under docs/architecture/"
  - MANIFEST.md:12
  - docs/adr/README.md:4 forbade adding ADRs under `adr/`, which reads as
    forbidding the very directory it declares canonical; the intended referent
    is SEO-Bot's adr/ series, now named explicitly

Also indexes ADR-0019-client-design-reference-...md, an accepted 8.7 KB
decision record that was missing from docs/adr/README.md's table and therefore
undiscoverable from the canonical index. It collides on number with
ADR-0019-retire-five-push-campaign-pack.md; the collision is flagged in place
rather than resolved, because renumbering is an ADR decision and the losing
document's inbound references move with it.

Pointers only. No ADR is moved, renumbered or created, and no third authority
location is introduced.

Nothing in the verify:all chain validates documentation links, which is how
eighteen of them drifted undetected. Worth adding.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L

* fix(golden): add the missing mandatory redesign stage to the fixture

Both hard-coded stage lists in the safehaven fixture builder went
seo-build-intelligence-preflight -> competitive-intelligence, skipping
design-reference-acquisition. The real REDESIGN_IMPROVE plan puts it between
those two (FactoryExecutionPlan.ts:275-279), and it is listed in
REDESIGN_ADDED_MANDATORY, so it is mandatory for every redesign run in every
mode.

The fixture declares mode: "end-to-end" with build_intent:
"REDESIGN_IMPROVE" and claims to represent a green run of exactly that plan,
so a stage the plan cannot omit was missing from the record. executed_stages
fed the emitted receipt and STAGES drives the synthetic checkpoint files and
the SQLite stage_runs rows, so both the receipt and the simulated stage
history described a run that could not occur.

Verified against the plan builder rather than by eye: an end-to-end
REDESIGN_IMPROVE plan emits ["seo-build-intelligence-preflight",
"design-reference-acquisition", "competitive-intelligence"] at that point,
which is now what both lists contain.

Found by Copilot's review on the stacked PR #210. It is a pre-existing gap
rather than one the preceding fixture commit introduced — that commit
corrected the tail of these lists — but the file is this PR's to get right,
and a fixture that misdescribes the pipeline is worse than no fixture.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L

* docs: correct the ADR-0019 index date and the docs/adr layout wording

Both from Copilot's review on #211, both correct.

The index row for ADR-0019-client-design-reference-... carried "—" for its
date. The ADR declares `## Date 2026-09-03`. I indexed that file without
reading its date field, and an index that invents an unknown where the source
states a fact is worse than the omission it replaced.

README.md:198 read "numbered Architecture Decision Records — the canonical
decision record", which describes a directory as though it were a single
record. It is the canonical ADR directory.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L

* fix(docs): retain the golden report's cited proof artifacts

Audit finding F2 of website-bot-all-open-prs-2026-09-17, against this PR.

docs/reports_and_test_results/08-18-2026/GOLDEN_E2E_FINAL_REPORT.md is a
retained report that cites two artifacts as its evidence — and calls them
"never hand-edited" and "never edited by hand", which is the whole point of
citing them:

  build/golden/golden-20260825-r61/pipeline.log
  build/golden/golden-20260825-r61/golden-oracle-result.json

This PR untracked both as generated output under build/, so the report's
evidence trail resolved to nothing. Before untracking I checked that no
script, test or workflow READS those files, and none does. I never checked
whether a retained document CITES them, which is exactly what a golden-run
proof report does. That was the gap.

Both are relocated verbatim from origin/main into evidence/ beside the report
that depends on them, and the three citations are repointed. Byte-identity is
the property that matters here, so it was verified rather than assumed: the
recovered files hash to 3b52732 and eeba265, the same blobs origin/main
carries. A regenerated substitute would have satisfied the link and destroyed
the claim.

docs/reports_and_test_results/**/evidence/ is the existing home for this
(08-15-2026 already uses it) and is tracked again since this PR anchored the
`evidence/` rule, so no new evidence location is introduced.

.gitignore needed one addition: `*.log` at line 11 matches at any depth, so
the relocated pipeline.log was silently not staged. `git add -f` would have
tracked it while leaving it ignored — precisely the tracked-but-ignored state
this PR exists to eliminate, and how 255 files accumulated in the first place.
The negation instead follows the repo's own precedent for retained logs
(!reports/test-runs/**/*.log) and is scoped to report evidence: build/,
root evidence/ and astro_template/ stay ignored, and `git ls-files -ci`
still returns only the two deliberate re-inclusions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L

---------

Co-authored-by: Claude <noreply@anthropic.com>
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.

3 participants