Context
A source-integrity audit while implementing #15088 falsified the local pull-request corpus contract. The Bird View can bypass the content index and report local divergence, but that containment is not a repair of the generated GitHub-content substrate.
A direct 2026-07-13 census found:
resources/content/_index.json: 4,566 pulls entries.
- Active + archived corpus: 4,593 files representing 4,566 unique PR IDs.
- 2,015 index entries reference missing paths; every affected ID still exists under
archive/pulls/.
- 27 PR IDs exist twice in the archive; every pair is byte-divergent.
The Problem
PR #13200 added PullRequestSyncer.reconcileClosedPullRequestLocations() and correctly moved the historical terminal-PR backlog out of the active tree. Its persistence boundary is incomplete:
reconcileClosedPullRequestLocations() calls fs.rename() but does not upsert the moved PR's _index.json entry.
- Its bucket plan sees the active scan plus delta-only
metadata.pulls, not complete existing archive-bucket membership, so it can calculate an ordinal target from a partial collection.
syncPullRequests() later rebuilds metadata.pulls from the fetched delta and upserts only those PRs. A historical archived PR refreshed without a cached prior path can be written at a partial-plan location while its earlier archived copy remains.
- No post-pass proves that every indexed path exists or that each PR ID has exactly one corpus artifact.
The prior assumption that “the next sync rebuilds _index.json” is empirically false for archive moves: the delta sync does not enumerate the complete archive, while reconcileActiveChunks() explicitly handles only the active tier.
Historical falsifier: sync commit 657f7f8d13600a01530fb66434e1f5c3401a220f moved 1,325 PR files from active to archive. Representative index entries for descriptive PRs #9537 and #10124 remained byte-identical before/after and continued to name active paths.
The Architectural Reality
ADR 0004 governs this generated-content substrate:
- §1.3: GitHub is source of truth;
resources/content/ is regeneratable.
- §2.4–§2.5: archive membership is sealed and ordinal paths use complete bucket ordering.
- §3.2:
_index.json is the ID-to-path lookup contract.
- §3.3: syncers update the index alongside content writes.
Owning surfaces:
ai/services/github-workflow/sync/PullRequestSyncer.mjs
#planBuckets()
reconcileClosedPullRequestLocations()
syncPullRequests()
ai/services/github-workflow/shared/contentIndex.mjs
ai/services/github-workflow/shared/reconcileActiveChunks.mjs
ai/services/knowledge-base/source/PullRequestSource.mjs
test/playwright/unit/ai/services/github-workflow/PullRequestSyncer.spec.mjs
The Agent OS structure map was run at creation time and confirms GitHub Workflow sync/shared services own the repair. #15088 remains non-blocked because its runtime reader deliberately bypasses the stale index and treats live GitHub as canonical; that safeguard must not become permission to leave the local projection corrupt.
The Fix
One coherent repair lane:
- Plan PR placement against a complete PR corpus inventory, including existing archive-bucket membership. Never derive a sealed archive ordinal from the current delta alone.
- Preserve an existing unique archived location when refreshing that PR. For a new active→archive move, compute the target from complete bucket membership.
- Treat file move/write and
_index.json upsert as one sync-pass mutation set. Before the generated-content commit, validate that every resulting indexed path exists.
- Detect duplicate PR IDs across active + archive:
- byte-identical copies may be deterministically collapsed;
- byte-divergent copies fail loud and are restored from canonical GitHub state or an ADR-0004 clean regeneration—never arbitrary “keep first” deletion.
- Repair the current generated corpus through the corrected normal sync/clean-regeneration path. Do not hand-edit 2,015 paths or add a one-off migration script.
- Emit a structured integrity result containing stale paths, duplicate IDs, divergent IDs, and repaired counts so the sync cannot silently commit partial integrity.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Evidence |
PullRequestSyncer.reconcileClosedPullRequestLocations() |
ADR 0004 §3.3 |
Every successful active→archive move contributes its index upsert in the same sync pass |
Move/index mismatch fails the generated-content pass before commit |
No-metadata and multi-move fixtures |
PullRequestSyncer.syncPullRequests() |
ADR 0004 §2.4–§2.5 |
Historical refreshes update their unique existing archive location; new placement uses complete membership |
Missing/ambiguous prior location routes to integrity repair, not a second write |
Existing-archive refresh fixture |
resources/content/_index.json |
ADR 0004 §3.2 |
Exactly one PR entry per ID and every indexed path exists |
Stale entry is an explicit integrity failure |
Full-corpus validation fixture |
| PR artifact uniqueness |
GitHub source of truth + ADR 0004 §1.3 |
Exactly one local artifact per PR ID |
Divergent duplicates fail loud and restore from GitHub/clean regeneration |
Equal-copy and divergent-copy fixtures |
PullRequestSource input |
Knowledge Base source config |
Active+archive extraction observes unique PR identities only |
Integrity failure blocks duplicate projection from masquerading as distinct evidence |
Duplicate logical-name falsifier |
Decision Record impact
aligned-with ADR 0004. This repairs enforcement of the accepted content-index and ordinal archive contracts; it does not amend them.
Acceptance Criteria
Out of Scope
- The resolved-PR Bird View runtime feature in #15088.
- Generalizing the repair to issues or discussions without equivalent empirical evidence.
- Re-chunking otherwise valid sealed archives.
- A one-off migration script or manual generated-file cleanup.
Avoided Traps
- Do not treat delta-only
metadata.pulls as the full PR corpus.
- Do not compute sealed archive ordinals from only the current delta or active backlog.
- Do not copy
reconcileActiveChunks()'s “keep first, unlink rest” behavior onto divergent archive artifacts.
- Do not merely warn and continue committing a stale index.
- Do not treat
#15088's index bypass as resolution of this defect.
Related
Follow-up: #13001 / PR #13200
Discovered by, non-blocking: #15088
Prior index substrate: #11390 / PR #11403
Adjacent active-tier repair: #13328 / PR #13332
Authority: learn/agentos/decisions/0004-github-content-architecture.md
Live duplicate sweep: latest 20 open issues, all open PRs, recent all-state A2A claims, targeted local history, and semantic Knowledge Base tickets checked at 2026-07-13T14:12Z; no equivalent open ticket, PR, or in-flight claim found.
Origin Session ID: 837ad74b-c2d2-413d-9aab-b7165a93a82a
Retrieval Hint: "PullRequestSyncer archive rename stale _index 2015 paths 27 divergent duplicate PR artifacts #13001 #13200"
Context
A source-integrity audit while implementing
#15088falsified the local pull-request corpus contract. The Bird View can bypass the content index and report local divergence, but that containment is not a repair of the generated GitHub-content substrate.A direct 2026-07-13 census found:
resources/content/_index.json: 4,566pullsentries.archive/pulls/.The Problem
PR #13200 added
PullRequestSyncer.reconcileClosedPullRequestLocations()and correctly moved the historical terminal-PR backlog out of the active tree. Its persistence boundary is incomplete:reconcileClosedPullRequestLocations()callsfs.rename()but does not upsert the moved PR's_index.jsonentry.metadata.pulls, not complete existing archive-bucket membership, so it can calculate an ordinal target from a partial collection.syncPullRequests()later rebuildsmetadata.pullsfrom the fetched delta and upserts only those PRs. A historical archived PR refreshed without a cached prior path can be written at a partial-plan location while its earlier archived copy remains.The prior assumption that “the next sync rebuilds
_index.json” is empirically false for archive moves: the delta sync does not enumerate the complete archive, whilereconcileActiveChunks()explicitly handles only the active tier.Historical falsifier: sync commit
657f7f8d13600a01530fb66434e1f5c3401a220fmoved 1,325 PR files from active to archive. Representative index entries for descriptive PRs#9537and#10124remained byte-identical before/after and continued to name active paths.The Architectural Reality
ADR 0004 governs this generated-content substrate:
resources/content/is regeneratable._index.jsonis the ID-to-path lookup contract.Owning surfaces:
ai/services/github-workflow/sync/PullRequestSyncer.mjs#planBuckets()reconcileClosedPullRequestLocations()syncPullRequests()ai/services/github-workflow/shared/contentIndex.mjsai/services/github-workflow/shared/reconcileActiveChunks.mjsai/services/knowledge-base/source/PullRequestSource.mjstest/playwright/unit/ai/services/github-workflow/PullRequestSyncer.spec.mjsThe Agent OS structure map was run at creation time and confirms GitHub Workflow sync/shared services own the repair.
#15088remains non-blocked because its runtime reader deliberately bypasses the stale index and treats live GitHub as canonical; that safeguard must not become permission to leave the local projection corrupt.The Fix
One coherent repair lane:
_index.jsonupsert as one sync-pass mutation set. Before the generated-content commit, validate that every resulting indexed path exists.Contract Ledger Matrix
PullRequestSyncer.reconcileClosedPullRequestLocations()PullRequestSyncer.syncPullRequests()resources/content/_index.jsonPullRequestSourceinputDecision Record impact
aligned-with ADR 0004. This repairs enforcement of the accepted content-index and ordinal archive contracts; it does not amend them.Acceptance Criteria
metadata.pullsentry receives a correct_index.jsonupsert in the same sync pass.pullsindex path exists and that indexversion,chunkNumber, andpathmatch the artifact.PullRequestSourcefalsifier proves the repaired corpus emits no duplicate logicalpr-N#...names.Out of Scope
Avoided Traps
metadata.pullsas the full PR corpus.reconcileActiveChunks()'s “keep first, unlink rest” behavior onto divergent archive artifacts.#15088's index bypass as resolution of this defect.Related
Follow-up: #13001 / PR #13200
Discovered by, non-blocking: #15088
Prior index substrate: #11390 / PR #11403
Adjacent active-tier repair: #13328 / PR #13332
Authority:
learn/agentos/decisions/0004-github-content-architecture.mdLive duplicate sweep: latest 20 open issues, all open PRs, recent all-state A2A claims, targeted local history, and semantic Knowledge Base tickets checked at 2026-07-13T14:12Z; no equivalent open ticket, PR, or in-flight claim found.
Origin Session ID: 837ad74b-c2d2-413d-9aab-b7165a93a82a
Retrieval Hint: "PullRequestSyncer archive rename stale _index 2015 paths 27 divergent duplicate PR artifacts #13001 #13200"