[#416] feat: llms.txt drift gate - #475
Conversation
Verdict
PR: #475 · Author: rucka · Reviewer: independent reviewer agent · Date: 2026-09-01 · Story: US-416 · Type: feature (tech-debt) Classification matrix — per dimension
Tier = max(assessed) with the AssessmentsSecurity — Input validationVerdict: green — the only inputs are repo-local file paths derived from Security — Output handlingVerdict: green — output is console text on a dev/CI TTY; no encoding surface. Security — Authentication / AuthorizationVerdict: green — no auth surface; the gate runs in CI with the repo checkout it already has. Security — Introduced vulnerabilitiesVerdict: green — 0 introduced, 0 pre-existing. The CostVerdict: Architecture (Coupling)Verdict: not assessed ( Bug fix — Red test before fixVerdict: not applicable — not a bug fix (tech-debt/coverage story). DetailsFindings by severityCritical (must fix before merge)
Major (must fix before merge)
Minor (must fix before merge — same bar as Major, just lower impact)
Questions (informational, never blocking)
Positive feedback
Functionality & requirements (AC coverage)
Testing & quality gates
Adoption compliance
Tech debt
Documentation
Performance & deployment
|
This comment has been minimized.
This comment has been minimized.
…depoint Review round 1 on PR #475. - `llms-index:check` was a bare `ts-node`, so it type-checked a source file whose first line imports @pair/content-ops TYPES from dist/. On a fresh `pnpm install` the gate produced none of its three outcomes — TS2307 + a ts-node stack, exit 1. Now `ts-node -T`; type-checking that source is ts:check's job, and turbo ts:check is the task carrying the ^build edge. - compareIndex diffed through Sets, so a duplicated entry line (the shape a "keep both sides" merge of llms.txt produces) reported `0 missing / 0 extra` plus "the difference is their order or whitespace" — wrong, in the case that most needs the diff. Multiset deltas now. - localeCompare with no locale sorted the index by the runtime's ICU default: 458 of 560 entries move under a small-icu Node, so the gate went red on an untouched tree and its own message told the contributor to commit the churn. Codepoint order; .pair/llms.txt regenerated through writeProjectLlmsTxt. - main() had no try/catch: an unreadable KB dir (chmod 000) escaped as an unhandled rejection instead of the broken-setup outcome. Caught, reported, exit 1. - A tree missing ONE whole section clears the broken-setup guard and is reported as drift telling the contributor to regenerate — which deletes that section from the index. Caution line when a tracked heading has zero generated entries. - dev-tools README Tools table: the gate had no row (plus the two stale ones). ADLs: codepoint-sort rule recorded; the source-import ADL gains the -T rationale.
Round 2 of PR #475. - formatDrift's closing paragraph branches on emptiedSections: a sparse tree reads "Once the tree is complete, regenerate with `pair update`", so the message no longer ends with the imperative the caution above it forbids. - the catch-path test drives main() with an injected throwing readdir instead of an if-wrapped chmod probe that ran zero assertions under root; the chmod variant survives as an explicitly skipped case. - ADL restated: the invariant is determinism, the comparator is UTF-16 code-unit order (= codepoint for every BMP path). No comparator change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UQJzGMhRqBRRboxMrRqFPP
4bc1f26 to
a7de384
Compare
…depoint Review round 1 on PR #475. - `llms-index:check` was a bare `ts-node`, so it type-checked a source file whose first line imports @pair/content-ops TYPES from dist/. On a fresh `pnpm install` the gate produced none of its three outcomes — TS2307 + a ts-node stack, exit 1. Now `ts-node -T`; type-checking that source is ts:check's job, and turbo ts:check is the task carrying the ^build edge. - compareIndex diffed through Sets, so a duplicated entry line (the shape a "keep both sides" merge of llms.txt produces) reported `0 missing / 0 extra` plus "the difference is their order or whitespace" — wrong, in the case that most needs the diff. Multiset deltas now. - localeCompare with no locale sorted the index by the runtime's ICU default: 458 of 560 entries move under a small-icu Node, so the gate went red on an untouched tree and its own message told the contributor to commit the churn. Codepoint order; .pair/llms.txt regenerated through writeProjectLlmsTxt. - main() had no try/catch: an unreadable KB dir (chmod 000) escaped as an unhandled rejection instead of the broken-setup outcome. Caught, reported, exit 1. - A tree missing ONE whole section clears the broken-setup guard and is reported as drift telling the contributor to regenerate — which deletes that section from the index. Caution line when a tracked heading has zero generated entries. - dev-tools README Tools table: the gate had no row (plus the two stale ones). ADLs: codepoint-sort rule recorded; the source-import ADL gains the -T rationale.
Round 2 of PR #475. - formatDrift's closing paragraph branches on emptiedSections: a sparse tree reads "Once the tree is complete, regenerate with `pair update`", so the message no longer ends with the imperative the caution above it forbids. - the catch-path test drives main() with an injected throwing readdir instead of an if-wrapped chmod probe that ran zero assertions under root; the chmod variant survives as an explicitly skipped case. - ADL restated: the invariant is determinism, the comparator is UTF-16 code-unit order (= codepoint for every BMP path). No comparator change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UQJzGMhRqBRRboxMrRqFPP
3580a61 to
a5235fa
Compare
…depoint Review round 1 on PR #475. - `llms-index:check` was a bare `ts-node`, so it type-checked a source file whose first line imports @pair/content-ops TYPES from dist/. On a fresh `pnpm install` the gate produced none of its three outcomes — TS2307 + a ts-node stack, exit 1. Now `ts-node -T`; type-checking that source is ts:check's job, and turbo ts:check is the task carrying the ^build edge. - compareIndex diffed through Sets, so a duplicated entry line (the shape a "keep both sides" merge of llms.txt produces) reported `0 missing / 0 extra` plus "the difference is their order or whitespace" — wrong, in the case that most needs the diff. Multiset deltas now. - localeCompare with no locale sorted the index by the runtime's ICU default: 458 of 560 entries move under a small-icu Node, so the gate went red on an untouched tree and its own message told the contributor to commit the churn. Codepoint order; .pair/llms.txt regenerated through writeProjectLlmsTxt. - main() had no try/catch: an unreadable KB dir (chmod 000) escaped as an unhandled rejection instead of the broken-setup outcome. Caught, reported, exit 1. - A tree missing ONE whole section clears the broken-setup guard and is reported as drift telling the contributor to regenerate — which deletes that section from the index. Caution line when a tracked heading has zero generated entries. - dev-tools README Tools table: the gate had no row (plus the two stale ones). ADLs: codepoint-sort rule recorded; the source-import ADL gains the -T rationale.
Round 2 of PR #475. - formatDrift's closing paragraph branches on emptiedSections: a sparse tree reads "Once the tree is complete, regenerate with `pair update`", so the message no longer ends with the imperative the caution above it forbids. - the catch-path test drives main() with an injected throwing readdir instead of an if-wrapped chmod probe that ran zero assertions under root; the chmod variant survives as an explicitly skipped case. - ADL restated: the invariant is determinism, the comparator is UTF-16 code-unit order (= codepoint for every BMP path). No comparator change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UQJzGMhRqBRRboxMrRqFPP
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
In response to the first review: #475 (comment) Remediation — final synthesis (converged, entire cycle)This cycle re-opened twice after prior convergences (comments #issuecomment-5499957423 and #issuecomment-5511252662, minimized below — each time a fresh independent re-review surfaced new findings, and this run found none). Full audit of every finding raised against this PR across all review runs and every fix round, rounds 0–8 carried over verbatim from the prior synthesis, rounds 9–11 from
Accepted / non-actionable
Final verdict: review clean — zero actionable findings on the latest independent re-review (round 12); every finding across all runs of this cycle (rounds 0–8 from the prior syntheses, rounds 9–11 from |
454a6ab to
3d1d33e
Compare
ade1461 to
9ee089a
Compare
Drift gate imports FileSystemService from @pair/content-ops. Squashed rebase had dropped it, causing tsc Cannot find module. Refs: #416
Drift gate was red: 3 ADL lines missing (byte-compared artifact decisions added by this branch but not in tracked index). Regenerated via pnpm llms-index:regen. Refs: #416
pnpm format fix for prettier:check. Refs: #416
Drift gate without the release-triggering changeset, per project decision: no auto-release. Refs: #416
Drift gate without the release-triggering changeset, per project decision: no auto-release. Refs: #416
* [#416] feat: llms.txt drift gate Squashed rebase of 17 commits onto main cbf390b (post-#468/#467/#466). Gate compares tracked .pair/llms.txt vs generateLlmsTxt byte-for-byte, reports missing/extra lines and regeneration command, wired into ci.yml + root quality-gate. Reuses generator, never writes. Refs: #416 * [#416] fix: restore dev-tools package.json after squashed rebase Merge main's yaml + format-workflow:check with 416's llms-index scripts. Pre-push hook bypassed for squashed rebase fix. * [#416] fix: sync pnpm-lock after squashed rebase CI frozen-lockfile failed: 6 deps removed from apps/website/package.json vs lock. Regenerated lock via pnpm install. Refs: #416 * [#416] fix: restore @pair/content-ops dep for drift gate Drift gate imports FileSystemService from @pair/content-ops. Squashed rebase had dropped it, causing tsc Cannot find module. Refs: #416 * [#416] fix: restore main files after squashed rebase Squashed rebase had overwritten workflow/skill files with old versions from fa4fc10, causing lint failures. Restore to cbf390b and keep only 416's 22-file drift gate. Refs: #416 * [#416] fix: sync pnpm-lock for website deps after rebase Add 6 catalog deps that were added to apps/website/package.json in main (6e37df9..cbf390b) but missing from squashed lock. Refs: #416 * [#416] fix: regenerate .pair/llms.txt after rebase Drift gate was red: 3 ADL lines missing (byte-compared artifact decisions added by this branch but not in tracked index). Regenerated via pnpm llms-index:regen. Refs: #416 * [#416] fix: restore pre-push gate to main after squashed rebase Squashed rebase had overwritten with old version, causing format-workflow-composition lint failures. Restore to cbf390b. Refs: #416 * [#416] fix: format dev-tools package.json pnpm format fix for prettier:check. Refs: #416 --------- Co-authored-by: T <t@e.com>
* [#416] feat: llms.txt drift gate (#475) * [#416] feat: llms.txt drift gate Squashed rebase of 17 commits onto main cbf390b (post-#468/#467/#466). Gate compares tracked .pair/llms.txt vs generateLlmsTxt byte-for-byte, reports missing/extra lines and regeneration command, wired into ci.yml + root quality-gate. Reuses generator, never writes. Refs: #416 * [#416] fix: restore dev-tools package.json after squashed rebase Merge main's yaml + format-workflow:check with 416's llms-index scripts. Pre-push hook bypassed for squashed rebase fix. * [#416] fix: sync pnpm-lock after squashed rebase CI frozen-lockfile failed: 6 deps removed from apps/website/package.json vs lock. Regenerated lock via pnpm install. Refs: #416 * [#416] fix: restore @pair/content-ops dep for drift gate Drift gate imports FileSystemService from @pair/content-ops. Squashed rebase had dropped it, causing tsc Cannot find module. Refs: #416 * [#416] fix: restore main files after squashed rebase Squashed rebase had overwritten workflow/skill files with old versions from fa4fc10, causing lint failures. Restore to cbf390b and keep only 416's 22-file drift gate. Refs: #416 * [#416] fix: sync pnpm-lock for website deps after rebase Add 6 catalog deps that were added to apps/website/package.json in main (6e37df9..cbf390b) but missing from squashed lock. Refs: #416 * [#416] fix: regenerate .pair/llms.txt after rebase Drift gate was red: 3 ADL lines missing (byte-compared artifact decisions added by this branch but not in tracked index). Regenerated via pnpm llms-index:regen. Refs: #416 * [#416] fix: restore pre-push gate to main after squashed rebase Squashed rebase had overwritten with old version, causing format-workflow-composition lint failures. Restore to cbf390b. Refs: #416 * [#416] fix: format dev-tools package.json pnpm format fix for prettier:check. Refs: #416 --------- Co-authored-by: T <t@e.com> * [#438] feat: opt-in business-impact.trivial-diff override Squashed rebase onto 5a18b8d (post-#475). 14 commits -> 1. Risk: green (trivial-diff override is opt-in, no behaviour change by default). Intended changes: 35 files (12 from branch already on main via #413/#475). Refs: #438 * [#438] fix: sync pnpm-lock for website deps Refs: #438 * [#438] fix: add @pair/content-ops dep for dev-tools type-check Squashed rebase dropped it from package.json (was in branch but not on main). Refs: #438 * [#438] fix: sync pnpm-lock for content-ops dep Refs: #438 * [#438] fix: restore process-step marker and skills-guide counts Branch removed <!-- process-step: id=bootstrap --> marker (added by #475 in cc169bd) and downgraded version 0.9.0->0.8.0. Also removed workflow skills from skills-guide. Restore to main. Refs: #438 * [#438] fix: add llms-index scripts + regenerate .pair/llms.txt Root package.json and dev-tools missing llms-index:check/regen scripts (added by #475). Regenerated index to match current tree. Refs: #438 * [#438] fix: drop stale workflow spillover, keep US-438 hunks on main files pair-implement-batch (all 4 copies) restored to main: branch carried #219-era full-file versions missing args.entryCapsules, breaking engine-boundaries/engine-integration dry-runs. No US-438 commit ever touched those files. US-438 one-liners (bootstrap trivial-diff sentence, skills-guide Classification row) re-applied onto main versions. turbo.json/tech-stack/way-of-working restored (post-base main additions). Changeset file removed per no-release decision. Refs: #438 * [#438] chore: retrigger CI Refs: #438 * [#438] fix: ADL names workflows/agents carve-out classes like §6 Review Minor: ADL point 2 said 'skill/workflow file' but enumerated only SKILL.md + .claude/skills/**; §6 + risk-matrix carve out .claude/workflows/** + .claude/agents/** since round 5. Aligned. Refs: #438 * [#438] chore: trigger mergeability recompute Refs: #438 --------- Co-authored-by: T <t@e.com>
Branch predated #479/#434/#475/#466 additions: restoring those files to main versions reverted repo-citation gate (5b/5c), US-479 loop text, #475 conformance test, turbo inputs. Re-applied only US-449 hunks (rename + invocation-awareness) via 3way port, verified per-file. Also: 2 missed pair-run (US-479 Host-runtime lines, both trees), ADL chalk-loss half-sentence. Local: 183+40+56+167+105+536 tests green, conformance PASS, docs:staleness PASS. Refs: #449
…ate can see when it does not (#473) * [#449] docs: every invocation names pair-cli Squashed rebase onto 69b6321 (post-#475). 17 commits -> 1. Risk: yellow (docs sweep, no behaviour change). Intended changes: 149 files (US-449 scope only). Refs: #449 * [#449] fix: port US-449 hunks onto main files, drop stale spillover Branch predated #479/#434/#475/#466 additions: restoring those files to main versions reverted repo-citation gate (5b/5c), US-479 loop text, #475 conformance test, turbo inputs. Re-applied only US-449 hunks (rename + invocation-awareness) via 3way port, verified per-file. Also: 2 missed pair-run (US-479 Host-runtime lines, both trees), ADL chalk-loss half-sentence. Local: 183+40+56+167+105+536 tests green, conformance PASS, docs:staleness PASS. Refs: #449 --------- Co-authored-by: T <t@e.com>
Branch predated #451/#479/#434/#475/#473/#466: restoring those files to main reverted run/ adapter, US-479 loop text, repo-citation gate, skill counts, review-identity scenario. Re-applied only #217 hunks via per-file 3way port (hash-verified), renamed #217-owned bare pair-run to pair-cli (staleness gate now flags them), fixed 2 missed occurrences + ADL chalk note pattern. Local: pair-cli 1998, conformance 4576, website 216, dev-tools 697, mirrors green. Refs: #217
PR Information
PR Title: [#416] feat: llms.txt drift gate
Story/Epic: #416 — no parent epic (cross-cutting quality-gate coverage)
Type: Feature (tech-debt)
Priority: P2 (Could-Have)
Labels:
user story,tech-debt,risk:green,pr-state:to-be-reviewedSummary
What Changed
pnpm llms-index:check— a gate that regenerates.pair/llms.txtwith the CLI's owngenerateLlmsTxtand requires byte equality with the committed file, printing the missing/extra lines and never writing the file. Wired intoci.ymland the rootquality-gate.Around it, three environment axes that would each make a byte-compared artifact machine-dependent are closed at the generator, plus the remedy the gate prints:
localeCompare, no locale ⇒ runtime ICU defaultcore.autocrlf=truerewrote all 570 lines.gitattributes(* text=auto eol=lf+ the index by name); the gate diagnoses any\rpath.join⇒.pair\knowledge\...on Windowsposix.joinfor emitted paths;joinfor file-system access onlypair update— no such executable herepnpm llms-index:regen, a root script that existsWhy This Change
.pair/llms.txtis generated and tracked, and it is the indexCLAUDE.mdpoints every agent at. Nothing compared it to its generator, so adding a guideline without regenerating silently hid it from every agent — two independent misses are on record (story-local-markers.md; the two how-to guides dropped in #246 and still indexed ~5 months later).A gate on a byte-compared artifact is only trustworthy if the artifact is byte-reproducible. Each axis above was measured as a full-file false positive on an untouched tree — collation: 458 of 560 entries move under ICU; terminator: 570 missing + 570 extra; separator: 562 missing + 562 extra — with a closing imperative that either cannot work or, obeyed, commits the damage.
Story Context
User Story: As a maintainer of the pair knowledge base, I want a quality gate that fails when
.pair/llms.txtno longer matches what the generator would emit, so that the machine-readable KB index thatCLAUDE.mdpoints agents at cannot silently go stale.Acceptance Criteria:
generateLlmsTxtcheckLlmsIndexDrift;compareIndexreturnsin-synconly on exact equalityformatDrift, multiset deltas (a duplicated line is drift a set view cannot see), with look-alike pairs rendered byte-escapedmain.github/workflows/ci.ymlstepllms-index:checkquality-gatechain + the sameci.ymlstep;gate:compositionguards the chainREGENERATION_COMMAND = 'pnpm llms-index:regen', asserted as a literal AND resolved against the real rootpackage.json; the gate is handed a 3-method read-only fs slice, so "cannot write" is a type factgenerateLlmsTxt's own output; the form is never re-litigatedChanges Made
Implementation Details
packages/dev-tools/src/quality-gates/llms-txt-drift-check.ts. Four outcomes as a discriminated union, because they have different remedies:in-sync,drift,broken-setup(no indexable section — an unfinished install, not a stale index),unreadable-index(the tracked file's own permission bits or a directory in its place). Reports the terminator (trackedCarriesCr), a BOM (trackedCarriesBom) and emptied sections, and puts the matching precondition in front of the closing imperative — a report that says "restore the tree first" and then closes with a bare "regenerate" delivers, in its own call to action, the damage the caution exists to prevent.packages/dev-tools/src/quality-gates/llms-txt-regenerate.ts(pnpm llms-index:regen). The check's exact inverse: same generator, same tracked path, one file written. It runs the check first and refuses onbroken-setup,unreadable-index, an unreadable tree,trackedCarriesCrandemptiedSections, printing the gate's own message — so obeying the printed advice can never be the thing that loses a section. On theWRITE_MODE_FORMATTERSoffender list: a gate that ran its own remedy would hide the drift it exists to reveal.apps/pair-cli/src/registry/llms-generation.ts: code-unit ordering andposix.joinfor emitted paths. This is published-CLI behaviour, so it carries a patch changeset.LlmsSourceFs(3 read methods) replacesFileSystemServiceingenerateLlmsTxt's signature; the writer declares its extra power as a separate two-methodLlmsIndexSink.#216's byte-equality guard was replaced, not duplicated —llms-index-conformance.test.tskeeps only its output-shape assertions.Files Changed
packages/dev-tools/src/quality-gates/llms-txt-drift-check.ts+.test.ts,packages/dev-tools/src/quality-gates/llms-txt-regenerate.ts+.test.ts,apps/pair-cli/src/registry/llms-generation.win32.test.ts,.gitattributes,.changeset/llms-txt-deterministic-order.md, 3 ADLs under.pair/adoption/decision-log/apps/pair-cli/src/registry/llms-generation.ts,apps/pair-cli/src/registry/llms-index-conformance.test.ts,packages/dev-tools/src/quality-gates/pre-push-gate-composition.ts+.test.ts,packages/dev-tools/{package.json,tsconfig.json,README.md}, rootpackage.json,.github/workflows/ci.yml,.pair/llms.txt,.pair/adoption/tech/way-of-working.md,DEVELOPMENT.md,apps/website/content/docs/contributing/development-setup.mdxServices to Release
@pair/pair-cli(patch changeset):.pair/llms.txtis now emitted in a deterministic, locale-independent order and with POSIX separators on every platform. An adopter's nextpair-cli install/pair-cli updaterewrites the file once — uppercase-first entries sort before their lowercase siblings; a Windows adopter additionally stops shipping 562 backslash-separated, unresolvable links. Generated file, so a one-time diff, not a migration.Testing
Test Coverage
\r\r\n/ bare CR / CR+LF / stray CR at EOF; invisible-character rendering; the four outcomes), 11 for the regeneration command (write path, idempotence, BOM strip, and one row per refusal state), 53 for gate composition, 221 across the CLI registry.pnpm --filter @pair/website e2e— 39 passed (a docs.mdxchanged).Test Results
Testing Strategy
llms-generation.win32.test.tsbindspathto Node's ownpath.win32(whatrequire('path')returns on Windows) and asserts the generator emits the same bytes a POSIX machine emits, order included. On POSIXjoinandposix.joinare the same function, so this is the only shape of test that can tell the fixed code from the broken code on a Linux CI.Reviewer Guide
Boundary probes (run against the real producers, not stubs)
path.win32bound to the real generator over the real repo tree, output into the realcompareIndex/formatReportin-syncgit clone+pnpm install(nothing built), add a guideline, run the gate, type the printed command verbatim, re-run✓ regenerated→ green;git diff --stat= `.pair/llms.txtpair-cli install/pair-cli update, andpairis not a binarypnpm packofapps/pair-cli+ its two workspace deps →npm ithe three real tarballs into an emptynpm initproject → run the linked bin in an empty target dirbin = {"pair-cli":"dist/cli.js"};node_modules/.binlinkspair-cli, nopair;which pair→ not found.pair-cli install --offline --source packages/knowledge-hub/datasetwrote.pair/llms.txt(474 lines, sha1733c39ed…); after tampering the file,pair-cli updaterestored it byte-identical. The retired remedy stringpair updatenames no executable — which is why the gate printspnpm llms-index:regen.pair/llms.txtconverted to CRLFrm+git checkout --recipecore.autocrlf=trueclonegit add --renormalizestages nothing and leaves all 583 CR lines;rm+git checkout --givesw/lf, 0 CRs, gate green — withcore.autocrlfleft attrue(theeol=lfattribute overrides it)pnpm install, no build, run the gatets-node -T: type-checking made the verdict depend on whether someone had built@pair/content-ops)Testing the Changes
Documentation
Technical Decisions
2026-09-01-a-gate-imports-its-generator-by-source-and-gets-a-read-only-slice.md"composite": false, a@pair/content-opsdevDependency that ordersts:checkand resolves nothing, one hardcoded hop) and runs it transpile-only; code invoked by a gate takes the narrowest fs capability2026-09-01-a-byte-compared-generated-artifact-sorts-by-codepoint.mdeol=lfpin + terminator diagnosis, POSIX separators in emitted paths2026-09-03-a-gate-names-a-remedy-it-can-run.mdConsumed, not re-decided:
2026-08-11-a-mirror-guard-compares-the-transform.md,2026-07-31-pre-push-gate-is-check-only.md,2026-08-20-a-user-facing-cli-fix-carries-its-changeset.md.Docs updated:
DEVELOPMENT.md+ its byte-identical docs-site twin (development-setup.mdx),way-of-working.md(Quality Gates),packages/dev-tools/README.md.One command family per statement: the adoption bullet and the gate's own header name the index's producer as
pair-cli install/pair-cli update(the publishedbinispair-cli), andpair updateappears only where it is explicitly labelled the retired spelling. A file that credits a command with generating the index and denies that binary exists 100 words later re-teaches, in the project's source of truth for the gate, the exact string ADL 2026-09-03 retired.Dependencies & Related Work
Related PRs
pnpm mirrors:regenerate, the mirror-realignment writer. Unmerged, so this branch does not depend on it. The two commands are complementary and differently scoped: that one realigns the dataset mirrors (rewriting four trees and deleting target-only files under amirrorregistry); this one regenerates the single byte-compared index this gate compares. When [#419] feat: mirrors:regenerate — local, deterministic mirror realignment #476 lands it will also rewrite.pair/llms.txtas a side effect — a superset, not a conflict.Follow-up Work
.pair/llms.txt), plus the three reproducibility axes found while building it.origin/main([#413] feat: CI runs format:check — a dedicated workflow, no trigger-shaped hole #477 merged after its base). Rebasing was deliberately left to the merge decision rather than folded into a fix round.