ID-68 Subtask {68.11} — Relocate dev-internal docs/ + .planning/ IP to a private docs repo before the public flip
ID-68 Subtask {68.11} — Relocate dev-internal docs/ + .planning/ IP to a private docs repo before the public flip
Section titled “ID-68 Subtask {68.11} — Relocate dev-internal docs/ + .planning/ IP to a private docs repo before the public flip”Type: TM-shape subtask spec (planning artefact only — NO move executed here). Parent: Task ID-68 (repo visibility / IP separation). Proposed id:
{68.11}(sits between{68.8}confirm-clean and{68.9}public flip). Authored: S293 (01/06/2026), read-only investigation. Worktree branched fromcanonical-pipeline-setup. Status: DRAFT — pending Liam ratification of the topology + split recommendation.
Context
Section titled “Context”The knowledge-hub repo is being flipped PRIVATE→PUBLIC under ID-68 ({68.9} flip,
{68.10} git filter-repo history purge). Two large dev-team-internal trees are
git-TRACKED, not gitignored and would become world-readable on the flip:
git check-ignore docs→ (nothing);git check-ignore .planning→ (nothing). Only/docs/database/is ignored (root.gitignore:112).docs/≈ 28 MB across 15 subdirs (largest:specs/6.2M,reference/6.0M,workflow-evaluation/3.9M,themes/3.5M,continuation-prompts/2.1M)..planning/= 36 MB, 1,269 files (RESEARCH §5.1), two parts:.planning/codebase/(7 live, cited architecture docs) +.planning/.archive/(~1,260 historical files concentrating process IP + client-name leaks).
Corroboration this is internal-only: .github/workflows/onprem-deploy.yml:89 explicitly
prunes docs/ + .planning/ from the cocoindex build context, commented “client IP”.
The ID-68 RESEARCH already lists .planning/** as an §3.12 hard constraint that must be
“excluded or relocated before any public flip” (§4.227), and docs/ client docs likewise
(§4.50–51).
Decision (Liam): move dev-internal docs/ + .planning/ OUT into a SEPARATE PRIVATE
repo (proposed knowledge-hub-docs-site) BEFORE {68.9}. This subtask specs that move
cleanly, accounting for the in-repo SDLC workflow that mutates ledgers/specs constantly and
the ID-9 Astro docs-site that builds FROM docs/.
This supersedes the PLAN’s AC9 / OQ-68-1-R2 deferral (“.planning/ untouched”). PLAN
§“Architecture decisions” line 24 said .planning/ was deferred pending a live docs-site;
Liam has now elected to relocate rather than defer. Record the AC9 override in the parent
TECH acceptance contract when this lands.
Investigation findings (load-bearing — these constrain the design)
Section titled “Investigation findings (load-bearing — these constrain the design)”F1 — ID-9 docs-site builds FROM docs/ via a relative source root (docs-site/ is in-repo)
Section titled “F1 — ID-9 docs-site builds FROM docs/ via a relative source root (docs-site/ is in-repo)”docs-site/is an Astro+Starlight project sibling to the app, deployed as a separate Vercel projectknowledge-hub-docs(ID-9 TECH §2.2).- Content is synced, not authored in place:
docs-site/sync-manifest.jsonhas"source_root": "../docs"and maps five spaces (product-functionality,ontology,reference,runbooks,specs→decisionsratified-only) plusadditional_source_dirs.reference = [design, generated]. The sync runs at build time:docs-site/package.jsonbuild=bun run sync && check-broken-links && check-token-parity && astro check && astro build;sync=bun scripts/sync-content.ts(docs-site/scripts/sync-content.ts, orchestrator; pure helpers insync-content-lib.ts). - The manifest
source_root: "../docs"is the single hard coupling. Ifdocs/moves anddocs-site/stays, the relative../docsdangles → build fails atwalk(spaceRoot)(sync-content.ts:106, “Fail loudly on missing source”). - The manifest already deny-lists the four ledger JSON + their MD mirrors + the
reference/{tasks,roadmap,backlog}/per-record dirs (sync-manifest.jsondeny_list). So the docs-site never publishes the ledgers today — confirming ledgers are NOT doc-site content; they are workflow state that happens to live underdocs/reference/. - ID-9 TECH §2.1 rationale: “Mirrors Warp’s separation (their docs are a sibling repo; KH
co-locates because the corpus is repo-internal).” That co-location premise inverts
the moment the repo goes public — the corpus must now leave the public repo. The
docs-site (which Liam also deems dev-internal) is the natural thing to co-locate WITH the
relocated
docs/in the new private repo.
F2 — Reference-count of dangling docs/ + .planning/ paths (tracked files, outside those trees)
Section titled “F2 — Reference-count of dangling docs/ + .planning/ paths (tracked files, outside those trees)”git grep -lF (with :(exclude) pathspecs for docs/**, .planning/**, node_modules,
dist, lockfiles):
- 715 tracked files reference
docs/(702) or.planning/(34) — 21 overlap. - By extension: 406
.ts, 98.md, 61.py, 54.sql, 49.tsx, 13.yml, 8.yaml, 5.sh, 5.js, 4.json, 2.mjs, plus.gitignore(2),.prettierignore,.gcloudignore,.toml,.css,.svg,.example,.worktreeinclude. - Caveat — most are NON-load-bearing. The bulk of the 406
.ts+ 54.sqlhits are doc-path mentions in code comments / spec-slice citations (Spec: docs/...), not runtime path resolution. The operationally load-bearing subset — things that read/write a realdocs/path or gate CI on one — is small and enumerated in F3–F5. The rewrite job is “repoint the load-bearing few + accept the comment-mentions dangle or batch-rewrite them cosmetically,” NOT “rewrite 715 files.”
F3 — Code/tests that RESOLVE real docs/reference/*.json ledger paths (the high-friction class)
Section titled “F3 — Code/tests that RESOLVE real docs/reference/*.json ledger paths (the high-friction class)”These break (or write to the wrong place) if docs/reference/ moves:
- Roundtrip guard tests (run on every
vitest):__tests__/docs/backlog-schema-roundtrip.test.ts(BACKLOG_PATH = join(PROJECT_ROOT, 'docs/reference/product-backlog.json')),retro-ledger-roundtrip.test.ts,roadmap-roundtrip.test.ts,umbrellas-task-list-roundtrip.test.ts(readFileSync('docs/reference/task-list.json')). - Ledger CLI + scripts hard-coding the paths:
scripts/ledger-cli.ts,scripts/ledger-normalise-oqls2.ts:36-38,scripts/ledger-sweep-s269.ts:38,scripts/backfill-capability-theme.ts:39-40,scripts/roadmap-from-json.ts,scripts/detect-roadmap-shipped-framings.ts:54,scripts/regen-mirrors.sh:77-79(task-view--check),lib/validation/ledger-budgets.ts:89(DISCIPLINE_DOC = 'docs/reference/task-list-discipline.md'). - SDLC skills that READ/WRITE these constantly:
write-product-spec,write-tech-spec(resolveNfromdocs/reference/task-list.json; writedocs/specs/ID-N-.../),spec-driven-implementation,workflow-orchestration,start-session,implement-subtask(append<info added>to task-list.json details),update-roadmap-backlog, the evaluate-* skills (readproduct-retros.json).
Implication: the ledgers + specs are written by the orchestration loop on essentially every session. A submodule-with-separate-commits or a moved-out path would impose a second commit/push on every ledger mutation — unacceptable friction. The ledgers and active specs must stay in the main repo.
F4 — Docs-automation that targets the docs CORPUS (mostly docs-site, not docs/)
Section titled “F4 — Docs-automation that targets the docs CORPUS (mostly docs-site, not docs/)”- docubot (
.github/workflows/docubot.yml,.github/actions/docubot/{action.yml,prompt.txt},scripts/docubot/run-agent.ts): writes DIRECTLY todocs-site/src/content/docs/<space>/<file>.md(ID-9 TECH §2.4 Inv-30 direct-write path). It does not writedocs/. It consultsdocs/reference/documentation-inventory.md(prompt.txt) to avoid recreating existing docs → that one read repoints with the inventory. - 5 ported docs skills +
keep-docs-in-sync(scripts/skills/run-skill.ts):check-for-broken-links(--root docs-site/src/content/docs),missing-docs/audit_docs.py(--root <repo-root> --docs-root <dir>, targets the content tree + surface map),docs-seo-audit/audit_seo.py,review-docs-pr,sync-source-docs.sync-source-docsis the one that bridges code→docs-site: it writesdocs-site/src/content/docs/reference/{schema-quick-reference,mcp-inventory, api-routes}.mdfromsupabase/types,lib/mcp/,app/api/**. Its spec citations point atdocs/specs/id-9-.../. These skills operate ondocs-site/, so if docs-site moves WITHdocs/, they move too and keep working; if docs-site stays, they keep working but their spec-citation comments dangle (cosmetic).
F5 — Config / CI / tooling that name docs/ or .planning/ (the exact load-bearing list)
Section titled “F5 — Config / CI / tooling that name docs/ or .planning/ (the exact load-bearing list)”| File | Reference | Action on move |
|---|---|---|
.gcloudignore:18-19 | docs/, .planning/ excludes | Harmless if dirs gone; leave or trim. |
.github/workflows/onprem-deploy.yml:89 | prunes docs/,.planning/ “client IP” | Harmless if gone; update comment. |
.prettierignore:39,42,57 | .planning/, docs/, docs/reference/classification-prompt.md | Keep for whatever stays (ledgers/specs). |
knip.config.ts:56-57 | docs/**, .planning/** ignore globs | Keep for staying subset; trim moved globs. |
tsconfig.json:46 | excludes docs-site (NOT docs/) | Only changes if docs-site moves. |
__tests__/validation/doc-freshness.test.ts | reads docs/reference/data-entry-points.md, classification-architecture.md, docs/runbooks/taxonomy-change-runbook.md via PROJECT_ROOT | These runbook/reference MDs must STAY or the test repoints. |
CLAUDE.md (root) + .ast-dataflow/CLAUDE.md | dozens of docs/... + .planning/codebase/ pointers (ledgers, runbooks, design, codebase map) | Repoint the moved pointers; keep the staying ones. |
| GitNexus + ccc indexes | both index .planning/ (RESEARCH §5.2; ~2,574 + index) | Removing .planning/.archive/ shrinks recall — accept, or keep .planning/codebase/. |
.worktreeinclude does NOT reference docs/.planning (only .env.local) — no change.
Recommendation
Section titled “Recommendation”R-Topology: Plain separate private repo + SPLIT (NOT submodule, NOT subtree)
Section titled “R-Topology: Plain separate private repo + SPLIT (NOT submodule, NOT subtree)”Create private repo knowledge-hub-docs-site and move into it the truly-internal,
rarely-mutated-by-the-loop trees. Keep in the main repo the workflow-mutated ledgers
and active specs (content-sanitised in place, not relocated). The new repo houses BOTH the
relocated source content AND the docs-site/ Astro project, so the build’s ../docs
coupling (F1) stays intact inside one repo.
Why not submodule / subtree:
- Submodule: every ledger/spec write (F3 — multiple per session) would require a second
commit in the submodule + a pointer-bump commit in the parent. The SDLC loop mutates
task-list.jsonon essentially every subtask. Submodule friction on the ledger write path is the dominant cost and rules it out. - Subtree: avoids the pointer-bump but
git subtree push/pullis error-prone for a high-churn directory and still splits history awkwardly; no real gain over a plain repo once the SPLIT removes the high-churn paths from the moved set. - Plain separate repo: lowest friction. The main repo retains only the things the loop writes; the moved trees are low-churn (archives, themes, evaluation runs, historical specs).
R-Split: what MOVES vs what STAYS
Section titled “R-Split: what MOVES vs what STAYS”MOVES to knowledge-hub-docs-site (private):
docs-site/(the Astro project itself — Liam deems it dev-internal; moving it keeps the../docssource coupling in one repo).docs/dev-internal corpus:themes/,workflow-evaluation/,continuation-prompts/,audits/,handover-guides/,research/,operations/,product-functionality/,ontology/,design/,generated/,testing/(note:testing/test-data/templates/holds the CSP file{68.5}already removes — coordinate so it isn’t double-handled)..planning/.archive/(the ~1,260-file historical IP store — RESEARCH §5 R4 “archive externally”). This is the single biggest IP + client-name concentration.
STAYS in knowledge-hub (content-sanitised in place, NOT relocated):
docs/reference/*.jsonledgers (task-list,product-backlog,product-roadmap,product-retros) + their MD mirrors +reference/{tasks,roadmap,backlog}/— written by the loop (F3). Sanitise client identifiers in place (already largely done at HEAD per PLAN §17).docs/specs/active spec dirs (ID-N-.../) — written by spec-driven skills (F3). These are architecture decisions, low client-IP risk; sanitise rather than move.docs/runbooks/+ the specificdocs/reference/*.mdthatdoc-freshness.test.tsand CLAUDE.md assert on (data-entry-points, classification-architecture, documentation-inventory, task-list-discipline, ai-visibility-policy, the{68.10}filter-repo runbook PLAN §85 leaves here). These are operational and loop-adjacent; keep + sanitise..planning/codebase/(7 live architecture docs cited by CLAUDE.md + write-tech-spec — RESEARCH §5.1; removing them degrades agent grounding immediately).
This split removes ~95% of the IP surface and ALL client-name-concentrated history
(.planning/.archive/) from the public repo while leaving the high-churn ledger/spec write
path untouched.
Docs-site source after the split: in the new repo, sync-manifest.json source_root
stays "../docs" ONLY IF the staying reference//runbooks//specs content is also
mirrored/available to it. Two sub-options:
- (a) Recommended: the docs-site syncs the STAYING reference/runbooks/specs from the
PUBLIC repo via a read-only checkout (CI step
git clone --depth 1 knowledge-hubinto a sibling dir, pointsource_rootat it) PLUS the movedproduct-functionality/ontology/design/generatedfrom its own repo. Manifest becomes multi-root. - (b) Simpler interim: copy the five published spaces into the new repo and let the public repo keep its own canonical copies; accept duplication of the published-only reference/runbook MDs (the ledgers were never published anyway). Lower engineering, mild drift risk — acceptable since docubot/sync-source-docs already manage drift. Recommend (b) for the first move, (a) as a follow-up if drift becomes painful.
R-Automation: reference-rewrite plan (concrete commands)
Section titled “R-Automation: reference-rewrite plan (concrete commands)”The move splits cleanly by file type. ast-dataflow does NOT cover Python or SQL (per
.ast-dataflow/CLAUDE.md), so combine tools:
- TS string-literal path refs (load-bearing resolution sites) — ast-dataflow CLI:
Cross-check against F3’s enumerated list. For any that resolve a MOVED path, repoint.bun scripts/ast-dataflow-cli.ts string-literal-uses "docs/reference/task-list.json"bun scripts/ast-dataflow-cli.ts string-literal-uses "docs/reference/product-backlog.json"bun scripts/ast-dataflow-cli.ts string-literal-uses "docs/" # broad sweep, triage
- TS symbol/import graph (does any module import a moved TS helper under docs-site?) —
GitNexus:
mcp__gitnexus__impact({target:"syncContent", direction:"upstream"})andmcp__gitnexus__query({query:"docs-site sync content build"})to confirm docs-site has no inbound app/lib import edges (it is a separate package — expect none). .md/.py/.yml/.yaml/.json/.shrefs (NOT covered by ast-dataflow) — plain grep sweep, triage load-bearing vs cosmetic:Python load-bearing sites to check:git grep -nF 'docs/' -- '*.py' '*.yml' '*.yaml' '*.sh' '*.json' ':(exclude)docs/**'git grep -nF '.planning/' -- . ':(exclude).planning/**' ':(exclude)docs/**'audit_docs.py,check_links.py,audit_seo.py(these take--root/--docs-rootargs — verify defaults, repoint if they default to a moved path).- Config files — hand-edit the F5 table list (
.gcloudignore,onprem-deploy.ymlcomment,.prettierignore,knip.config.ts,tsconfig.jsononly if docs-site moves, CLAUDE.md ×2). These are few and exact. - Verification: after rewrite,
bun run test(catches the four roundtrip guards +doc-freshness.test.ts),bun lint,python3 -m pytest scripts/tests/,mcp__gitnexus__detect_changes()to confirm only expected symbols moved, and adocs-sitebuild dry-run (cd docs-site && bun run buildin the NEW repo).
R-Sequencing
Section titled “R-Sequencing”This subtask MUST land before {68.9} flip and before {68.10} history purge, and
after {68.8} (so the scrub/relocation of scripts/ literals is already done and the
build context is confirmed clean). Insert as {68.11} with the dependency graph edge:
{68.8} confirm ghcr clean └── {68.11} relocate dev-internal docs/+.planning/.archive/ to private repo (THIS) └── {68.9} repo public flip + security suite (now also gated on {68.11}) └── {68.10} git filter-repo history purge (LAST)History-purge interplay (critical): moving the trees at HEAD does NOT remove them from
git history — every old commit still contains the client IP. Therefore {68.10}’s
git filter-repo path set MUST be extended to also strip the relocated paths
(docs/themes/, docs/workflow-evaluation/, .planning/.archive/, docs-site/, and the
other MOVED subdirs from F’s MOVES list) from ALL history of the public repo. Add an explicit
acceptance line to {68.10}: “fresh mirror clone shows zero blobs for the
{68.11}-relocated path set across all history.” Without this, the move leaves the IP in
history and the public flip still leaks it. The relocated content’s history can be preserved
in the new private repo via git filter-repo --path <subdir> --path-rename extraction from
a pre-purge mirror clone (do the extraction BEFORE {68.10} rewrites SHAs).
R-Risks
Section titled “R-Risks”| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
docs-site build breaks (../docs source root dangles) | High if naive | High | Move docs-site WITH the corpus into one repo (keeps relative coupling); OR repoint source_root + multi-root manifest (R-Split option a). Dry-run bun run build in new repo before flip. |
| Ledger-write friction (loop blocked / split-brain ledgers) | High if ledgers moved | Critical | DON’T move ledgers/specs — keep + sanitise in main repo (R-Split STAYS). Submodule explicitly rejected for this reason. |
| Dangling refs in skills → silent SDLC failures | Medium | Medium | Enumerate load-bearing sites (F3–F5); repoint via ast-dataflow + grep sweep; bun run test (4 roundtrip guards + doc-freshness) must pass before flip. |
| History purge omits relocated paths → IP still leaks post-flip | Medium | Critical | Extend {68.10} filter-repo path set to the {68.11} MOVES list; add the “zero blobs across all history” acceptance line; extract preserved history to new repo from a pre-purge mirror. |
.planning/.archive/ removal degrades GitNexus/ccc recall | Medium | Low–Med | Keep .planning/codebase/ (live map); accept archive-recall loss (RESEARCH §5.2 trade-off already framed); archive lives in new private repo, re-indexable there if needed. |
| AC9 override not recorded | Low | Med | This subtask supersedes PLAN AC9 / OQ-68-1-R2 deferral; record the override in parent TECH acceptance contract when {68.11} lands. |
TM-shape record (for orchestrator to append to docs/reference/task-list.json)
Section titled “TM-shape record (for orchestrator to append to docs/reference/task-list.json)”- id:
{68.11}(sequence: between{68.8}and{68.9}) - description (≤250 chars): Relocate dev-internal
docs/corpus +.planning/.archive/(and thedocs-site/Astro project) into a privateknowledge-hub-docs-siterepo before the public flip; KEEP + sanitise the workflow-mutated ledgers/specs/runbooks and.planning/codebase/in the main repo. Repoint all load-bearing refs. - dependencies:
{68.8}(sibling — confirm build context clean). Blocks{68.9}. - details: see this file (load-bearing F1–F5 findings, R-Split MOVES/STAYS lists,
R-Automation commands, R-Sequencing edge, history-purge extension to
{68.10}). - testStrategy: After rewrite,
bun run test(4 ledger roundtrip guards +doc-freshness.test.tsmust pass),bun lint,python3 -m pytest scripts/tests/,mcp__gitnexus__detect_changes()clean, and adocs-sitebun run builddry-run in the new repo all green;git grep -F 'docs/<moved-subdir>'and'.planning/.archive'return no load-bearing resolution sites.
Open questions for Liam
Section titled “Open questions for Liam”- OQ-68.11-1 — docs-site source after move: R-Split option (a) multi-root manifest syncing staying-reference from the public repo, or (b) interim duplication? (Spec recommends (b) first, (a) as follow-up.)
- OQ-68.11-2 — published reference/runbook MDs: these STAY (loop/test-adjacent) but are also published by the docs-site. Confirm duplication-with-drift-tooling is acceptable vs. a single-source multi-root sync.
- OQ-68.11-3 —
.planning/codebase/: confirmed STAY (live, cited). Any of the 7 docs carry client IP needing sanitisation before the public flip?