ID-68 — Repo visibility and IP separation: TECH
ID-68 — Repo visibility and IP separation: TECH (revised)
Section titled “ID-68 — Repo visibility and IP separation: TECH (revised)”{68.3} TECH artefact — REVISION authored against the ratified {68.2} PRODUCT
(S317). Supersedes the S291 TECH in full: that document carried its acceptance contract
inline (ID-54 precedent, now superseded — the contract lives in PRODUCT.md), and its
C6→C7 ordering (flip, then purge) is reversed by PRODUCT Invariant 36/Gate 5 (history
is clean before exposure). Mechanics from the legacy TECH that survive re-verification
are folded in below and marked; everything else is replaced.
- Task: ID-68 “Repo visibility and IP separation — private→public readiness”
- Status: RATIFIED (Liam, S317) — Checker PASS_WITH_NOTES (note applied);
the four flagged design calls ratified: PC-31 = E1 repo-secret, unified with the
existing
KH_CLIENT_NAME_DENYLISTsecret (superset content); PC-37 = paid org plan confirmed, required checks enforced pre-flip; PC-7 step 2 =eval-gold/relocation approved; PC-19 = gitignored root.type-drift-report.mdapproved. - Predecessors:
PRODUCT.md(RATIFIED S317, 05/06/2026 — THE acceptance contract);TARGET-STATE-ARCHITECTURE.md(canonical topology; §0.1 live migration state);DOC-LIFECYCLE-DESIGN.md(doc classes + 15-folder disposition);PRE-FLIP-DEID-PLAN.md({68.13}ratified — items A/B/C/E/F; §4 D3 routing subsumed). - Authored: 05/06/2026 (fresh Planner per Q-PLANNER-2). Grounding verified against
canonical-pipeline-setupHEAD3e13d6ee(the branch moved twice during authoring —ea971fda→3e13d6eelanded the Invariant 22 deletions live; see §Context). - Status: Draft, pending ratification before
{68.4}PLAN revision.
Context
Section titled “Context”What is being built
Section titled “What is being built”Repo-split mechanics for the corrected four-tier model (PRODUCT Inv 1): make
ai-solution-hub/knowledge-hub flip-safe by (1) finishing the public-repo minimal docs
floor + pointer rework, (2) standing up the single KH_PRIVATE_DOCS_DIR bridge, (3)
splitting the eval lane (code public, data split), (4) executing the Group E de-ID of
genuine client content, (5) designing the {68.10} history purge, and (6) finalising
cold storage. Behaviour and acceptance live in PRODUCT.md; this document maps one
proposed change per invariant (PC-1 … PC-42) and sequences them against the Invariant
38 gate table (which this document consumes, never re-derives).
This is a repo-governance Task: artefacts are tracked files, git history, CI workflows
and GitHub settings, not application symbols. Code-intelligence orientation: not
applicable — repo-governance/doc-lifecycle scope, no execution-flow symbols specified for
modification (per PRODUCT §Problem; the legacy TECH’s verified greenfield finding stands:
gitnexus orientation: no existing symbols match — greenfield surface). The handful of
code-touching slices (eval fixture resolver, branding codegen, type-drift path move)
name their exact consumer sites below; their Executors apply gitnexus/ast-dataflow
discipline per-symbol at execution time.
Grounding facts verified at HEAD 3e13d6ee (05/06/2026)
Section titled “Grounding facts verified at HEAD 3e13d6ee (05/06/2026)”All claims below were grep/read-verified against the main repo on
canonical-pipeline-setup. The branch is being actively committed to — re-verify any
fact you act on (that is also Gate 7’s whole purpose).
Bridge knob state (Group D):
- Zero
KH_DOCS_DIRconsumers anywhere outsidedocs/prose at canonical HEAD (6 files match, all historical docs: continuation prompts, the ID-68 spec corpus, workflow-evaluationevents.jsonl). ZeroKH_PUBLIC_REPO_DIRand zeroKH_PRIVATE_DOCS_DIRmatches anywhere. - The Phase-0a knob commit (
a7e087ee, re-picked asf81db588) never landed on canonical —f81db588is an ancestor ofid68-relocation-phase23only. Its consumer set there:.claude/skills/handoff/SKILL.md:17,.claude/skills/session-driver-cmux/scripts/stop-worker.sh:142,146-147,371,.claude/skills/start-session/SKILL.md:81-83,.claude/skills/workflow-orchestration/SKILL.md:397,CLAUDE.md:132,142,150(worktree-branch line numbers). Consequence: the Inv 25 “rename” is in practice name-at-birth on canonical plus a prohibition on cherry-picking the old-name commits (PC-25/PC-26).
Generated artefacts + CI floor (Group C):
docs/generated/at HEAD contains onlytype-drift-baseline.json+type-drift-report.md—codebase-stats.{md,json}andmcp-inventory.{md,json}were already deleted in9b1e5aaf(ahead of the PRODUCT Δ annotation).- Generator scripts still tracked:
scripts/generate-codebase-stats.ts,scripts/generate-mcp-inventory.ts;package.json:44("stats"),package.json:46("generate:mcp-inventory"). regenerate-statsjob (ID-9.19) live at.github/workflows/ci.yml:1245, runsbun run stats+bun run generate:mcp-inventoryon push to main; shape-guarded by__tests__/workflows/ci-regenerate-stats.test.ts(whole-file guard on that job).type-drift-baseline.jsonconsumers:lib/ast-dataflow/queries/type-drift-detect.ts:90(canonical read path),scripts/ast-dataflow-cli.ts:817,842,scripts/codemods/generate-response-schemas.ts:81,scripts/codemods/inference-source-a.ts:12,scripts/codemods/README.md:42,63,80,.github/workflows/ci.yml:874(comment in thetype-drift-parityjob), tests__tests__/lib/ast-dataflow/type-drift-detect.test.ts,__tests__/integration/ops-t1-codemod-verifier.integration.test.ts,__tests__/scripts/codemods/wrap-define-route.test.ts+ 2 fixtures.reference-doc-paths.jsondoes not exist at canonical HEAD. It exists only onid68-relocation-phase23(__tests__/fixtures/reference-doc-paths.json+__tests__/validation/reference-doc-paths.test.ts, commitsfe071a00/e2bd1e8a— “{68.12} 0b — R8 reference-doc-paths.test.ts replaces doc-freshness”). PC-19 integrates it..knip-baseline.jsonat repo root (confirmed);bun run ci:knip-checkatci.yml:108. NoLICENSE/LICENCE/COPYINGfile tracked (AC-A2 already true).scripts/run-1m-context.ts+scripts/wf-export.py: deleted at3e13d6ee(landed during this authoring) — Inv 22 is now verify-only..graphifyignore: already deleted (zero tracked or untracked matches) — Inv 5’s deletion clause is verify-only.- CLAUDE.md gitnexus block (
CLAUDE.md:268-310): no live counts (count-strip landed,9b1e5aaf).
Docs tree + pointer inventory (Groups B/C):
- All 15
docs/top-level folders still present at HEAD (audits, continuation-prompts, design, generated, handover-guides, ontology, operations, product-functionality, reference, research, runbooks, specs, testing, themes, workflow-evaluation) — matches DOC-LIFECYCLE §4’s disposition table unit-for-unit. - Runtime/code readers of
docs/paths (the Inv 19 pointer-rework floor — non-exhaustive; PC-40’s sweep finalises):scripts/kb_pipeline/config.py:15—PROMPT_PATH→docs/reference/classification-prompt.md(retires withkb_pipeline, Inv 33-C).scripts/bundle-plugin.ts:174— bundlesclassification-prompt.mdinto the MCP plugin.scripts/generate-classification-prompt-taxonomy.ts:22,238— codegen target.scripts/cocoindex_pipeline/verify_driver.py:5,77,85— readsdocs/testing/test-data/**(Class 7; disposition owned by ID-80.2, Inv 16/42).__tests__/validation/doc-freshness.test.ts— assertsdocs/reference/data-entry-points.md,docs/reference/classification-architecture.md,docs/runbooks/taxonomy-change-runbook.md.__tests__/lib/ontology/form-type-parity.test.ts:32— readsdocs/ontology/26-form-type.md(evidence for OQ-E: a test does read an ontology doc; OQ-E remains open — see PC-24).- Ledger readers:
__tests__/validation/ledger-schema-integrity.test.ts:51-68readsdocs/reference/{task-list,product-roadmap,product-backlog}.json; plustask-list-schema/roadmap-schema/backlog-schema/umbrellas-roundtriptests,lib/validation/*andscripts/backfill-capability-theme.ts:39-40— all ID-20 substrate territory (Gate 2 boundary).
- Harness-floor files referencing
docs/paths (AC-C5 sweep scope):CLAUDE.md23 refs,AGENTS.md26 refs (incl. the knowingly staledocs-site/src/content/block —AGENTS.md:7,41,72), ~78 files under.claude/**. - Docs operator surfaces still in the public repo at HEAD:
.github/workflows/{docubot,sync-source-docs,review-docs-pr,missing-docs,check-for-broken-links,docs-seo-audit}.yml,.github/actions/docubot/{action.yml,prompt.txt}, 6 docs skills under.claude/skills/,scripts/skills/run-skill.ts,scripts/docubot/run-agent.ts,__tests__/actions/docubot-prompt-shape.test.ts, dev-dep@anthropic-ai/claude-agent-sdk(package.json:135). Private copies of all six operator workflows already exist in the docs-site repo (knowledge-hub-docs-site/.github/workflows/verified). create-github-app-tokenalready in use at.github/workflows/sync-source-docs.yml— the proven cross-repo checkout pattern PC-28 generalises.
Eval lane (Inv 7):
- 7 files match
scripts/eval-*.tsat HEAD (classification, entity-classification, holder-rule-ts, procurement-drafting, search, summarisation, tag-morphology-adoption) — PRODUCT’s “5 runners” = the 5 with__tests__/eval/*-eval.test.tscounterparts; the sweep covers all 7. - 4 gold-standards at
__tests__/fixtures/*-eval-gold-standard.jsonwith identity-set density: classification 21phewmatches, entity 162, procurement-drafting 24, summarisation 43. Metric baselines at__tests__/fixtures/eval-baselines/*.json(4 files: classification, entity-classification, search, summarisation — note the path: not a top-leveleval-baselines/).scripts/search-evaluation.json+__tests__/fixtures/eval-baselines/search.baseline.json: zero identity matches. - Runners hardcode fixture paths (
scripts/eval-classification.ts:709,scripts/eval-summarisation.ts:429);__tests__/validation/eval-fixture-sync.test.tsruns in defaultbun run testand asserts existence + minimum item counts of all 4 gold-standards — it breaks the moment the 2 private fixtures move (PC-7 reworks it in the same change). Eval suites are env-gated (__tests__/eval/summarisation-eval.test.ts:60—EVAL_SUMMARISATION === '1'). Pre-existing filename discrepancy (Checker S317):scripts/eval-procurement-drafting.ts:306hardcodes__tests__/fixtures/bid-drafting-eval-gold-standard.json, but the tracked artefact isprocurement-drafting-eval-gold-standard.json(the nameeval-fixture-sync.test.tsasserts) — reconcile the canonical name when PC-7 step 3 repoints the runners to the resolver.
Identity set at HEAD (Group E; full git grep -ic 'phew' HEAD outside docs/):
- Branding:
lib/branding/clients/phew.json(tracked),public/clients/phew/*(5 assets),lib/client-config.ts:270,580,586(static import + map entry — the id68-branch removal commits are NOT on canonical; DEPLOY-OVERLAY-DESIGN §1’s “done” refers to that branch). - Auth hook:
supabase/config.toml:72-78(line 78 = the client-named hook URI);supabase/migrations/20260424202806_capture_phew_domain_hook.sql(6 matches, incl. the filename);supabase/migrations/20260419212103_…:48(seededPhew Design Limitedrow — OQ-G(b));supabase/migrations/20260428122626_user_profiles_mirror.sql:47,70(comments);supabase/types/database.types.ts:4253(generated hook type);scripts/audit-opaque-json-rpcs.ts:354,360(hook allowlist entry). The generic migration20260603121652_hook_restrict_signup_to_allowed_domain.sqlexists at HEAD: additive-only,SET search_pathat:29, fail-closed GUC read at:37, no DROP of the old function and no domain literal — confirming OQ-G(a)‘s cutover is still open. - Domain (
kh.phew.org.uk) outside docs/:CLAUDE.md:94,scripts/tests/test_cocoindex_flow_failure_mode.py(5),…_pipeline_run_webhook.py(3),…_app_main_retry_wiring.py(2),__tests__/actions/docubot-prompt-shape.test.ts(2). Widerphewinscripts/tests/: 6 files (addtest_workspace_resolver.py(18) andtest_docx_tracked_changes_regression.py(1)) — one more than PRODUCT Inv 40’s “5” (HEAD moved; sweep input updated). - Client-named scripts still tracked:
scripts/export-phew-articles.ts(4),scripts/seed-phew-guides.ts(3),scripts/split_phew_site_content.py(1). - Harness floor:
.claude/skills/run-knowledge-hub/SKILL.md:60,67(NEXT_PUBLIC_CLIENT_ID=phew, described as load-bearing);.env.example:14(slug example — carve-out candidate);next.config.ts:56(Sentry issue-id commentPHEW-DESIGN-1/3). - Test fixtures/mocks: ~25
__tests__/**files carry incidentalphewmock values (e.g.__tests__/lib/entity-aliases.test.ts35 matches,__tests__/setup.ts,__tests__/helpers/mock-supabase.ts) — PC-32 categorises. telehouse(case-insensitive) outside docs/:scripts/eval-holder-rule-ts.ts(15 — code literals at:568,911),scripts/propagate-cert-metadata.ts(10),scripts/kb_pipeline/eval_holder_rule.py(2),scripts/tests/test_eval_holder_rule.py(18),scripts/tests/test_classify_store_entities.py(6),lib/ai/skills/classification.md(4) +lib/ai/skills/inlined.generated.ts(1),__tests__/lib/ai/classify.test.ts(11),__tests__/api/certifications.test.ts(5),__tests__/mcp/certification-status-tool.test.ts(3), the 4 gold-standards, andcomponents/entity-management/entity-detail-panel.tsx:247(UI placeholder “e.g. Telehouse”) — materially wider than the single PRODUCT citation; PC-32/PC-33 carry the full set.- ICO number: placeholder’d at HEAD (only synthetic
ZA123456in__tests__/components/certification-summary-card.test.tsx) — history-purge item only. deploy/coolify/docker-compose.production.yaml:69— comment# Carry-over from cloudrun/services/staging-phew-cocoindex.yaml:45-71.(the ID-83 sweep item, verified).- One-shot ITT seeds: gone from HEAD (
scripts/catalogue-*now onlycatalogue-from-instance.ts+catalogue-standard-sq.ts, both generic) —{68.7}held; their historical paths stay in the purge set.
Sibling repos:
knowledge-hub-docs-site(../): commitsf9c92ba2+1ad3e1cfverified; remoteai-solution-hub/knowledge-hub-docs-site; spaces present:decisions design handover-guides ontology product-functionality reference runbooks specs themes— notedecisions/still scaffolded (OQ-D resolved S317: drop). The repo root still carries the old internal-repo harness (lib/,__tests__/,scripts/,package.json) including a stale copy of all 4 gold-standards — strip is ID-9 lineage (Inv 42), but the 2 private fixtures’ canonical home lands there first (PC-7).knowledge-hub-archive(../): initial commit08c51dd, no remote, currently holds.planning/.archive-lineage dirs only —docs/workflow-evaluation/+ continuation-prompt history not yet ingested (PC-13/PC-5 + migration plan Phase 4).
Terminology (unchanged from RESEARCH §11)
Section titled “Terminology (unchanged from RESEARCH §11)”AI Solution Hub = our organisation (public-safe). Phew / Phew Design Limited = the first client (the identity set). Knowledge Hub = the platform.
Proposed changes
Section titled “Proposed changes”One proposed change per PRODUCT invariant; PC-n ↔ Invariant n. “Verify + record” means the invariant is already satisfied at HEAD: the change is to run the named command at the relevant gate and record the artefact in the Subtask journal — no re-work.
Group A — topology and privacy boundaries
Section titled “Group A — topology and privacy boundaries”PC-1 (Inv 1 — four-tier topology). No standalone work item: the topology is the sum of PC-3/4/5/6/17/21/23. Verification at flip: the Inv 1 table’s four rows each have their gate artefact (AC-A1–A6).
PC-2 (Inv 2 — public ≠ open-source). Verify + record: no LICENSE/LICENCE/
COPYING tracked at HEAD (confirmed). Add a one-line assertion to the guard-CI
workflow (PC-37) failing on the appearance of an OSI licence file, so the invariant
holds post-flip without relying on review vigilance. AC-A2.
PC-3 (Inv 3 — docs-site is the single private docs home). Verify + record:
gh repo view ai-solution-hub/knowledge-hub-docs-site --json visibility = private.
Vercel gating is ID-9 lineage (Inv 42) — referenced, not owned.
PC-4 (Inv 4 — docs corpus git-tracked in the docs-site repo). Verify + record
(Δ executed S301a-8): git -C ../knowledge-hub-docs-site ls-files 'docs-site/src/content/docs/**' returns the corpus per space, not placeholders
(AC-A3). The pending docs-site→root move is ID-9’s (Inv 42); only the Inv 7
fixture-homing below touches that repo from this Task.
PC-5 (Inv 5 — archive indexed by nothing). .graphifyignore deletion: verify +
record (already absent at HEAD). Remaining mechanics: after Phase-4 archive ingest,
run gitnexus_query/ccc index-scope checks from the main repo and record zero
archive-path results (AC-A4); document the opt-in archive index as a runbook note
(point gitnexus/ccc at the archive checkout on demand — each tool indexes the path it
is pointed at, TARGET-STATE §3.4).
PC-6 (Inv 6 — client corpus never in git). Verify + record: git ls-files zero
rows for the legacy corpus paths (docs/client-documentation-corpus/,
docs/client-briefs/, docs/client-personas.md, docs/kh-client-feedback.md —
removed b6e35683); ID-69 external ingestion is shipped (boundary). The accepted
public-tender list = the 8 tracked files under docs/testing/test-data/templates/
(Charnwood ITT, EFA ITT, British Council RFP — OQ-2). AC-A5.
PC-7 (Inv 7 — eval lane split). The main code-touching slice:
- Private homing: move
summarisation-eval-gold-standard.json+procurement-drafting-eval-gold-standard.jsonto the docs-site repo at a stable tracked path (eval-fixtures/at that repo’s root — survives the ID-9 root-move). - Public name-swap: rewrite
classification-eval-gold-standard.json(21 matches)entity-eval-gold-standard.json(162) with placeholder org names (Example Client Ltdetc.) and de-telehouse them; relocate the swapped files to a new path__tests__/fixtures/eval-gold/so the new paths’ history begins at the clean blob — the legacy paths join the{68.10}purge set (this is what lets AC-E2 hold without enumerating bid prose in the redaction map). Ratified (Liam, S317).
- Resolver (the indirection): new
lib/eval/fixtures.tsexportingresolveEvalFixture(name): public names →__tests__/fixtures/eval-gold/…; private names (summarisation,procurement-drafting) →${KH_PRIVATE_DOCS_DIR}/eval-fixtures/…, throwing the Inv 29 actionable error when the knob is unset. No second knob, no per-space matrix — the private branch of the resolver is the one bridge consumer (Inv 25/27 honoured). Repoint the hardcoded paths in the 7 runners + 5__tests__/eval/*-eval.test.tssuites to the resolver. - Guard rework (same change):
__tests__/validation/eval-fixture-sync.test.tsasserts only the 2 public fixtures by default; the 2 private assertions run only whenKH_PRIVATE_DOCS_DIRis set (keeps AC-C3 — defaultbun run testgreen with no knob). - Parameterise the
telehousecode literals inscripts/eval-holder-rule-ts.ts:568,911(config/env-driven positive-control entity, per the existingNEXT_PUBLIC_CLIENT_IDpattern in that script). Both suites stayEVAL_*=1-gated out of PR CI (verified). AC-A6.
PC-8 (Inv 8 — cutover, not big-bang). Owned by the §Migration plan: every flip of a live mechanism (ledger writes → ID-20; doc reads → bridge; deploys → overlay) appears there strictly after its replacement’s integration + test evidence. No separate work item.
Group B — doc-class model
Section titled “Group B — doc-class model”PC-9 (Inv 9 — class-at-birth). Reference-only: the taxonomy is normative via DOC-LIFECYCLE §3/§4. ID-68’s enforcement surface is the relocation execution (PC-17) landing every folder per its class row. Producing-skill template updates beyond that are the workflow review’s (OQ-B/OQ-C — boundary).
PC-10 (Inv 10 — spaces = Class 1+2 only). At relocation cutover, the docs-site
space list must equal the Inv 10 set. Two deltas verified today: (a) the scaffolded
decisions/ space exists in the docs-site repo — drop it (OQ-D resolved S317:
ADR scaffold dropped; changelog adoption is workflow-review co-scope, not ID-68);
(b) no Class 3/4/5/6/7 space may be created during PC-17 routing. AC-B1.
PC-11 (Inv 11 — specs kept forever; docs/research/ dissolves). During PC-17:
route docs/specs/ (191 files) → docs-site specs/ (already copied — verify);
triage docs/research/ (16 files): any feeding live tasks stay until consumed, rest →
archive (DOC-LIFECYCLE §4); no new freestanding research lands (AC-B3 is a
convention assertion — spot-check at close, plus the spec-dir convention already in
CLAUDE.md §Spec directory).
PC-12 (Inv 12 — Class 3 never canonical). Interim-only mechanics: consolidate
cmux-briefs to one home (fix the stale handoff pointer + session-driver-cmux
example paths — TARGET-STATE §3.1); continuation prompts stay in place until the
workflow review designs the scripted model (OQ-B boundary). No site space, no archive
sweep designed here (OQ-C resolved → workflow review).
PC-13 (Inv 13 — Class 4 archives on decision-captured). Phase-4 mechanics: for each
Class-4 set (docs/audits/ 29 files, docs/workflow-evaluation/ 76,
docs/operations/ point-in-time subset, docs/testing/uat/), check a ledger reference
exists (grep docs/reference/tasks/ + retros for the doc’s slug), then git mv into
knowledge-hub-archive with provenance line in the archive commit. Docs lacking a
ledger reference surface to the Orchestrator rather than being archived silently.
AC-B4.
PC-14 (Inv 14 — ledgers private via ID-20). Boundary, not work: ledgers + mirrors
remain in docs/reference/ until the ID-20 patch-server cutover (Gate 2). The only
ID-68 mechanics: the relocation cutover (PC-17) explicitly EXCLUDES
docs/reference/{task-list,product-backlog,product-roadmap,product-retros,umbrellas}.json
docs/reference/{tasks,backlog,roadmap,retros}/mirrors from the public-deletion set until Gate 2 is recorded done; the ledger guard tests (ledger-schema-integrity.test.ts:51-68et al.) move/repoint as part of ID-20’s cutover, not this Task’s pointer rework.
PC-15 (Inv 15 — Class 6 never canonical). Delivered by PC-19 (baseline root-move) + PC-21 (deletion set). No separate item.
PC-16 (Inv 16 — Class 7 owned by ID-80.2). Boundary, with one recorded fact: the
canonical pipeline’s verify_driver.py:5,77,85 reads docs/testing/test-data/** at
runtime, so the Class-7 disposition cannot be executed by ID-68 without breaking the
verify lane — hand this citation to ID-80.2 and leave the 8 template files in place
(they are on the OQ-2 accepted-public list, so they do not block the flip).
Group C — public-repo minimal docs floor
Section titled “Group C — public-repo minimal docs floor”PC-17 (Inv 17 — floor rule execution). The relocation cutover (migration-plan
Phase 3): for each of the 15 docs/ folders, execute its DOC-LIFECYCLE §4 disposition
— Class 1/2 → verify docs-site copy current then git rm -r from public; Class 4 →
PC-13 archive flow; operations/+testing/ split rows per their table entries;
continuation-prompts/ stays (interim, Class 3); reference/ ledger subset held back
per PC-14. Pre-condition: bridge proven (PC-25 consumers green against the sibling
checkout) — Inv 23’s condition. AC-C1.
PC-18 (Inv 18 — harness floor). Verify + record the six floor surfaces exist and
contain no dangling docs/ references post-PC-17 (the AC-C5 sweep). One de-ID overlap
handled here: genericise .claude/skills/run-knowledge-hub/SKILL.md:60,67
(NEXT_PUBLIC_CLIENT_ID=phew → <client-id> example reading .env.local), since
.claude/** stays public.
PC-19 (Inv 19 — CI floor + pointer rework). Three slices:
- Baseline root-move:
git mv docs/generated/type-drift-baseline.json .type-drift-baseline.json; repoint the verified consumer list (Context above:type-drift-detect.ts:90,ast-dataflow-cli.ts:817,842,generate-response-schemas.ts:81,inference-source-a.ts, codemods README,ci.ymltype-drift-parity job, the 3 test files + 2 fixtures). (Δ S317: the baseline root-move LANDED on canonical mid-authoring —47be7899, Checker PASS_WITH_NOTES, scoped tests +--ciparity green — this sub-slice is verify-only for the executor.)type-drift-report.mdis Class 6: delete fromdocs/generated/; the CLI’s--ciregeneration (ast-dataflow-cli.ts:835-842) retargets a gitignored root.type-drift-report.md— ratified (Liam, S317).docs/generated/is then empty and removed (closes the Inv 21 remainder). reference-doc-paths.jsonintegration: cherry-pick or re-author the id68-branchfe071a00/e2bd1e8apair (path-manifest fixture +reference-doc-paths.test.tsreplacing the three hard-codeddoc-freshnesstargets) onto canonical, so the doc-pointer guard is manifest-driven before relocation flips the paths.- Pointer rework at cutover: the Context inventory + PC-40’s sweep output is the
work list; every entry is either (a) retargeted to
${KH_PRIVATE_DOCS_DIR}/…via the PC-25 resolver, (b) moved private with its consumer (operator workflows, PC-27), or (c) deleted with its feature (kb_pipelinereaders, PC-33-C). CLAUDE.md edits here coordinate with ID-9.21’s atomic edit — sequential commits, never interleaved (§Migration plan Phase 2/3 ordering). AC-C4, AC-C5.
PC-20 (Inv 20 — no CONTRIBUTING.md). Verify + record (absent at HEAD); add to the guard-CI assertion list alongside PC-2’s licence check.
PC-21 (Inv 21 — generated artefacts deleted; expanded set). Already landed
(9b1e5aaf): codebase-stats.{md,json}, mcp-inventory.{md,json}, .planning/,
count-strip — verify + record. Remaining, expanded per the S317 directive and
HARD-sequenced after ID-9.20 + ID-9.21 complete (or ID-9.21’s acceptance formally
amended): one atomic change deleting the regenerate-stats job (ci.yml:1245), its
shape guard __tests__/workflows/ci-regenerate-stats.test.ts, the generator scripts
scripts/generate-codebase-stats.ts + scripts/generate-mcp-inventory.ts, and
package.json:44,46 script entries (run bun run knip after — the deletions may
shift the knip baseline). Docs-site sync entries: n/a — the sync model was retired
(1ad3e1cf). The docs/generated/ dir removal itself rides PC-19 slice 1. AC-C4.
PC-22 (Inv 22 — scripts hygiene). Verify + record only: deletion landed at
3e13d6ee during this spec’s authoring. Historical paths join the purge set (PC-35).
PC-23 (Inv 23 — interim duplication ends). docs/specs/ + docs/themes/ deletion
from public is simply two rows of PC-17’s Phase-3 execution; their pre-condition
(bridge proven + ID-20 cutover) is encoded there. At flip: git ls-files 'docs/**'
zero rows (AC-C1).
PC-24 (Inv 24 — sanitised ontology subset, OQ-E conditional). Do not resolve OQ-E.
Mechanics for both branches, decided by the PC-40 sweep + ratification:
(a) subset stays public: keep exactly the code/test-read ontology docs (today’s
verified floor: docs/ontology/26-form-type.md, read by
form-type-parity.test.ts:32), sanitised per Group E, with the client-customisation
seam recorded as a forward design note (per PRE-FLIP §4 Ontology);
(b) no subset: repoint form-type-parity.test.ts at a TS-side fixture (the
baseline_values block extracted to __tests__/fixtures/) and the ontology space is
private-only. Either branch keeps AC-C1’s “sole permitted exception” wording exact.
Group D — private-docs bridge
Section titled “Group D — private-docs bridge”PC-25 (Inv 25 — the one knob). Introduce KH_PRIVATE_DOCS_DIR at birth on
canonical (no rename sweep needed — zero old-name consumers at HEAD, see Context):
- TS consumers:
lib/private-docs.tsexportingresolvePrivateDocsDir()— returnsprocess.env.KH_PRIVATE_DOCS_DIRor throws the Inv 29 error. Direct file imports only (no barrel). - Shell/skill consumers: the documented one-liner
"${KH_PRIVATE_DOCS_DIR:?KH_PRIVATE_DOCS_DIR not set — point it at the knowledge-hub-docs-site checkout (sibling clone locally; GitHub-App token checkout in CI)}". - The id68-branch knob commits (
a7e087ee/f81db588) are never cherry-picked; their consumer inventory (Context) is re-authored under the new name as those consumers’ surfaces land in Phase 3 (handoff/start-session/workflow-orchestration SKILL.md pointers,stop-worker.sharchive base, CLAUDE.md pointer lines). Read direction public→private only.
PC-26 (Inv 26 — rename completeness). Verify + record at cutover and at flip:
git grep -i 'KH_DOCS_DIR' -- ':!docs/' zero at HEAD today (recorded); after Phase 3
the docs/ prose carriers have moved private, making the AC-D1 repo-wide grep zero.
Add KH_DOCS_DIR (exact string, old name) to the guard-CI denylist so it cannot
return.
PC-27 (Inv 27 — routing matrix retired; docubot lane). KH_PUBLIC_REPO_DIR: zero
matches at HEAD (verified) — nothing to retire on canonical; the id68-branch
plans that used it are superseded paper. The docubot repoint (the sole surviving
lane): move the six operator workflows + .github/actions/docubot/ + the 6 docs
skills + scripts/skills/run-skill.ts + scripts/docubot/run-agent.ts +
__tests__/actions/docubot-prompt-shape.test.ts to the docs-site repo (private copies
of the workflows already exist there — reconcile, don’t duplicate). In the private
repo, docubot resolves the public code checkout via KH_PUBLIC_REPO_DIR, populated by
an App-token checkout step; trigger becomes repository_dispatch from a thin public
workflow on PR-merge (App token; pattern below). Public-side removal also drops the
now-unconsumed @anthropic-ai/claude-agent-sdk dev-dep (package.json:135) — or
knip-baselines it if removal churns the lockfile at a bad time. AC-D2.
PC-28 (Inv 28 — resolution model). Local/dev: the knob points at the sibling
checkout (../knowledge-hub-docs-site) — set explicitly (in .env.local /shell
profile), never auto-discovered, so consumers stay single-path. CI: a reusable step
mints an installation token via actions/create-github-app-token (proven in-repo at
sync-source-docs.yml), checks out knowledge-hub-docs-site into
${{ runner.temp }}/kh-private-docs, and exports KH_PRIVATE_DOCS_DIR. Consumers
never implement their own resolution — they read the env var via PC-25’s helpers only.
PC-29 (Inv 29 — fail loudly). Contract enforced in PC-25’s two helpers: exit
non-zero / throw with a message naming KH_PRIVATE_DOCS_DIR and both resolution
routes. Explicitly forbidden: falling back to in-repo docs/ (the stale public
duplicate) — this is the behavioural difference from the superseded Phase-0a knob,
whose precedence chain ended at in-repo docs/. Test: unit test for the TS helper +
one AC-D3 smoke (invoke a bridge consumer knob-unset; assert exit code + message).
PC-30 (Inv 30 — public self-sufficiency). Structural: no PR-blocking CI job sets
the knob (verified today: zero matches in .github/workflows/); bridge consumers are
opt-in lanes (eval private suite, docubot dispatch). AC-C3/AC-D4 verify it: full
bun run test + bun build + PR CI on a fresh public clone, no knob, no sibling.
Group E — de-identification of the public tier
Section titled “Group E — de-identification of the public tier”PC-31 (Inv 31 — identity set → machine-readable denylist). Materialise the Inv 31
table as the single shared input for guard-CI (PC-37), the HEAD sweep (PC-32), and the
purge redaction map (PC-35). Placement constraint: the denylist cannot live in the
public repo (a public denylist naming phew IS the leak). Two options:
| Option | Mechanism | Trade-off |
|---|---|---|
| E1 — repo secret (recommended) | Multiline IDENTITY_DENYLIST Actions secret on the public repo; guard-CI greps the tree against it | No cross-repo dependency; secret invisible in logs (mask); rotation manual |
| E2 — private fetch | Guard-CI mints an App token, reads the denylist file from the docs-site repo | Single canonical file; adds a cross-repo dependency to a required check (outage = red PRs) |
Recommend E1 with the canonical copy checked into the docs-site repo (private) and
the secret synced from it manually on change. Carve-out (parameterised-mechanism config
keys, generic placeholders, .env.example:14-style slug examples) is encoded as an
exclusion-pattern list alongside.
Ratified (Liam, S317): E1, UNIFIED with the existing secret. The repo already
carries KH_CLIENT_NAME_DENYLIST (provisioned 04/06/2026; sole consumer = the {68.13}
ledger write guard ledger-client-name-guard.yml + scripts/check-ledger-client-name.ts,
commit 245c35ac — id68-relocation-phase23 branch only, not yet on canonical). PC-31
WIDENS that one secret’s content to the full Inv 31 identity superset rather than
introducing a second IDENTITY_DENYLIST: both the ledger guard and the PC-37
identity-guard.yml consume it; one rotation point; canonical copy in the docs-site
repo. Accepted side-effect: the ledger guard now also rejects non-name identity strings
(e.g. telehouse) entering ledgers — desirable widening.
PC-32 (Inv 32 — clean public HEAD). The categorised sweep over the Context
inventory (and the PC-40 re-run output), per site: (a) parameterise — config/env
lookup (telehouse literals in eval-holder-rule-ts.ts, propagate-cert-metadata.ts,
positive-control entities in scripts/tests/test_eval_holder_rule.py /
test_classify_store_entities.py; NEXT_PUBLIC_CLIENT_ID=phew examples); (b)
synthetic-swap — mock values in the ~25 __tests__/** files +
scripts/tests/test_workspace_resolver.py (rename mock orgs/domains to
example-client.example; tests verify behaviour, not the literal —
docs/reference/test-philosophy.md); (c) delete — the 3 client-named scripts
(export-phew-articles.ts, seed-phew-guides.ts, split_phew_site_content.py:
one-shot historical, zero pipeline coupling — paths join the purge set); (d)
regenerate — lib/ai/skills/inlined.generated.ts after (a)/(b) hit
classification.md; supabase/types/database.types.ts:4253 after PC-39(i) drops the
old hook function; (e) carve-out — recorded against the PC-31 exclusion list
(.env.example:14; decide entity-detail-panel.tsx:247 “e.g. Telehouse” — recommend
swap to a generic placeholder anyway since AC-E1 targets zero); (f) comment scrubs
— next.config.ts:56, docker-compose.production.yaml:69,
user_profiles_mirror.sql:47,70, audit-opaque-json-rpcs.ts:354,360 (reworked with
PC-39(i)). Python/SQL sites need plain grep sweeps — ast-dataflow is TS-only
(.ast-dataflow/CLAUDE.md). AC-E1.
PC-33 (Inv 33 — itemised closures, per PRE-FLIP).
- A (branding): integrate-or-reauthor the id68-branch untracking
(
git rm lib/branding/clients/phew.json public/clients/phew/*; drop the static import + map entry atlib/client-config.ts:580,586so the bundle ships{ default }) — NOT yet on canonical (verified). The deploy overlay = DEPLOY-OVERLAY-DESIGN Option 2 (codegen map): build prestep globslib/branding/clients/*.json→client-branding-map.generated.ts; the client deploy overlays the private files + setsNEXT_PUBLIC_CLIENT_ID(live-tenant item — PC-39(ii)). AC-E3. - B (auth hook): the generic migration exists at HEAD (verified, no domain literal, fail-closed). Remaining = PC-39(i) live cutover.
- C (classification prompt): decision mechanics — confirm
kb_pipelineretirement timing (ID-66 carry); if retirement precedes flip, the three consumers (config.py:15,bundle-plugin.ts:174,generate-classification-prompt-taxonomy.ts) delete with it anddocs/reference/classification-prompt.mdleaves with PC-17; if the flip must come first, relocate the file private and repoint the bundle/codegen via the PC-25 knob (bridge-dependent opt-in lane — plugin bundling is not PR CI). Live-tenant tracked item — PC-39(iii). - Eval data: delivered by PC-7 (name-swap + relocation + private homing + telehouse parameterisation).
- F (domain): genericise
kh.phew.org.ukin:CLAUDE.md:94(production-URL line → “per-deployAPP_URL; see.env.local”), the 3scripts/tests/*.pywebhook-URL files (fixture URLs →kh.example.org),__tests__/actions/docubot-prompt-shape.test.ts(2), and thedocker-compose.production.yaml:69comment (with PC-32(f)). The real domain becomes per-deploy config (APP_URL) — a non-issue publicly. AC-E1.
PC-34 (Inv 34 — session-start domain awareness). Record APP_URL=https://… in the
gitignored .env.local; add one line to .claude/skills/start-session/SKILL.md
surfacing it at session start (“current live domain: grep '^APP_URL' .env.local”).
No public reference; survives client-domain changes as deploy config.
PC-35 (Inv 35 — history purge {68.10} design). Tool verified: git-filter-repo
2.47.0 installed (pip; invoke python3 -m git_filter_repo), --analyze /
--invert-paths / --replace-text all present (§Verification). Procedure (runs LAST,
explicit Liam GO):
- Backup (mandatory first):
git clone --mirror→ tagpre-id68-purge→ store outside the repo tree; record location in the journal (AC-E5). - Path inventory (
--paths-from-file): generated at purge time from: all relocateddocs/**paths;.planning/**;docs-site/**; the legacy AC2 set (client corpus/briefs/personas/feedback, the CSP underdocs/testing/test-data/,scripts/catalogue-*-itt.tshistorical paths);lib/branding/clients/phew.json+public/clients/phew/**; the 3 deleted client-named scripts;scripts/run-1m-context.ts+scripts/wf-export.py; the 4 legacy gold-standard paths (their replacements live at the PC-7 paths with clean first blobs). - Redaction map (
--replace-text): the PC-31 denylist rendered as literal→placeholder rules (phew.org.uk→client.example,Phew Design Limited→Example Client Ltd,support@phew.org.uk,kh.phew.org.uk,telehouse→generic, the historical ICO number, the old hook name). Final map contents = OQ-H (open, Liam) — including whether HEAD-scrub-only is acceptable for low-sensitivity strings; this PC supplies the draft map, not the ratified one. Migration-file treatment (filename20260424202806_capture_phew_domain_hook.sqlvia--path-rename; content via the map; replay-consistency check via a stagingsupabase db reset) is conditional on OQ-H/OQ-G(b). - Execute on a fresh mirror, never in the working clone.
- Verification clone before force-push:
--analyzereport +git log --all -S<entry>per map entry +git rev-list --objects --allgrep per path = zero (AC-E2); only then force-push, then every checkout re-clones (all SHAs change),supabase linkre-verified, gitnexus/ccc re-indexed, worktrees recreated. Leave a filter-repo runbook in the private docs (runbooks/space) — carried from the legacy TECH’s follow-up.
PC-36 (Inv 36 — clean-before-exposure). Sequencing assertion, not a work item: the
purge (PC-35) + its verification clone complete before {68.9} executes — the
reverse of the legacy TECH’s C6→C7 order (supersession recorded in the header). The
flip checklist’s first line re-runs the AC-E2 verification against the post-purge
remote across all refs (--all includes tags; delete or rewrite stale refs that
fail it).
PC-37 (Inv 37 — re-introduction guards). New public-repo workflow
identity-guard.yml (name final at implementation): on pull_request + push,
case-insensitive git grep -E of the full tree (not the diff — catches
re-introduction via any path) against the PC-31 secret-held denylist, minus the
carve-out exclusions; plus the PC-2 licence-file and PC-20 CONTRIBUTING.md and PC-26
KH_DOCS_DIR assertions. Register as a required status check via
gh api repos/{owner}/{repo}/branches/main/protection (AC-E6). Ratified (Liam,
S317): the org IS on a paid plan — required-check enforcement is applied during the
private phase (Phase 0), full rehearsal of the public posture; no advisory window.
(The advisory-until-flip fallback is retired; the §Risks entry narrows accordingly.) The ledger client-name write
guard ports into the ID-20 substrate — boundary (Inv 42), referenced here only.
Group F — flip-readiness gates
Section titled “Group F — flip-readiness gates”PC-38 (Inv 38 — the gate table is the contract). No re-derivation. Mechanics =
the verification artefact per row, recorded in the {68.9} Subtask journal before
execution: Gate 1 → AC-A3 + AC-C1 commands; Gate 2 → ID-20 cutover journal reference;
Gate 3 → AC-E1 grep set + AC-E2 clone report; Gate 4 → AC-E6 API read of required
checks; Gate 5 → PC-35 artefacts (backup tag + verification report); Gate 6 → AC-A4
index checks; Gate 7 → PC-40 sweep report citing the HEAD SHA it ran against; Gate 8 →
gh api repos/ai-solution-hub/knowledge-hub/dependabot/alerts --jq '[.[]|select(.security_advisory.severity=="high" and .state=="open")]|length' = 0;
Gate 9 → Liam GO journal line. AC-F1/AC-F2.
PC-39 (Inv 39 — the 3 live-tenant subtasks). PLAN opens these as tracked ID-68 subtasks; TECH mechanics:
- (i) Signup-hook cutover (OQ-G(a)): on staging — set the GUC
(
ALTER DATABASE postgres SET app.allowed_signup_domain = '<domain>'), repointsupabase/config.toml:78tohook_restrict_signup_to_allowed_domain(+ scrub the:72-73comments), verify the signup gate; then live tenant — same GUC per-deploy, a new migration droppinghook_restrict_signup_to_phew_domain(append-only discipline;SET search_path+ anon-REVOKE rules per CLAUDE.md apply to any new function, none expected here), regeneratedatabase.types.ts(the:4253entry disappears; CIsupabase-types-parityguards), updateaudit-opaque-json-rpcs.ts:354-360. DDL via CLI only;cat supabase/.temp/project-refbefore any push (CLAUDE.md gotcha). The20260419212103:48seeded-row disposition stays open (OQ-G(b)) — supersede-migration vs accept-as-data + history redaction. - (ii) Branding overlay: implement DEPLOY-OVERLAY Option 2 (codegen map prestep + private overlay files sourced from the docs-site repo + deploy-step copy) and wire it into the client deploy before PC-33-A’s removal reaches a deployed build; AC-E3’s “deployed site still branded” is its acceptance.
- (iii)
kb_pipelineretirement-or-relocation: execute whichever PC-33-C branch the retirement-timing check selects; the flip gates on one of the two.
PC-40 (Inv 40 — relocation sweep re-run). A scripted, repeatable sweep (so Gate 7
can cite the exact HEAD SHA): (1) identity grep — the PC-31 denylist over the full
tree; (2) docs-pointer grep — git grep -nE '\bdocs/' -- lib/ app/ scripts/ components/ contexts/ hooks/ __tests__/ .github/ .claude/ CLAUDE.md AGENTS.md categorised
runtime-read vs prose; (3) plain-grep extension over Python/SQL (ast-dataflow is
TS-only); (4) explicit ID-83 coverage — the POST /walk route + compose files
(docker-compose.production.yaml:69 verified carrying the comment), the
onprem-deploy workflow, the rewritten runbook + scheduled-task doc (both relocate
private with PC-17 regardless), and the now-6 scripts/tests/*.py identity carriers
(PRODUCT said 5; HEAD moved — test_workspace_resolver.py (18 matches) +
test_docx_tracked_changes_regression.py (1) join the set). Output: a report feeding
the Group E set + the PC-19 pointer list; it also answers OQ-E’s “does any code/test
read ontology docs” with today’s known floor (form-type-parity.test.ts:32) as the
seed.
Group G — negative scope
Section titled “Group G — negative scope”PC-41 (Inv 41 — collapsed workstreams stay collapsed). Enforced editorially: this
TECH contains no third-docs-repo, no routing matrix, no private-docs de-ID, no ledger
sanitisation, no internal-repo harness build-out, and no KH_PUBLIC_REPO_DIR use
beyond the PC-27 docubot lane. {68.4} PLAN inherits the same checklist; the Checker
verifies AC-G1 against both documents.
PC-42 (Inv 42 — boundaries as dependencies). Expressed throughout as references: ID-20 (PC-14, PC-37 guard port, Gate 2), ID-69 (PC-6), ID-80.2 (PC-16), workflow review (PC-9/12/13 deferrals + OQ-D changelog adoption), ID-9 lineage (PC-3/4 site standup, harness strip), ID-9.19/9.20/9.21 (PC-21 sequencing). PLAN encodes these as Task-level dependencies, never as ID-68 Subtasks (sibling-only rule).
Migration plan
Section titled “Migration plan”Ordered phases; the Inv 38 gate table governs. Reversible work front-loads; the two Liam-GO actions close. Within a phase, items are parallelisable unless noted.
Phase 0 — immediately dispatchable (no external gates):
verify+record set (PC-2/5/6/20/22, PC-21-landed slice); guard-CI standup as a
required check from day one (PC-31/37 — paid plan ratified S317, no advisory mode;
early, so every later phase is leak-guarded); bridge helper introduction
(PC-25/29 + AC-D3 test); eval-lane split (PC-7) + eval-fixture-sync rework; HEAD
de-ID sweeps (PC-32, PC-33-A integrate-or-reauthor, PC-33-F, PC-34, PC-18 skill
genericise); PC-19 slices 1–2 (baseline root-move + reference-doc-paths integration);
sweep tooling (PC-40 script, first run recorded).
Phase 1 — live-tenant items (Liam-gated, staging-first): PC-39(i) staging → live hook cutover; PC-39(ii) overlay built + wired; PC-39(iii) retirement-timing decision executed. These may overlap Phase 0 but each needs explicit Liam sign-off before its live half.
Phase 2 — ID-9 sequencing window: wait for ID-9.20 + ID-9.21 done (or amended); then PC-21’s expanded deletion (regenerate-stats job + guard test + generators + package.json) as one atomic change. CLAUDE.md: ID-9.21’s atomic edit lands first; PC-19 slice-3 CLAUDE.md edits follow in a separate commit — never interleaved.
Phase 3 — relocation cutover (gated on: bridge proven via Phase-0 consumers green
against the sibling checkout; ID-20 cutover done for the ledger subset): PC-17
folder-by-folder execution (incl. PC-10 space-list check + decisions/ drop, PC-11
research triage, PC-23 specs/themes deletion); PC-19 slice-3 pointer rework + AC-C5
floor sweep; PC-27 operator repoint + public-side removal; PC-12 cmux-brief
consolidation. Exit check: AC-C1 + AC-C3 on a fresh clone, knob unset.
Phase 4 — cold-storage finalisation: PC-13 Class-4 archive flow
(workflow-evaluation, audits, operations/testing point-in-time sets); optional private
GitHub remote for knowledge-hub-archive; PC-5 index verification (AC-A4).
Phase 5 — pre-flip assembly: PC-40 sweep re-run against the then-current HEAD (Gate 7); Dependabot live re-check (Gate 8); PC-38 gate-artefact checklist completed; guard-CI flipped to required if the plan tier allows pre-flip (else at flip).
Phase 6 — irreversible tail (explicit Liam GO at each step): PC-35 purge (backup →
mirror rewrite → verification clone → force-push → fleet re-clone/re-index) → PC-36
all-refs re-verification → {68.9} flip (gh repo edit --visibility public) →
required-check + security-suite enablement (Dependabot updates, CodeQL, secret
scanning + push protection — scanning now runs over the already-cleaned history,
resolving the legacy TECH’s ordering concern) → AC-A1/F2 closure records.
Testing and validation
Section titled “Testing and validation”Governance Task: verification = recorded commands + artefacts; code-touching slices get
behaviour tests (philosophy: docs/reference/test-philosophy.md).
| AC | Verification |
|---|---|
| AC-A1 | gh repo view <each> --json visibility triplet, recorded at flip |
| AC-A2 | git ls-files | grep -iE '^(LICENSE|LICENCE|COPYING)' empty + guard-CI assertion green |
| AC-A3 | git -C ../knowledge-hub-docs-site ls-files per-space row counts vs DOC-LIFECYCLE §4 |
| AC-A4 | gitnexus/ccc queries for archive paths return zero from the main repo |
| AC-A5 | git ls-files zero for corpus paths; test-data inventory equals the 8-file OQ-2 list |
| AC-A6 | public clone holds the 2 swapped fixtures at the PC-7 paths, zero rows for the 2 private ones; docs-site repo eval-fixtures/ holds them |
| AC-B1–B4 | space ls vs Inv 10 set; ID-68 spec dir present post-close; no new docs/research/ files; archive spot-checks carry ledger refs |
| AC-C1 | git ls-files 'docs/**' zero (± the OQ-E subset if ratified in) |
| AC-C2 | floor-file presence list; CONTRIBUTING.md absent |
| AC-C3 / AC-D4 | fresh public clone, knob unset: bun run test, bun build, PR CI green (the PC-7 guard rework is what makes the default suite knob-independent) |
| AC-C4 | deletion-set git ls-files zero; .type-drift-baseline.json at root; type-drift-parity CI job green post-move |
| AC-C5 | scripted link/path sweep over README/AGENTS/CLAUDE/.claude/** for removed docs/ paths = zero |
| AC-D1 | repo-wide grep -ri 'KH_DOCS_DIR' zero; KH_PRIVATE_DOCS_DIR consumer list equals the documented lanes |
| AC-D2 | grep -r 'KH_PUBLIC_REPO_DIR' matches only the relocated docubot lane (private repo) |
| AC-D3 | knob-unset invocation exits non-zero naming the knob (unit + smoke) |
| AC-E1 | public-clone git grep -i per identity-set entry: carve-out-only for phew, zero for telehouse |
| AC-E2 | post-purge verification-clone report: --analyze + -S per map entry + object-list grep per path, all zero, across all refs |
| AC-E3 | git ls-files zero for branding paths; overlay deploy renders client branding (PC-39(ii) acceptance 1–3 per DEPLOY-OVERLAY §6) |
| AC-E4 | migration list contains the generic hook migration; config.toml grep zero client-named hook; staging signup gate exercised |
| AC-E5 | pre-id68-purge mirror tag + location journal line exist before purge execution |
| AC-E6 | gh api …/branches/main/protection lists the guard check as required |
| AC-F1/F2 | gate-artefact checklist complete in the journal before {68.9}; ledger journal ordering audited by the Checker |
| AC-G1 | Checker reads TECH+PLAN against the Inv 41 table and the Inv 42 boundary list |
Code-slice tests: PC-7 resolver (unit: public path, private path with knob, throw
without); PC-33-A codegen map (DEPLOY-OVERLAY §6 regression guard: build green with no
overlay resolves default); PC-19 path moves (existing type-drift + codemod suites
re-run green); PC-32 scrubbed scripts (python3 -m pytest scripts/tests/ +
bun run test green post-swap).
Risks and mitigations
Section titled “Risks and mitigations”- Purge is one-way. Mirror backup first (AC-E5), verification clone before
force-push, ordered last; full fleet re-clone +
supabase linkre-verify + index rebuild scripted in the runbook. All open branches/PRs and SHA citations in private ledgers break — accepted (private historical record), noted in the runbook. - Live auth cutover (PC-39(i)). Staging-verified first; fail-closed GUC design
already in the migration; rollback = repoint
config.tomlto the old function name (which is only dropped in the final live migration step). - Branding loss on client deploy. PC-33-A’s public removal must not reach a deployed build before PC-39(ii)‘s overlay exists — encoded as a named dependency, and the DEPLOY-OVERLAY §6 no-overlay regression guard keeps the public build green.
- Default test suite breaks at fixture move.
eval-fixture-sync.test.tsruns in defaultbun run test— its rework ships in the same commit as the fixture move (PC-7 step 4), else every CI run reds. - Guard-CI required-check tier limitation — RETIRED (ratified S317). The org is on a paid plan; required checks enforce from Phase 0. Residual risk only if the plan lapses pre-flip — Gate 4’s AC-E6 API read re-verifies at flip regardless.
- HEAD drift during the long middle. Canonical moved twice during this authoring alone; every Phase-5 artefact must cite the SHA it ran against, and Gate 7 exists precisely to re-base the analysis.
- ID-9.21 / PC-19 CLAUDE.md collision. Same-file edits sequenced as separate commits per the S317 directive; the PLAN must not schedule them into one wave.
- Secret-scanning retro-scan. Enabled post-purge (Phase 6 ordering), so it scans cleaned history; legacy TECH’s verification (no live credentials in tracked files) stands but is re-checked by the PC-40 sweep.
- Migration redaction vs replay. Rewriting applied migration files (names/content)
risks replay divergence; gated on OQ-H/OQ-G(b) ratification with a staging
supabase db resetas the proof, per PC-35 step 3.
Out of scope (mirrors PRODUCT Group G — do not implement here)
Section titled “Out of scope (mirrors PRODUCT Group G — do not implement here)”Per Inv 41: no third docs repo; no per-space routing matrix; no de-ID of
reference/runbooks/product-functionality/specs (private, never public); no ledger
sanitisation-for-public; no internal-repo harness build-out (the docs-site repo’s
harness strip is ID-9’s); no KH_PUBLIC_REPO_DIR beyond the docubot lane.
Per Inv 42 (referenced as dependencies only): ID-20 patch-server substrate + ledger
guard port + cutover (Gate 2); ID-69 external ingestion; ID-80.2 test-data disposition
(holding the verify_driver.py citation); the workflow review (Class-3 scripted model,
Class-4 sweep mechanics, OQ-D changelog adoption); the Warp WARP.md/CLAUDE.md
comparison; ID-9 docs-site IA/build standup (root move, Vercel repoint, harness strip);
ID-9.20/9.21 docubot decommission gates (PC-21 sequences against them).
Open questions NOT resolved by this TECH (per PRODUCT §Open questions discipline): OQ-E (ontology subset — PC-24 carries both branches; PC-40 supplies the evidence), OQ-G(b) (seeded-row disposition — PC-39(i) notes it), OQ-H (redaction-map contents — PC-35 supplies a draft only), OQ-A/OQ-B (boundaries).
Verification (pre-ratification empirical checks)
Section titled “Verification (pre-ratification empirical checks)”Per the Q-EX2 forcing function — external tools this spec’s mechanics depend on, checked 05/06/2026 against the local environment:
| Tool / symbol | Pinned/installed | Check | Result |
|---|---|---|---|
git-filter-repo (--analyze, --invert-paths, --replace-text) | 2.47.0 (pip) | python3 -m git_filter_repo --help | PRESENT (all three flags) |
gh CLI (repo edit --visibility, api …/branches/main/protection, api …/dependabot/alerts) | 2.73.0 | gh --version | PRESENT |
actions/create-github-app-token pattern | in-repo precedent | .github/workflows/sync-source-docs.yml | PRESENT (proven cross-repo lane) |
EVAL_* suite gating | in-repo | __tests__/eval/summarisation-eval.test.ts:60 | PRESENT |
No third-party library APIs are cited beyond these CLI surfaces; internal symbols are
grounded by the file:line citations in §Context (all verified at HEAD 3e13d6ee).