fix(gitignore): drop remediator re-ignore of Claude local settings - #207
Conversation
Website-Bot must match the other undoA repos: session-injected Claude paths stay unignored. The #188 remediator line put .claude/settings.local.json back. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Copilot wasn't able to review any files in this pull request.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 67abe9c249
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
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)
Note before merge — audit finding F1Recording this on the PR because it is about to be merged and the finding should not live only in a chat transcript. Audit
Verified directly: The repository operator was shown this finding and elected to merge #207 as written. That is their call, and this comment is the record rather than an objection. If the ignore is wanted back later, it is one line restored under the "Local secrets and Claude Code machine overrides — never commit" block in Generated by Claude Code |
Restore the machine-override exclusion this branch deleted so workstation Claude settings cannot be staged by a routine git add. Remediation-Cycle: #207/cycle-1
PR Remediation — Cycle 1 SummaryCommit: Fixed (1)
Deferred (0)none Acknowledged (0)none Disagreed (0)none Local verify: Unknown | Threads resolved: 1/1 |
|
* 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>
…omic (#209) * 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(normalize-spec): cover both committed pairs and make overrides atomic Two defects in one CLI, both reachable today. Coverage. The default check and write were hardcoded to examples/supplemental-insurance-pros, so the second committed pair was verified by nothing. It duly rotted: examples/quantum-ai-partners was last written in #174, the v1.1 semantic compiler landed in #196, and the committed IR is six top-level keys behind it — routes (missing purpose, template and priority on every route), seo_contract (missing route_targets and schema_application), and business_facts, conversion_authority, content_guardrails and semantic_provenance absent entirely. An artifact nothing verifies is an artifact that drifts. Both pairs are now checked and regenerated together, and the regenerated quantum IR lands in this commit because the script alone would leave the gate red. Pairing. A source and its normalized output are one unit, but a one-sided override filled the missing half from the first committed pair: { in: inArg ?? COMMITTED_SPECS[0].in, out: outArg ?? COMMITTED_SPECS[0].out } So `--in examples/quantum-ai-partners/domain_spec.source.yaml` with no --out compiled quantum and wrote it over supplemental's committed artifact — the wrong client's file, overwritten while the invocation looked entirely deliberate. An override now names both sides, or one side that resolves to exactly one committed pair; anything else is an error rather than a guess. Also pins stringify lineWidth: 0. The committed artifacts were generated unfolded while the writer kept the yaml package's 80-column default, so a regeneration rewrapped an in-sync file by +76 bytes and the gate stayed green through it — it compares parsed objects, not bytes. Verified inert: after this change `npm run normalize-spec` leaves the supplemental artifact byte-identical. The three-function split that the superseded #198 used for this is deliberately not carried over: a loop over the pair list is the same behaviour at roughly a quarter of the diff. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L * test(normalize-spec): pin atomic override pairing and both-pair coverage Four tests, each verified to fail against the parent commit's script and pass against this one (14 pass / 4 fail before, 18 pass after). The load-bearing one asserts that `--check --in <quantum source>` is judged against quantum's OWN output and leaves supplemental's committed artifact byte-identical and untouched by mtime. That is the exact shape of the defect: the old resolution would have compared quantum's compile against supplemental's artifact, and without --check would have overwritten it. The others cover the mirror case (a one-sided --out), the failure case (a one-sided path matching no committed pair must error rather than pick one), and the preservation obligation that the no-flag default still names every committed pair, so the gate cannot quietly narrow back to one client. These reuse the spawnSync + mtime/body snapshot harness already used by the entry-point-guard test, which is the only existing test that exercises the CLI rather than importing buildFlatSpec. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019Hmr3SKRhYQ56omTzNFZ4L --------- Co-authored-by: Claude <noreply@anthropic.com>
…re rule (#210) * 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 * 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 * 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>
* 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>



Summary
Type of change
type:feature— new feature or capability — not measured by open_pr_after_gate.sh — do not treat as verifiedtype:bugfix— bug fix — not measured by open_pr_after_gate.sh — do not treat as verifiedtype:refactor— refactor, no behavior change — not measured by open_pr_after_gate.sh — do not treat as verifiedtype:docs— documentation only — not measured by open_pr_after_gate.sh — do not treat as verifiedtype:ci— CI / workflow changes — not measured by open_pr_after_gate.sh — do not treat as verifiedtype:security— security fix or hardening — not measured by open_pr_after_gate.sh — do not treat as verifiedArea
area:backend— src/, packages/ — not measured by open_pr_after_gate.sh — do not treat as verifiedarea:frontend— UI — not measured by open_pr_after_gate.sh — do not treat as verifiedarea:infrastructure— docker, deployment, config — not measured by open_pr_after_gate.sh — do not treat as verifiedarea:workflows— .github/, CI — not measured by open_pr_after_gate.sh — do not treat as verifiedarea:llm-router— @quantum-l9/llm-router consumption (src/services/llm.ts) — not measured by open_pr_after_gate.sh — do not treat as verifiedChecklist
npm run verify:allpasses locally — not measured by open_pr_after_gate.sh — do not treat as verifiednpx tsc --noEmitpasses (no type errors) — not measured by open_pr_after_gate.sh — do not treat as verifiedVALIDATION.mdupdated if validation artifacts changed — not measured by open_pr_after_gate.sh — do not treat as verifiedDECISION_LOG.mdupdated if relevant — not measured by open_pr_after_gate.sh — do not treat as verifiedRelated issues / ADRs / contracts
Commits
Test plan
make prlocal gate receipt presentrelease_authorized)Changed files
Mechanical evidence
gate-receipt.json present: schema=l9.pr_gate_receipt.v2 head=None passed_at=2026-09-15T14:46:19Z
L4 receipt present: phase=release_authorized head=67abe9c249c4eaac0bc8dff3351d40fa4d31f380