Context
A knowledge-base sync on a remote deployment fails outright with:
PullRequestSource: pull request 11982 has more than one local artifact
(resources/content/archive/pulls/v13.0.0/chunk-1/pr-11982.md and
resources/content/archive/pulls/v13.0.0/chunk-10/pr-11982.md)
— refusing to embed duplicate evidence under one logical name. Repair the corpus first.
The refusal is correct. The corpus is not.
The Problem
resources/content/archive/pulls currently holds 27 duplicated logical PR names, each appearing under two different chunk directories. The pr-11982 pair has divergent md5s (9263d3f3… vs ca5ce901…), so these are two different documents asserting the same identity — not harmless copies. Embedding either one silently would attach one PR's evidence to another's logical name, which is why PullRequestSource refuses instead.
Consequences:
- The full-corpus sync aborts on the first duplicate. Enumeration never completes, so KB document count stays 0 and
get_ingestion_progress reports all-null timestamps. A deployment in this state has a Knowledge Base server of zero value.
- This very likely affects our own KB sync, which needs verifying as the first act of this ticket. Our KB still answers queries from previously embedded content, so a frozen sync would be invisible — the failure mode is silent staleness, not an error anyone sees.
The guard never existed — nothing prevents a duplicate logical name from entering the corpus, and nothing detects one until an embed attempt refuses it, potentially long after the commit that caused it.
The Architectural Reality
PullRequestSource already owns the invariant and enforces it at the right moment — at embed time, fail-closed, with a precise message. The gap is that the invariant is enforced only at the point of consumption, by a component that runs on a schedule, possibly on someone else's host, days after the commit that broke it. By then the author is gone and the failure surfaces as "the client's KB is empty."
The invariant is a property of the committed corpus, so it should be checked where the corpus changes. This is the same shape as the config-leaf parity manifest: an invariant a lint asserts at commit time rather than one a runtime discovers later.
The Fix (one PR)
- Repair the 27 existing collisions. Each pair needs a decision, because the contents diverge — this is not a mechanical dedupe. Determine which artifact is authoritative for its logical name (or whether one is misfiled into the wrong chunk) and reconcile.
- Add the guard: a lint that fails when two artifacts under
resources/content/archive/** claim the same logical name, wired into the existing lint surface so it runs pre-commit and in CI.
- The guard must land with the repair — added first, CI goes red on
dev.
Acceptance Criteria
Out of Scope
- Tenant-repo pull-mode ingestion failures — a separate lane with a separate cause; see the ingestion-diagnosability ticket.
- KB chunk-layout redesign.
Related
- #15798 (Local Runtime Parity) — the deployment surface where this surfaced
Context
A knowledge-base sync on a remote deployment fails outright with:
The refusal is correct. The corpus is not.
The Problem
resources/content/archive/pullscurrently holds 27 duplicated logical PR names, each appearing under two different chunk directories. Thepr-11982pair has divergent md5s (9263d3f3…vsca5ce901…), so these are two different documents asserting the same identity — not harmless copies. Embedding either one silently would attach one PR's evidence to another's logical name, which is whyPullRequestSourcerefuses instead.Consequences:
get_ingestion_progressreports all-null timestamps. A deployment in this state has a Knowledge Base server of zero value.The guard never existed — nothing prevents a duplicate logical name from entering the corpus, and nothing detects one until an embed attempt refuses it, potentially long after the commit that caused it.
The Architectural Reality
PullRequestSourcealready owns the invariant and enforces it at the right moment — at embed time, fail-closed, with a precise message. The gap is that the invariant is enforced only at the point of consumption, by a component that runs on a schedule, possibly on someone else's host, days after the commit that broke it. By then the author is gone and the failure surfaces as "the client's KB is empty."The invariant is a property of the committed corpus, so it should be checked where the corpus changes. This is the same shape as the config-leaf parity manifest: an invariant a lint asserts at commit time rather than one a runtime discovers later.
The Fix (one PR)
resources/content/archive/**claim the same logical name, wired into the existing lint surface so it runs pre-commit and in CI.dev.Acceptance Criteria
Out of Scope
Related