ID-68 {68.12} — Docs/Ledger Relocation: V2 Addendum (Warp-grounded verdict + routing taxonomy + ontology auto-sync)
ID-68 {68.12} — Docs/Ledger Relocation: V2 Addendum (Warp-grounded verdict + routing taxonomy + ontology auto-sync)
Section titled “ID-68 {68.12} — Docs/Ledger Relocation: V2 Addendum (Warp-grounded verdict + routing taxonomy + ontology auto-sync)”Type: Investigation report (V2 addendum). NO implementation — investigation + design only. No code, test, ledger, skill, or workflow edits made. Authored: 02/06/2026 by a directed cmux research worker. Extends:
RELOCATION-INVESTIGATION.md(S299), per Liam’s S301 feedback. Read that first — V2 does not restate its §1 codebase inventory; it tests, amends, and extends it. Companion (superseded framing):DOCS-RELOCATION-SUBTASK.md(S293 R-Split).
Ratification (S301 — 02/06/2026)
Section titled “Ratification (S301 — 02/06/2026)”Liam ratified all 12 open questions (OQ-R1…OQ-R12) on 02/06/2026. They are closed — the §6′ table below records each disposition. Two headline rulings:
- OQ-R10 — the partitioned routing taxonomy in §D2 is ratified policy, amending the
S294 blanket override (“move everything under
/docs+/.planningout”). - OQ-R12 (security re-examination, S-B adopted) — SENSITIVITY is now a PRIMARY routing
axis. The docs-site (internal KB, not customer docs — Warp precedent does not apply) +
the recon-valuable spaces (
reference,runbooks,specs→decisionsrender,product-functionality,generated) move toknowledge-hub-internalwith a GATED Vercel deployment;ontologySTAYS (sanitised public-safe build input + cross-repo published);designSTAYS (public-safe); ledgers + raw spec source STAY (sanitised-public). The S299 §3 code→private-docs publish bridge is re-added, security-justified. Vercel Deployment Protection is CONFIRMED enabled (present-tense exposure closed). The §D2 rows carry per-row amended OQ-R12 (S301) notes.
Other rulings folded in:
retire documentation-inventory.md + doc-freshness.test.ts keeping a slim
reference-doc-paths.test.ts (R8); Starlight sidebar + Pagefind replace the inventory and
the same-commit write-coupling rule is removed (R9); docs/ontology/ stays in the code repo
(R7); product-retros.json stays with the other 3 ledgers and the relocated evaluation lane
becomes a code→ledger cross-repo writer via the docs-bridge GitHub App (R4); add
ontology-sync.yml + add docs/ontology/** to the code→docs publish set (R11); sibling
checkout + KH_DOCS_DIR and a GitHub App for cross-repo auth (R1/R2, detail deferred to
implementation); R3/R5/R6 resolved by R10; R12 = Option S-B (docs-site + recon spaces →
private gated; ontology/design + ledgers/specs stay sanitised-public; Vercel gating
confirmed). The phased implementation design lives in RELOCATION-IMPLEMENTATION-PLAN.md.
0. What V2 changes (read this first)
Section titled “0. What V2 changes (read this first)”S299 recommended Option A (two-repo split, sibling checkout, one KH_DOCS_DIR env var)
and declared an “unavoidable structural cost”: sidecar→orthogonal trades
zero-drift-by-construction for autonomy. V2 tests that claim against Warp’s actual code and
finds it conditionally true, not unconditionally true — the cost is a function of the
routing choice, and Warp engineered most of it away by partitioning content rather than
moving all of it. Four concrete deltas:
-
D1 verdict (amended). Warp did not leave the cost unavoidable. They keep lockstep-mutated content (engineering specs) inside the code repo and move only published-derived docs out, where an agent (docubot) auto-compensates drift on every PR. The cost only materialises for content you both move out and mutate in lockstep with code. S299’s “move everything under
/docs+/.planningout” maximises that surface. (§D1) -
D2 routing taxonomy (now ratified S301 policy). A prescriptive per-doc-type destination table. The load-bearing principle, Warp-grounded and ratified (OQ-R10): build inputs + lockstep-mutated SDLC state stay in the code repo (sanitised); pure-published + durable-private + ephemeral move out. This amends the S294 blanket override. (§D2)
-
D3 retire, don’t relocate (new). The Starlight autogenerated sidebar is the inventory —
documentation-inventory.mdretires.doc-freshness.test.tsis a different thing (a doc→code-path guard the docs-site build does not replace); retiring it loses a real guarantee for 3 docs. Precise loss + replacement specified. (§D3) -
D4 ontology sync is brownfield + a build-coupling S299 missed. Ontology sync was already built — the WP6 Markdown Ontology Harness (S236–S238): markdown register as source-of-truth, build-time codegen, and a 3-way parity test (markdown ↔ generated tuple ↔ live DB CHECK) that fails CI on drift. It does not mirror taxonomy-sync (inverted source-of-truth: ontology’s markdown lives in git, so it needs a guard, not an auto-commit workflow). The split-survival delta is one routing decision:
docs/ontology/04-content-type.mdis a code-repoprebuildgenerator source — moving it breaksbun build/bun dev, not just the docs-site — so the register stays in the code repo and the whole harness keeps working unchanged. No new workflow required. (§D4)
The §6 OQs are revised at the end — all 12 are ratified/closed (S301, 02/06/2026), incl. the OQ-R12 security re-examination (Option S-B; sensitivity-primary routing).
D1 — The “unavoidable structural cost” tested against Warp
Section titled “D1 — The “unavoidable structural cost” tested against Warp”D1.1 Sources cross-checked
Section titled “D1.1 Sources cross-checked”- Blog: Open-sourcing our docs and the agents that maintain them (warp.dev).
- Local Warp code repo:
/Users/liamj/Documents/development/Warp— confirmed to be the code repo (warpdotdev/warp): Rust workspaceCargo.toml, README links out tohttps://docs.warp.dev. Top-level dirs:.agents/ .claude/ .warp/ .github/ app/ crates/ command-signatures-v2/ docker/ resources/ script/ specs/. - Mempalace provenance: a prior KH research doc —
docs/research/docs-site-rebuild-research.md(716 lines, S51) — already inventoried Warp’s 6 docs skills atgithub.com/warpdotdev/docs/.agents/skills/(24 skills total) and docubot’s 7-step composite action. Corroborates the repo evidence below.
D1.2 The concrete mechanism (claims confirmed against files)
Section titled “D1.2 The concrete mechanism (claims confirmed against files)”| Blog claim | Repo evidence (code repo at /Users/liamj/Documents/development/Warp) | Verdict |
|---|---|---|
| Docs live in a separate repo | README → docs.warp.dev; no top-level docs/ or .planning/ (confirmed absent by ls) | Confirmed |
| ”Agents that maintain them” are in the docs repo | The 6 docs skills (review-docs-pr, update-changelog, sync-error-docs, missing_docs, check_for_broken_links, docs-seo-audit) are NOT in the code repo’s .agents/skills/ (20 skills, all engineering: create-pr, write-tech-spec, rust-unit-tests, …). They live in warpdotdev/docs/.agents/skills/ per mempalace. | Confirmed |
| Docs “follow the code automatically” across the boundary | docubot: .github/workflows/docubot_reply_to_comment.yml + .github/actions/docubot/action.yml (action.yml:30 checks out warpdotdev/gitbook via token into a local path) + prompt.txt. The Warp CLI agent reads the invoking PR’s diff, edits the docs repo’s .md, opens a docubot/<slug> branch + PR there, posts the link back. | Confirmed |
| Engineering specs | Warp checks specs/GH<issue>/PRODUCT.md + TECH.md into the code repo (top-level specs/, authored by in-repo write-product-spec/write-tech-spec skills). | Confirmed — specs do NOT move out |
| (Bonus) code public/private boundary | .github/workflows/repo-sync.yml mirrors public warpdotdev/warp ↔ private warpdotdev/warp-internal. Prior art for KH’s own {68.9} flip. | Confirmed |
Repo-name note: the blog and mempalace name the docs repo
warpdotdev/docs; the local code repo’s docubot action checks outwarpdotdev/gitbook. The backing repo was renamed on open-sourcing; the mechanism (token-authed cross-repo checkout → agent edit → cross-repo PR) is identical and is what KH already ported as its owndocubot.yml+.github/actions/docubot/+scripts/docubot/run-agent.ts.
D1.3 Verdict — did Warp engineer the cost down, and how?
Section titled “D1.3 Verdict — did Warp engineer the cost down, and how?”Yes — by partitioning content, not by moving all of it. Two named mechanisms:
-
docubot (the drift-compensation agent). The cost S299 framed as “a spec and the code it describes land in one PR; after the split they land in two repos and can drift” is only paid for content that crosses the boundary. For everything Warp moves out (customer-facing docs), docubot regenerates the affected pages from each PR’s diff and opens a docs-repo PR automatically. The drift is detected and compensated at source-change time, per-PR — exactly the role S299 §4 re-attributed to KH’s ported
sync-source-docs+ docubot. KH already owns this tool. So for derived/published docs the cost is genuinely engineered down to “an agent opens a second PR for you,” not “a human must remember to update two repos.” -
Keeping lockstep-mutated content in the code repo (the cost-avoidance, not cost-compensation, mechanism). Warp’s engineering specs never leave the code repo. They are not published, not derived, and they mutate in lockstep with code — so Warp pays zero cross-repo drift cost on them by simply not splitting them out. The only content Warp moves out is the published, code-derived surface, where docubot handles drift.
Therefore the cost is not unconditionally unavoidable. It is unavoidable only for content that is simultaneously (a) moved out of the code repo and (b) mutated in lockstep with code. The cardinality of that set is a routing decision, not a law of nature:
- Under S299’s blanket “move everything under
/docsout” override, the lockstep-mutated set forced across the boundary is large: the ledgers (written essentially every session), the activedocs/specs/ID-N-*dirs (written by the spec-driven skills), and — newly surfaced in §D4 — the ontology CV register (a code-repo build input). Each one is a recurring double-commit / cross-repo-bridge tax. - Under the Warp-grounded routing (§D2), that set shrinks to ~empty: ledgers, active
specs, ontology register, the 3 freshness-guarded reference/runbook docs, and generated
artefacts all stay in the code repo (sanitised). Only durable-private
(
.planning/.archive/), ephemeral (continuation-prompts, old audits), and pure-published prose move out — and the published surface’s drift is docubot’s job.
Grounded revision of S299 §4’s verdict: the sentence “moving from sidecar→orthogonal
trades zero-drift-by-construction for autonomy” stays true for whatever you choose to move
out. What S299 got wrong is implying the trade is total and forced. Warp’s evidence
(specs/ in-repo; docubot per-PR; 6 maintenance skills in the docs repo only) shows the
honest framing is: route lockstep-mutated content to the code repo so you never pay the
trade on it; move only what is published-derived (drift auto-compensated) or
private-historical (never mutated again). The “unavoidable cost” is real but bounded by
the routing taxonomy, and the taxonomy is the actual deliverable of {68.12}.
Ratified (S301, OQ-R10): this partitioned routing is adopted policy and amends the S294 blanket override. The §D2 table is the binding relocation plan.
D2 — Doc-type routing taxonomy (ratified S301 policy)
Section titled “D2 — Doc-type routing taxonomy (ratified S301 policy)”Status: ratified (OQ-R10, S301 02/06/2026). This table is the adopted relocation policy and amends the S294 blanket “move everything out” override — it is no longer a recommendation.
Routing principle (Warp-grounded + SENSITIVITY-primary, amended by OQ-R12 S301):
SENSITIVITY is the PRIMARY axis (OQ-R12). If an artefact has recon/attack value (architecture, runbooks, deploy/secrets, internal decisions, API/structure maps, product strategy) it is INTERNAL-ONLY and must not be world-readable in the public repo — it routes to the private
knowledge-hub-internalregardless of build-coupling. Only genuinely public-safe artefacts (post-{68.11}sanitisation) may stay in the public code repo. Build-coupling is the secondary axis, applied within the public-safe set. STAYS-IN-CODE-REPO if the artefact is public-safe and (build input — a generator/CI/test reads it — or lockstep-mutated by the SDLC loop). Build inputs that are NOT public-safe are minimised + sanitised to public-safe, or fed cross-repo (§D4, §0.2.4 of the implementation plan). MOVES-TO-knowledge-hub-internalif it is internal-only (recon value) or durable-private (historical IP) or dev-internal prose not on any build/loop path. PUBLISHED-TO-DOCS-SITE is an orthogonal axis: a code-repo doc can stay canonical in the code repo and be published to the site via the code→docs bridge (this is already how thereference/runbooks/ontologyspaces work viasync-manifest.json). EPHEMERAL if point-in-time and safe to retire/delete after a window.
Destinations are not mutually exclusive with publication: “stays-in-code-repo + published” means canonical in code repo, surfaced read-only on the site.
| Tree / doc-type | Destination | Lifecycle | Sync direction (if it crosses code↔docs) | Why |
|---|---|---|---|---|
docs/reference/*.json ledgers (task-list, product-backlog, product-roadmap, product-retros, umbrellas) + mirrors (tasks/ roadmap/ backlog/ retros/) | stays-in-code-repo | durable | none (already deny-listed from docs-site) | SDLC write-path; loop writes every session; ledger-cli + 4 roundtrip guards read them. Already never published. |
docs/specs/ID-N-*/ active spec source dirs (RESEARCH/PRODUCT/TECH/PLAN) | stays-in-code-repo (sanitised-public) — amended OQ-R12 (S301) | durable | code→private-docs (ratified-only decisions render now on the GATED internal site) | Raw spec source stays public (sanitised, {68.11}); its published decisions render moves WITH the docs-site to the private gated site. |
docs/runbooks/** | moves-to-knowledge-hub-internal (private, GATED site) — amended OQ-R12 (S301) | durable | n/a (internal site, in-repo) | HIGH sensitivity — deploy/secrets/DB-rebuild/CI playbooks (onprem-secrets-migration, database-rebuild-runbook, production-setup-guide, github-environments). Recon/attack value → internal-only. The one freshness-guarded runbook (taxonomy-change-runbook.md) decouples to a path-manifest (§0.2.4 of the plan). |
docs/ontology/01..32-*.md CV register | stays-in-code-repo (sanitised public-safe) + cross-repo published — amended OQ-R12 (S301) | durable | code→private-docs (ontology pulled to the internal site) | Build input — 04-content-type.md is the prebuild codegen source (§D4); moving it breaks bun build. Stays, but sanitise the go-to-market prose in 03-layer-vocabulary/14-bid-states (keep schema-visible keys+labels). |
docs/reference/*.md freshness-guarded (data-entry-points.md, classification-architecture.md) | moves-to-knowledge-hub-internal (private, GATED site) — amended OQ-R12 (S301) | durable | n/a (internal site) | HIGH sensitivity — data-entry-points is an attack-surface map; classification-architecture is AI internals. The freshness guard decouples from their prose to a code-repo path-manifest (§0.2.4 of the plan), so no private prose is read in public CI. |
docs/reference/*.md other (state-of-the-product, skill-routing-map, test-philosophy, ai-visibility-policy, ux-principles, …) | moves-to-knowledge-hub-internal (private, GATED site) — amended OQ-R12 (S301) | durable | n/a (internal site) | HIGH sensitivity — architecture/AI-strategy/roadmap recon. Loop/agents read them via the sibling KH_DOCS_DIR checkout. |
docs/reference/classification-prompt.md | stays-in-code-repo | durable (regenerated) | none | GENERATED by sync:taxonomy (build output). Lives with its generator. (Public-safety: review — it is a generated prompt; confirm no sensitive prose in OQ-R12 follow-up.) |
docs/reference/documentation-inventory.md | retire (§D3) | — | — | Superseded by the Starlight autogenerated sidebar + Pagefind. |
docs/generated/** (codebase-stats, mcp-inventory, type-drift-*) | moves-to-knowledge-hub-internal (private, GATED site) — amended OQ-R12 (S301) | durable (regenerated) | n/a (internal site; regeneratable from code) | HIGH sensitivity — mcp-inventory = full API surface, codebase-stats = structure map. Regenerated artefacts; render on the internal site only. |
docs/design/** (Warm Meridian spec/philosophy/identity.pdf/audit) | stays-in-code-repo (public-safe) + published — amended OQ-R12 (S301) | durable | code→private-docs (design to the internal site) | LOW sensitivity — visual identity only. Public-safe; cited by CLAUDE.md + .claude/checks/. |
docs/product-functionality/** | moves-to-knowledge-hub-internal (private, GATED site) — amended OQ-R12 (S301) | durable | n/a (internal site) | MOD–HIGH sensitivity — capabilities, AI-integration internals, governance, bid-management = product strategy + functional recon. |
docs/themes/** (orchestration assessments, workspace plans) | moves-to-docs-repo | durable-private | none (not a docs-site space) | Dev-internal strategy IP; not published, not a build input. |
docs/workflow-evaluation/** + docs/reference/workflow-evaluation/ | moves-to-docs-repo | durable-archive | none | 20+ archived sessions read by evaluate-workflow/evaluate-findings. The whole evaluation lane relocates as a unit (writes product-retros.json — which stays, so the evaluator runs against the code repo’s ledger; see OQ-R4). |
docs/continuation-prompts/** (handoffs + sNNN-worker-reports/) | ephemeral (move-to-docs-repo archive, prune after window) | ephemeral | none | Point-in-time session state. The active handoff is transient; historical ones are archive-only. |
docs/audits/** (point-in-time reports + eval JSONs) | moves-to-docs-repo | durable-private (mostly ephemeral) | none | Historical record; client-eval JSONs are IP-sensitive. |
docs/research/** (investigations incl. docs-site-rebuild-research.md, coolify evals) | moves-to-docs-repo | durable-private | none | Internal decision research; point-in-time. |
docs/operations/** (cutover/re-ingestion reports) | moves-to-docs-repo | durable-private (mostly ephemeral) | none | Internal ops record. |
docs/handover-guides/** (gdpr-data-export.md) | moves-to-docs-repo | durable | none | Internal operational handover. |
docs/testing/test-data/** | stays-in-code-repo if used as fixtures; else moves | durable | none | Verify fixture consumption before routing. (Note: test-data/templates/ CSP file is {68.5}’s job — coordinate, don’t double-handle.) |
docs/testing/{e2e,uat}/** | moves-to-docs-repo unless referenced by Playwright config | mixed | none | Test prose/plans; relocate only the non-build-input parts. |
docs/database/** | n/a | — | — | gitignored (.gitignore:112) — never tracked, never public. No action. |
.planning/.archive/** (1,269 tracked files in HEAD; sparse-checkout omits from this worktree) | moves-to-docs-repo + history-purge | durable-private | none | The single biggest IP + client-name concentration. Move at HEAD and strip from all code-repo history ({68.10}). |
.planning/codebase/** (7 architecture docs) | retire | ephemeral | — | RETIRED per S299/Liam (GitNexus + ast-dataflow supersede). Do not carry over. |
.planning/knip-baseline.txt | stays-in-code-repo | durable | none | CI knip-gate baseline — a build input. |
docs-site/** (Astro project + Vercel deployment) | moves-to-knowledge-hub-internal + GATED deployment — amended OQ-R12 (S301) | durable | code→private-docs (pulls sanitised ontology + code-derived schema/mcp/api-routes via sync-source-docs) | Internal KB site, not customer docs (Warp precedent does NOT apply — §0.2.1). Moves WITH the recon-valuable spaces it renders; deploy behind Vercel Deployment Protection (CONFIRMED enabled — §0.2.2a). The 6 docs workflows + 6 docs skills + run-skill.ts/docubot move with it. |
Ephemeral vs durable, made explicit (per brief):
- Ephemeral (retire/prune):
.planning/codebase/(retire now);docs/continuation-prompts/(prune after a session window); mostdocs/audits/+docs/operations/point-in-time reports (archive then prune). - Durable-but-private (move, keep):
.planning/.archive/,docs/themes/,docs/research/,docs/workflow-evaluation/,docs/handover-guides/. - Durable + published (stay in code repo, surface on site):
docs/reference/**,docs/runbooks/**,docs/ontology/**,docs/generated/**,docs/design/**, ratifieddocs/specs/**.
Net effect of this routing: the lockstep-mutated set that crosses the boundary is ~empty (ledgers, specs, ontology, freshness docs, generated artefacts all stay) → the “unavoidable structural cost” (double-commit / split-brain) is collapsed to the rare session that also edits moved private corpus. This is the §D1 verdict applied.
D3 — Retire (not relocate) documentation-inventory.md + doc-freshness.test.ts
Section titled “D3 — Retire (not relocate) documentation-inventory.md + doc-freshness.test.ts”These are two independent artefacts the brief bundles. doc-freshness.test.ts does
not read documentation-inventory.md at all (confirmed — it reads
data-entry-points.md, classification-architecture.md,
runbooks/taxonomy-change-runbook.md). Treat them separately.
D3.1 documentation-inventory.md — retire; the Starlight sidebar IS the inventory
Section titled “D3.1 documentation-inventory.md — retire; the Starlight sidebar IS the inventory”What supersedes it. docs-site/astro.config.mjs:126-147 defines the sidebar as five
autogenerated spaces — autogenerate: { directory: 'product-functionality' | 'ontology' | 'reference' | 'runbooks' | 'decisions' }. Starlight rebuilds this nav from the content tree
on every build — a live, always-current index with zero hand-maintenance. Plus Pagefind
full-text search (PRODUCT Inv-8) over every published page. The hand-maintained
documentation-inventory.md carries a write-coupling tax: keep-docs-in-sync/SKILL.md
(:157-159) mandates “add an entry to documentation-inventory.md in the same commit” on
every new doc — drift-prone and strictly inferior to an autogenerated nav. Retire.
Every consumer to repoint/remove on retirement (load-bearing subset; the remaining hits are cosmetic spec/ledger/continuation-prompt mentions):
| Consumer | How it uses the inventory | Action |
|---|---|---|
.claude/skills/keep-docs-in-sync/SKILL.md:142-159 | ”consult before authoring; add an entry in the same commit” — the write-coupling | Remove the consult + same-commit-append rule; replace with “the autogenerated sidebar is the index.” |
.github/actions/docubot/prompt.txt:39-41 | ”Inventory check: before drafting a NEW doc, consult documentation-inventory.md” | Replace with “search the live site / Pagefind for an existing page.” |
__tests__/skills/keep-docs-in-sync-shape.test.ts:18 | Names the inventory in the skill-shape contract | Update the shape contract when the skill rule is removed (this guard test runs on every bun run test — will fail if the SKILL.md changes without it). |
CLAUDE.md:136 | ”Full inventory of all reference docs: documentation-inventory.md” | Repoint to the docs-site URL / sidebar. |
docs/reference/skill-routing-map.md | Reference mention | Repoint or drop. |
The S299 §1.4 note (“docubot reads
documentation-inventory.md”) is theprompt.txt:39consumer above — confirmed and enumerated.
D3.2 doc-freshness.test.ts — retiring it loses a real guarantee the site does not provide
Section titled “D3.2 doc-freshness.test.ts — retiring it loses a real guarantee the site does not provide”What it currently guards (__tests__/validation/doc-freshness.test.ts): for three docs,
it asserts the code paths they cite still exist on disk and that key source files contain
expected symbols:
data-entry-points.md— 10 known entry-point files exist + are referenced; and a code scan that anyapp/api/lib/mcp/toolsfile inserting intocontent_itemsis documented (an allow-listed completeness check).classification-architecture.md—lib/ai/classify.tscontainsclassifyContent;classify.py/layer_inference.pyexist; File-Reference-table paths exist.runbooks/taxonomy-change-runbook.md— referencessync:taxonomy; the 3 generator scripts- Scripts/Generated-artefacts table paths exist.
What the docs-site build provides (docs-site/package.json:9): check-broken-links
(internal doc↔doc links + external HTTP — check-broken-links.ts:1-18), check-token-parity
(the 6-token Warm-Meridian CSS mirror, app globals.css ↔ docs-site warm-meridian.css),
astro check (Astro components + TS types). None of these validate a doc→code-path
reference. Pagefind/sidebar index pages; they do not check that
scripts/kb_pipeline/pipeline.py cited in a doc still exists.
What is genuinely lost on retirement: the only guard that catches a reference/runbook doc
citing a deleted/renamed source file, plus the content_items-INSERT completeness scan.
This is fundamentally a code-repo concern (it needs the code tree), so it cannot move to
the docs repo without a cross-repo code checkout.
Replacement guard — recommended (small): because the three guarded docs stay in the
code repo under §D2, keep a slimmed code-repo guard that retains only the
path-existence assertions (doc cites X → X exists on disk) and drops anything coupled
to documentation-inventory.md framing. Net: retire the name and the inventory-adjacent
parts; preserve ~40 lines of path-existence + the content_items completeness scan as a
lean reference-doc-paths.test.ts. If Liam prefers full retirement, the loss is bounded
(3 low-churn docs; drift caught at review) — but it is a real loss, not a no-op. Do not
relocate it to the docs repo (no code tree there). See OQ-R8.
D4 — Ontology sync/drift: today’s mechanism + the split-survival delta
Section titled “D4 — Ontology sync/drift: today’s mechanism + the split-survival delta”Brownfield correction (Liam, mid-session): ontology sync is not green-field. It was designed and partially implemented as the WP6 Markdown Ontology Harness (S236–S238, branch
content-items-investigation). D4 is therefore reframed as (1) what the mechanism is today and (2) what must change to survive the split — not a from-scratch design. Sources mined:docs/specs/wp6-ontology-harness/TECH.md(the harness spec, last verified 14/05/2026),verifier-reports/B1-md-vs-db-drift.md,investigations/INV-{1,2,3}-*.md; traced to ID-9; mempalace consulted (the WP6 wave trail is documented in TECH.md’s footer, which is the authoritative history).
D4.1 What the ontology sync/drift mechanism IS today (it does NOT mirror taxonomy-sync)
Section titled “D4.1 What the ontology sync/drift mechanism IS today (it does NOT mirror taxonomy-sync)”The harness already exists and is wired end-to-end. Its shape (TECH.md §3 architecture
diagram):
docs/ontology/*.md (32 CV register files; frontmatter Zod-contracted) │ ├── build-time path (predev + prebuild) ──▶ scripts/generate-content-type-values.ts │ └─▶ lib/ontology/content-type-values.generated.ts (frozen tuple, client-safe) │ └─▶ content-type-registry.ts ─▶ lib/validation/schemas.ts VALID_CONTENT_TYPES │ ├── server/test path ──▶ lib/ontology/loader.ts (sync fs read, Zod-validates all 32 at load) │ └─▶ __tests__/lib/ontology/markdown-parity.test.ts │ (asserts: markdown ↔ generated tuple ↔ live DB CHECK — 3-way lockstep) │ └── future automated markdown→DB sync ──▶ scripts/ontology-sync/parse-flow.py (STUB, not run)| Concern | How it works today | File / citation |
|---|---|---|
| Source of truth | The markdown register docs/ontology/*.md is the “single source-of-truth artefact” (TECH.md §1). The live DB CHECK is its lockstep partner, not its source. | TECH.md §1, lib/ontology/schemas.ts (OntologyCVSchema.strict()) |
| Codegen (compensation A) | generate-content-type-values.ts reads 04-content-type.md → writes the frozen TS tuple. Wired predev/prebuild/build:vercel → regenerated on every build (S237 codegen split 13f30993 resolved a Turbopack node:fs client-bundle leak). | scripts/generate-content-type-values.ts, package.json:12-13,59, TECH.md §5.3 |
| Drift guard (compensation B) | markdown-parity.test.ts asserts 3-way set-equality (markdown register ↔ generated tuple ↔ live DB CHECK via taxonomy_snapshot.json). Any of the three drifting fails CI (bun run test). | __tests__/lib/ontology/{markdown,form-type}-parity.test.ts, TECH.md §5.4,§5.3.6 |
| DB-side oracle | The parity test reads scripts/tests/fixtures/taxonomy_snapshot.json content_types[] — which is refreshed by bun run sync:taxonomy. So ontology’s DB oracle piggybacks on taxonomy-sync’s snapshot regen. | TECH.md §4, scripts/generate-taxonomy-snapshot.ts:76-114 |
| Future markdown→DB auto-sync | parse-flow.py is a typed cocoindex stub, deliberately NOT executed (needs a DB target table + migration, deferred to land with application_types, Q-OQR1-16). | scripts/ontology-sync/parse-flow.py, TECH.md §5.5,§2 |
| Why the guard is load-bearing | The B1 verifier found the hand-authored register drifted hard from the live DB on first authoring: 17/29 CVs needed changes, 1 CRITICAL (CV03 layer-vocabulary baseline values were entirely invented). The parity test is the compensating control for exactly this. | verifier-reports/B1-md-vs-db-drift.md §1 |
Does it mirror taxonomy-sync? No — and it does not need to. The two have inverted sources of truth, which dictates opposite mechanisms:
taxonomy-sync.yml | ontology harness (today) | |
|---|---|---|
| Source of truth | DB (taxonomy/layer tables) | Markdown register (docs/ontology/*.md) |
| Mechanism | regenerate-and-commit: repository_dispatch → bun run sync:taxonomy regenerates DB-derived artefacts → commit + push main → HMAC callback | regenerate-at-build + fail-on-drift: build-time codegen (every build) + parity test (every CI run) |
| Direction | DB → repo artefacts (push) | markdown → TS tuple (codegen); DB is a validated peer, not a sink |
| Needs a workflow? | Yes (DB mutations happen outside git, so a workflow must pull them into the repo) | No — the register is edited in git, so the codegen + test already see every change at build/CI time |
Because taxonomy’s source (the DB) mutates outside git, it needs a workflow to pull
changes back into the repo. Ontology’s source (the markdown) mutates inside git, so there
is nothing to “sync back” — the codegen + parity test already compensate drift on every
build/CI run. The honest finding: ontology already has an appropriate drift-compensation
mechanism; it is a detect-and-block guard, not an auto-commit workflow, and that is correct
for its inverted source-of-truth. The true taxonomy-sync analogue (a markdown→DB push)
is the deferred cocoindex flow (parse-flow.py), not anything missing from the sync layer.
D4.2 What must CHANGE for it to survive the docs/code split (the delta)
Section titled “D4.2 What must CHANGE for it to survive the docs/code split (the delta)”The harness has one load-bearing cross-boundary dependency: docs/ontology/*.md is read
by three code-repo consumers — the build-time codegen (generate-content-type-values.ts,
on the prebuild/predev critical path), the runtime/test loader (loader.ts), and the
future cocoindex flow (parse-flow.py, which localfs.walk_dirs docs/ontology/). If the
register moves to the docs repo under S299’s blanket “move everything out”:
bun build/bun dev/build:vercelbreak — the codegen’sreadFile(SOURCE)dangles. This is a build-coupling S299 missed, and it is worse than the docs-site../docsdangle S299 did catch, because it sits on the app’s critical build path, not a separate docs build. Same class assync-manifest.json:"source_root":"../docs".markdown-parity.test.ts+loader.tsbreak —bun run testcan no longer find the register; the 3-way drift guard goes dark.- The future cocoindex flow would need a cross-repo source root before it can ever run.
The split-survival delta is therefore one routing decision, not new tooling: the ontology
CV register is simultaneously a code build input, a code test fixture, and (future) a
code-side cocoindex source with a live-DB lockstep contract. It is not pure-published
prose. → docs/ontology/ STAYS in the code repo (sanitised), routed exactly like the
ledgers and active specs in §D2. With that single decision:
- The entire harness (codegen + loader + parity test + the deferred cocoindex flow) keeps working unchanged — every consumer and its source stay in the code repo.
- No new workflow is required for split-survival. The existing build-codegen + parity-test mechanism is already split-immune once the register stays put.
- No docs→code reverse bridge, no cross-repo token is introduced (the rejected alternative — moving the register out — would create the system’s only docs→code sync direction and still leave the prebuild codegen needing a cross-repo source; strictly more fragile, zero benefit).
Ratified enhancement (S301, OQ-R11): add an ontology-sync.yml that runs the codegen +
parity on push to docs/ontology/**, catching register drift at edit time rather than on
the next unrelated build/CI run. This is not required for split-survival (the parity test
already runs on every bun run test in CI) but Liam adopted it as an edit-time early-warning.
The same ruling adds docs/ontology/** to the code→docs publish pull set (§D4.3).
D4.3 Ontology-derived content reaching the docs-site (after the split)
Section titled “D4.3 Ontology-derived content reaching the docs-site (after the split)”The docs-site already publishes an ontology space (sync-manifest.json:6,
astro.config.mjs:131-134) by syncing ../docs/ontology. With the register staying in the
code repo, the published view reaches the docs-site (in the docs repo) through the same
code→docs bridge S299 §3 already specifies for sync-source-docs’s generated surfaces
(schema-quick-reference/mcp-inventory/api-routes): the docs-site build cross-checks-out
the code repo and pulls docs/ontology/**. Specify (amended OQ-R12 S-B): the docs-site
now lives in knowledge-hub-internal; its build pulls sanitised docs/ontology/** (the
one public-safe build-input space that stays) plus the code-derived schema/mcp-inventory/
api-routes surfaces from the public code repo via sync-source-docs + the R4 GitHub App. The
canonical ontology register never leaves the public code repo; its rendered form is published
on the gated internal site. (Under S-B, reference/generated themselves move private, so
they are local to the docs-site, not cross-repo-pulled.) Asymmetry holds for the staying
build-inputs: canonical-in-code, surfaced-on-the-gated-site.
§6′ — Open Questions (all ratified/closed, S301 02/06/2026)
Section titled “§6′ — Open Questions (all ratified/closed, S301 02/06/2026)”Status legend: RATIFIED (Liam adopted the disposition) · RATIFIED-IN-PRINCIPLE (adopted; implementation detail deferred) · RESOLVED (dissolved by another ruling). All 12 are closed.
| OQ | Status (S301) | Ratified disposition |
|---|---|---|
OQ-R1 — sibling-checkout + KH_DOCS_DIR vs loop-from-docs-repo | RATIFIED-IN-PRINCIPLE | Sibling-checkout + KH_DOCS_DIR adopted; precise env-threading deferred to implementation. Scope is small because build inputs (ledgers/specs/ontology) stay in the code repo under §D2. |
| OQ-R2 — cross-repo auth: PAT vs GitHub App | RATIFIED-IN-PRINCIPLE | GitHub App adopted for cross-repo auth (the code→docs publish bridge + the R4 code→ledger evaluator write-back share this one App token); detail deferred to implementation. |
OQ-R3 — bun run test ownership of the 4 ledger roundtrip guards + doc-freshness.test.ts | RESOLVED (by R10) | Ledgers stay in the code repo → the 4 roundtrip guards stay put (no move). doc-freshness.test.ts retires, replaced by the slim reference-doc-paths.test.ts (R8). Nothing relocates to the docs repo. |
OQ-R4 — evaluation-lane relocation + product-retros.json home | RATIFIED | product-retros.json stays in the code repo with the other 3 ledgers. The workflow-evaluation/ corpus + evaluate-* skills relocate to the docs repo and become a code→ledger cross-repo writer, using the same GitHub App token as the docs bridge (R2). No longer needs Liam. |
| OQ-R5 — double-commit acceptance | RESOLVED (by R10) | Dissolved. Under §D2 the lockstep-mutated set stays in the code repo, so a typical session produces only a code commit; double-commit occurs only when a session also edits moved private corpus (rare). |
OQ-R6 — docs/runbooks/ mirrored back for on-call | RESOLVED (by R10) | Moot — runbooks stay in the code repo (build/CI-cited). No mirroring needed. |
| OQ-R7 — ontology CV register home | RATIFIED | docs/ontology/** stays in the code repo — it is the WP6 harness’s build input + test fixture + future cocoindex source with a live-DB lockstep contract. Moving it out breaks bun build AND markdown-parity.test.ts; the whole harness survives the split unchanged when it stays. |
OQ-R8 — doc-freshness replacement guard | RATIFIED | Retire doc-freshness.test.ts; keep a slim code-repo reference-doc-paths.test.ts carrying the path-existence assertions + the content_items-INSERT completeness scan. (§D3.2) |
| OQ-R9 — inventory write-coupling removal | RATIFIED | The autogenerated Starlight sidebar + Pagefind replace documentation-inventory.md; remove the “add an entry in the same commit” rule from keep-docs-in-sync/SKILL.md + docubot/prompt.txt + update keep-docs-in-sync-shape.test.ts. (§D3.1) |
| OQ-R10 — the routing principle (the load-bearing decision) | RATIFIED | Partitioned routing adopted, amending the S294 blanket override: build inputs + lockstep-mutated SDLC state stay in the code repo (sanitised); only durable-private + ephemeral + pure-published-prose move out. The §D2 table is now policy. (§D1, §D2) |
OQ-R11 — ontology-sync.yml + publish surface | RATIFIED | Add ontology-sync.yml (codegen + parity on push to docs/ontology/**) for edit-time drift feedback, and add docs/ontology/** to the code→docs publish pull set so the rendered register stays on the docs-site. Both adopted (not optional). (§D4.2-D4.3) |
| OQ-R12 — docs-site + published-corpus sensitivity routing (security re-examination) | RATIFIED (Option S-B) | SENSITIVITY is a PRIMARY routing axis. docs-site (internal KB — Warp precedent does NOT apply) + reference, runbooks, specs→decisions render, product-functionality, generated → move to knowledge-hub-internal, GATED Vercel deployment. ontology STAYS (sanitised public-safe build input + cross-repo published); design STAYS (public-safe); ledgers + raw spec source STAY (sanitised-public — no ledger-write-path parameterisation). S299 §3 code→private-docs publish bridge re-added (security-justified) via the R4 GitHub App. Vercel Deployment Protection CONFIRMED enabled (present-tense exposure closed). Per-row §D2 amendments carry amended OQ-R12 (S301). Phased design: RELOCATION-IMPLEMENTATION-PLAN.md §0.2 + §1 (Option S-B). |
OQ-R10 was the load-bearing decision and it is ratified: the S294 blanket “move
everything out” override is amended to the partitioned §D2 routing. The lockstep-mutated
rows (ledgers, specs, ontology, freshness docs, generated artefacts) stay in the code repo
(sanitised) and publish to the site via the code→docs bridge, which collapses the
“unavoidable structural cost” to the rare session that also edits moved private corpus. The
companion build-breakage fixes the ruling requires are tracked in §D4.2 (ontology source) and
S299 §1.3 (docs-site ../docs co-relocation). Implementation (Phase-0 design) is deferred
to a separate go-ahead.
Sources
Section titled “Sources”Primary (this investigation):
- Warp blog — Open-sourcing our docs and the agents that maintain them,
https://www.warp.dev/blog/open-sourcing-our-docs-and-the-agents-that-maintain-them. - Local Warp code repo
/Users/liamj/Documents/development/Warp:.github/actions/docubot/action.yml:30(cross-repo checkout ofwarpdotdev/gitbook),.github/workflows/docubot_reply_to_comment.yml,.github/actions/docubot/prompt.txt,.github/workflows/repo-sync.yml(public↔private code mirror),.agents/skills/(20 engineering skills, no docs skills), top-levelspecs/(specs in code repo). - Mempalace (default-wing search;
wingfilter known-broken): prior KH research docdocs/research/docs-site-rebuild-research.md(S51, 716 lines) — Warp’s 6 docs skills atwarpdotdev/docs/.agents/skills/(24 total) + docubot 7-step composite action.
Ontology harness — prior work mined for D4 (brownfield):
docs/specs/wp6-ontology-harness/TECH.md(the WP6 Markdown Ontology Harness spec; §1 goals, §3 architecture, §5.3 codegen, §5.4 parity test, §5.5 cocoindex stub; S236–S238 wave trail in the footer is the authoritative history).docs/specs/wp6-ontology-harness/verifier-reports/B1-md-vs-db-drift.md(§1: 17/29 CVs drifted, 1 CRITICAL — the evidence the parity guard exists to catch).docs/specs/wp6-ontology-harness/investigations/INV-{1,2,3}-*.md; traced to ID-9.
KH codebase (verified this session):
scripts/generate-content-type-values.ts(ontology generator; sourcedocs/ontology/04-content-type.md),package.json:12-13,15,59(predev/prebuild/build:vercelwiring),__tests__/lib/ontology/{markdown,form-type}-parity.test.ts,lib/ontology/{loader,schemas,content-type-registry}.ts,scripts/ontology-sync/parse-flow.py(cocoindex stub, not executed)..github/workflows/taxonomy-sync.yml(the contrasting auto-commit model; ontology does NOT mirror it — §D4.1).docs-site/astro.config.mjs:126-147(autogenerated 5-space sidebar),docs-site/package.json:9,13-14,docs-site/scripts/check-broken-links.ts,docs-site/scripts/check-token-parity.ts,docs-site/sync-manifest.json.__tests__/validation/doc-freshness.test.ts,.claude/skills/keep-docs-in-sync/SKILL.md:142-159,.github/actions/docubot/prompt.txt:39-41,__tests__/skills/keep-docs-in-sync-shape.test.ts:18,CLAUDE.md:136.
Prior art (inherited from S299, unchanged): Passo.uno docs-as-code topologies (sidecar / orthogonal / federated / specialised); Antora multi-repo; withastro/starlight #2844, #956 (multi-repo not first-class); docusaurus #6086; Mintlify cross-repo checkout.