Skip to content

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_DENYLIST secret (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.md approved.
  • 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-setup HEAD 3e13d6ee (the branch moved twice during authoring — ea971fda3e13d6ee landed the Invariant 22 deletions live; see §Context).
  • Status: Draft, pending ratification before {68.4} PLAN revision.

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_DIR consumers anywhere outside docs/ prose at canonical HEAD (6 files match, all historical docs: continuation prompts, the ID-68 spec corpus, workflow-evaluation events.jsonl). Zero KH_PUBLIC_REPO_DIR and zero KH_PRIVATE_DOCS_DIR matches anywhere.
  • The Phase-0a knob commit (a7e087ee, re-picked as f81db588) never landed on canonicalf81db588 is an ancestor of id68-relocation-phase23 only. 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 only type-drift-baseline.json + type-drift-report.mdcodebase-stats.{md,json} and mcp-inventory.{md,json} were already deleted in 9b1e5aaf (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-stats job (ID-9.19) live at .github/workflows/ci.yml:1245, runs bun run stats + bun run generate:mcp-inventory on push to main; shape-guarded by __tests__/workflows/ci-regenerate-stats.test.ts (whole-file guard on that job).
  • type-drift-baseline.json consumers: 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 the type-drift-parity job), 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.json does not exist at canonical HEAD. It exists only on id68-relocation-phase23 (__tests__/fixtures/reference-doc-paths.json + __tests__/validation/reference-doc-paths.test.ts, commits fe071a00/e2bd1e8a — “{68.12} 0b — R8 reference-doc-paths.test.ts replaces doc-freshness”). PC-19 integrates it.
  • .knip-baseline.json at repo root (confirmed); bun run ci:knip-check at ci.yml:108. No LICENSE/LICENCE/COPYING file tracked (AC-A2 already true).
  • scripts/run-1m-context.ts + scripts/wf-export.py: deleted at 3e13d6ee (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:15PROMPT_PATHdocs/reference/classification-prompt.md (retires with kb_pipeline, Inv 33-C).
    • scripts/bundle-plugin.ts:174 — bundles classification-prompt.md into the MCP plugin.
    • scripts/generate-classification-prompt-taxonomy.ts:22,238 — codegen target.
    • scripts/cocoindex_pipeline/verify_driver.py:5,77,85 — reads docs/testing/test-data/** (Class 7; disposition owned by ID-80.2, Inv 16/42).
    • __tests__/validation/doc-freshness.test.ts — asserts docs/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 — reads docs/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-68 reads docs/reference/{task-list,product-roadmap,product-backlog}.json; plus task-list-schema/roadmap-schema/backlog-schema/umbrellas-roundtrip tests, lib/validation/* and scripts/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.md 23 refs, AGENTS.md 26 refs (incl. the knowingly stale docs-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-token already 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-*.ts at 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.ts counterparts; the sweep covers all 7.
  • 4 gold-standards at __tests__/fixtures/*-eval-gold-standard.json with identity-set density: classification 21 phew matches, 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-level eval-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.ts runs in default bun run test and 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:60EVAL_SUMMARISATION === '1'). Pre-existing filename discrepancy (Checker S317): scripts/eval-procurement-drafting.ts:306 hardcodes __tests__/fixtures/bid-drafting-eval-gold-standard.json, but the tracked artefact is procurement-drafting-eval-gold-standard.json (the name eval-fixture-sync.test.ts asserts) — 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 (seeded Phew Design Limited row — 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 migration 20260603121652_hook_restrict_signup_to_allowed_domain.sql exists at HEAD: additive-only, SET search_path at :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). Wider phew in scripts/tests/: 6 files (add test_workspace_resolver.py (18) and test_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 comment PHEW-DESIGN-1/3).
  • Test fixtures/mocks: ~25 __tests__/** files carry incidental phew mock values (e.g. __tests__/lib/entity-aliases.test.ts 35 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, and components/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 ZA123456 in __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 only catalogue-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 (../): commits f9c92ba2 + 1ad3e1cf verified; remote ai-solution-hub/knowledge-hub-docs-site; spaces present: decisions design handover-guides ontology product-functionality reference runbooks specs themes — note decisions/ 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 commit 08c51dd, 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.


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:

  1. Private homing: move summarisation-eval-gold-standard.json + procurement-drafting-eval-gold-standard.json to the docs-site repo at a stable tracked path (eval-fixtures/ at that repo’s root — survives the ID-9 root-move).
  2. Public name-swap: rewrite classification-eval-gold-standard.json (21 matches)
    • entity-eval-gold-standard.json (162) with placeholder org names (Example Client Ltd etc.) 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).
  3. Resolver (the indirection): new lib/eval/fixtures.ts exporting resolveEvalFixture(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.ts suites to the resolver.
  4. Guard rework (same change): __tests__/validation/eval-fixture-sync.test.ts asserts only the 2 public fixtures by default; the 2 private assertions run only when KH_PRIVATE_DOCS_DIR is set (keeps AC-C3 — default bun run test green with no knob).
  5. Parameterise the telehouse code literals in scripts/eval-holder-rule-ts.ts:568,911 (config/env-driven positive-control entity, per the existing NEXT_PUBLIC_CLIENT_ID pattern in that script). Both suites stay EVAL_*=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.

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-68 et 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:

  1. 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.yml type-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 + --ci parity green — this sub-slice is verify-only for the executor.) type-drift-report.md is Class 6: delete from docs/generated/; the CLI’s --ci regeneration (ast-dataflow-cli.ts:835-842) retargets a gitignored root .type-drift-report.mdratified (Liam, S317). docs/generated/ is then empty and removed (closes the Inv 21 remainder).
  2. reference-doc-paths.json integration: cherry-pick or re-author the id68-branch fe071a00/e2bd1e8a pair (path-manifest fixture + reference-doc-paths.test.ts replacing the three hard-coded doc-freshness targets) onto canonical, so the doc-pointer guard is manifest-driven before relocation flips the paths.
  3. 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_pipeline readers, 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.

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.ts exporting resolvePrivateDocsDir() — returns process.env.KH_PRIVATE_DOCS_DIR or 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.sh archive 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:

OptionMechanismTrade-off
E1 — repo secret (recommended)Multiline IDENTITY_DENYLIST Actions secret on the public repo; guard-CI greps the tree against itNo cross-repo dependency; secret invisible in logs (mask); rotation manual
E2 — private fetchGuard-CI mints an App token, reads the denylist file from the docs-site repoSingle 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) regeneratelib/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 scrubsnext.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 at lib/client-config.ts:580,586 so the bundle ships { default }) — NOT yet on canonical (verified). The deploy overlay = DEPLOY-OVERLAY-DESIGN Option 2 (codegen map): build prestep globs lib/branding/clients/*.jsonclient-branding-map.generated.ts; the client deploy overlays the private files + sets NEXT_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_pipeline retirement 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 and docs/reference/classification-prompt.md leaves 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.uk in: CLAUDE.md:94 (production-URL line → “per-deploy APP_URL; see .env.local”), the 3 scripts/tests/*.py webhook-URL files (fixture URLs → kh.example.org), __tests__/actions/docubot-prompt-shape.test.ts (2), and the docker-compose.production.yaml:69 comment (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):

  1. Backup (mandatory first): git clone --mirror → tag pre-id68-purge → store outside the repo tree; record location in the journal (AC-E5).
  2. Path inventory (--paths-from-file): generated at purge time from: all relocated docs/** paths; .planning/**; docs-site/**; the legacy AC2 set (client corpus/briefs/personas/feedback, the CSP under docs/testing/test-data/, scripts/catalogue-*-itt.ts historical 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).
  3. Redaction map (--replace-text): the PC-31 denylist rendered as literal→placeholder rules (phew.org.ukclient.example, Phew Design LimitedExample 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 (filename 20260424202806_capture_phew_domain_hook.sql via --path-rename; content via the map; replay-consistency check via a staging supabase db reset) is conditional on OQ-H/OQ-G(b).
  4. Execute on a fresh mirror, never in the working clone.
  5. Verification clone before force-push: --analyze report + git log --all -S<entry> per map entry + git rev-list --objects --all grep per path = zero (AC-E2); only then force-push, then every checkout re-clones (all SHAs change), supabase link re-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.

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>'), repoint supabase/config.toml:78 to hook_restrict_signup_to_allowed_domain (+ scrub the :72-73 comments), verify the signup gate; then live tenant — same GUC per-deploy, a new migration dropping hook_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), regenerate database.types.ts (the :4253 entry disappears; CI supabase-types-parity guards), update audit-opaque-json-rpcs.ts:354-360. DDL via CLI only; cat supabase/.temp/project-ref before any push (CLAUDE.md gotcha). The 20260419212103:48 seeded-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_pipeline retirement-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.

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).


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.


Governance Task: verification = recorded commands + artefacts; code-touching slices get behaviour tests (philosophy: docs/reference/test-philosophy.md).

ACVerification
AC-A1gh repo view <each> --json visibility triplet, recorded at flip
AC-A2git ls-files | grep -iE '^(LICENSE|LICENCE|COPYING)' empty + guard-CI assertion green
AC-A3git -C ../knowledge-hub-docs-site ls-files per-space row counts vs DOC-LIFECYCLE §4
AC-A4gitnexus/ccc queries for archive paths return zero from the main repo
AC-A5git ls-files zero for corpus paths; test-data inventory equals the 8-file OQ-2 list
AC-A6public 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–B4space ls vs Inv 10 set; ID-68 spec dir present post-close; no new docs/research/ files; archive spot-checks carry ledger refs
AC-C1git ls-files 'docs/**' zero (± the OQ-E subset if ratified in)
AC-C2floor-file presence list; CONTRIBUTING.md absent
AC-C3 / AC-D4fresh 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-C4deletion-set git ls-files zero; .type-drift-baseline.json at root; type-drift-parity CI job green post-move
AC-C5scripted link/path sweep over README/AGENTS/CLAUDE/.claude/** for removed docs/ paths = zero
AC-D1repo-wide grep -ri 'KH_DOCS_DIR' zero; KH_PRIVATE_DOCS_DIR consumer list equals the documented lanes
AC-D2grep -r 'KH_PUBLIC_REPO_DIR' matches only the relocated docubot lane (private repo)
AC-D3knob-unset invocation exits non-zero naming the knob (unit + smoke)
AC-E1public-clone git grep -i per identity-set entry: carve-out-only for phew, zero for telehouse
AC-E2post-purge verification-clone report: --analyze + -S per map entry + object-list grep per path, all zero, across all refs
AC-E3git ls-files zero for branding paths; overlay deploy renders client branding (PC-39(ii) acceptance 1–3 per DEPLOY-OVERLAY §6)
AC-E4migration list contains the generic hook migration; config.toml grep zero client-named hook; staging signup gate exercised
AC-E5pre-id68-purge mirror tag + location journal line exist before purge execution
AC-E6gh api …/branches/main/protection lists the guard check as required
AC-F1/F2gate-artefact checklist complete in the journal before {68.9}; ledger journal ordering audited by the Checker
AC-G1Checker 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).


  • Purge is one-way. Mirror backup first (AC-E5), verification clone before force-push, ordered last; full fleet re-clone + supabase link re-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.toml to 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.ts runs in default bun 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 reset as 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 / symbolPinned/installedCheckResult
git-filter-repo (--analyze, --invert-paths, --replace-text)2.47.0 (pip)python3 -m git_filter_repo --helpPRESENT (all three flags)
gh CLI (repo edit --visibility, api …/branches/main/protection, api …/dependabot/alerts)2.73.0gh --versionPRESENT
actions/create-github-app-token patternin-repo precedent.github/workflows/sync-source-docs.ymlPRESENT (proven cross-repo lane)
EVAL_* suite gatingin-repo__tests__/eval/summarisation-eval.test.ts:60PRESENT

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).