Skip to content

ID-68 — Repo visibility and IP separation: private→public readiness

ID-68 — Repo visibility and IP separation: private→public readiness

Section titled “ID-68 — Repo visibility and IP separation: private→public readiness”

{68.1} RESEARCH artefact. This is the investigation phase of the spec-driven lifecycle: it scopes the problem, records current-state findings, lays out options with trade-offs, and surfaces decisions for Liam. It is not an implementation plan. Liam ratifies this before PRODUCT ({68.2}) / TECH ({68.3}) / PLAN ({68.4}).

  • Task: ID-68 “Repo visibility and IP separation — private→public readiness”
  • Roadmap theme: 12 “Repo visibility and IP separation” (time horizon: next)
  • Provenance: Triggered in S288 during ID-66 on-prem Coolify setup by the ghcr package-public question; this Task is the broader repo-public question that the narrower ghcr decision deferred to.
  • Authored: S289 (31/05/2026), main branch.
  • Status: Draft, pending ratification.

A public GitHub repo unlocks GitHub’s free security tooling for public repositories — Dependabot alerts, code scanning, and secret scanning — and the direction of travel aligns with the on-prem pivot (ID-66), where the build artefact (the ghcr cocoindex image) is already public. The pull toward public is real and has a concrete security payoff.

The blocker is equally real: the repository currently contains pre-launch client-specific documentation and proprietary process/IP artefacts that must remain protected. The hard constraint from theme 12 is unchanged — client documentation and IP must remain protected. The question this Task answers is not “should we go public” in the abstract, but: what must be excluded, relocated, scrubbed, or accepted before the knowledge-hub repository can be made public without leaking client documentation or IP, and is the supporting machinery (docs-site, security features) ready to make that worthwhile.

A second framing nuance discovered this session: a meaningful slice of the “leak” is already public via the ghcr cocoindex image (which ships scripts/ verbatim — see §4.1). So part of this Task is reactive cleanup of an existing exposure, not purely prevention of a future one.

gitnexus orientation: no existing symbols match — greenfield surface (this is a repo-governance / publication-readiness Task, not a code feature; the relevant artefacts are build config, tracked files, and GitHub settings, not application symbols. The two gitnexus-flagged symbols scripts/export-phew-articles.ts and scripts/split_phew_site_content.py are incidental client-named scripts, catalogued in §4.)

  1. What must be excluded or relocated before the repo goes public — client docs, .planning/**, other IP, the client-name leak in scripts/. (§4)
  2. Whether the ID-9 Astro docs-site is the right mechanism to host public-facing docs separately from the code repo. (§6)
  3. Disposition of .planning/** — retire, archive externally, or retain private. (§5)
  4. GitHub security-feature gains post-publication (Dependabot, code scanning, secret scanning; the repo currently has open Dependabot vulns). (§7)
  5. Container image visibility policy (ghcr kh-cocoindex-pipeline, already public). (§8)

All findings below were derived from the repository at HEAD on the main branch (commit 075bd282) on 31/05/2026:

  • git ls-files / git grep over the tracked tree (untracked / gitignored content is out of scope — it never ships).
  • gh API queries for repo visibility, Dependabot alert counts, and ghcr package visibility (live, 31/05/2026).
  • Direct reads of deploy/onprem/docker-compose.yml, .github/workflows/onprem-deploy.yml, lib/client-config.ts, docs-site/astro.config.mjs, and .gitignore.

Scope boundary. This RESEARCH scopes and recommends; it does not execute. The actual scrub, relocation, and the GitHub flip belong to {68.4+} implementation Subtasks after ratification. The dedicated scrub session (client-name parameterisation, catalogue-script relocation) is planned for a later session and folds into this Task’s PLAN.


FactValueSource
Repo visibilityPRIVATEgh repo view ai-solution-hub/knowledge-hub
Total tracked files5,094git ls-files
ghcr kh-cocoindex-pipeline visibilityPUBLICgh api .../packages/container
Open Dependabot alerts23 (8 high / 11 medium / 4 low)gh api .../dependabot/alerts
.planning/git-TRACKED, 36 MB, 1,269 filesgit ls-files .planning/
docs/client-documentation-corpus/git-TRACKED, 33 filesgit ls-files
docs-site (ID-9)BUILT + committed, NOT deployeddocs-site/astro.config.mjs:30

Correction to the S288/S289 brief. The brief cited “3 open Dependabot vulns (2 moderate, 1 low)”. The live count on the default branch is 23 open alerts (8 high, 11 medium, 4 low). The “3” was likely a stale or filtered figure. Whichever is canonical, the directional point holds: publication turns these alerts on for free and there is open vulnerability debt to clear (see §7). PRODUCT should re-pull the live count at the time of the go decision.


4. Area 1 — What must be excluded, relocated, scrubbed, or accepted

Section titled “4. Area 1 — What must be excluded, relocated, scrubbed, or accepted”

This is the core of the investigation. The exposure splits into two distinct risk channels with different urgency, because of how the ghcr image is built.

4.1 The ghcr image ships only a pruned scripts/ tree — not the whole repo

Section titled “4.1 The ghcr image ships only a pruned scripts/ tree — not the whole repo”

This is the single most important finding for prioritisation, and it corrects the working assumption in the S289 brief (“the ghcr image bundles all of scripts/ verbatim”).

.github/workflows/onprem-deploy.yml builds the cocoindex image from an explicitly pruned build context, not the repo root:

Terminal window
CTX="$(mktemp -d)"
cp -R scripts "${CTX}/scripts"
cp requirements.txt "${CTX}/requirements.txt"
pack build "${IMAGE}:${TAG}" --path "${CTX}" ...

The workflow comment is explicit about why: pack does not reliably honour .gcloudignore / project.toml excludes (a whitelist attempt leaked .claude, docs-site, __tests__ into /workspace), so the build copies only scripts/ + requirements.txt into a temp dir and builds from there. The asserted post-condition is ls /workspacescripts requirements.txt only.

Consequence — two risk channels:

  • Channel A (already public, via the image). Everything under scripts/ (all .py and .ts) is already shipped in the public ghcr image, verbatim. Anyone who pulls ghcr.io/ai-solution-hub/kh-cocoindex-pipeline can extract it. The client-name leak in scripts/ (§4.2) is therefore already exposed, independent of the repo flip. This makes the scripts/ scrub reactive cleanup, not future prevention.
  • Channel B (exposed only if the repo goes public). Everything outside scripts/docs/, .planning/, lib/, app/, fixtures, the client corpus — is not in the image and is exposed only by the repo flip. This is the higher-severity, still-private content (§4.3), and it is the real gate on going public.

A go-public decision must clear both channels, but they are scoped and sequenced differently: Channel A can be cleaned at leisure (the horse has bolted; cleanup limits future image builds and is good hygiene); Channel B is the hard pre-condition.

4.2 Channel A — client-identity leak in scripts/ (already public)

Section titled “4.2 Channel A — client-identity leak in scripts/ (already public)”

“phew” (case-insensitive) appears in 602 tracked files repo-wide; the scripts/-only subset (the part already in the public image) includes:

  • scripts/eval-holder-rule-ts.ts:100const CLIENT_ORG_LOWER = 'phew design limited'; plus named third-party content: “Telehouse” certs and the disclaimer text “…held by Telehouse, not Phew Design Ltd” (lines 528–557).
  • scripts/seed-phew-guides.ts — header “Seed script for Phew Design guide definitions.”
  • scripts/catalogue-charnwood-itt.ts — “Catalogue Charnwood Borough Council ITT Services requirements. Inserts 30 requirements…” (named third-party tender content; a public-tender PPN-style ITT, but still a named council).
  • scripts/restore-eval-corrupted-items.ts, scripts/reclassify-items.ts, scripts/export-phew-articles.ts, scripts/split_phew_site_content.py, scripts/kb_pipeline/classify.py, scripts/keyword_classifier.py, and ~20 more scripts/ files referencing the client name or eval fixtures.

No live credentials/keys/JWTs are leaked. Verified: no sk-ant-api03…, AKIA…, or BEGIN … PRIVATE KEY in non-test, non-.planning tracked files; the compose file uses only ${VAR} refs (Coolify injects secrets at deploy); Supabase project-refs are public DNS subdomains that identify but do not authenticate a project, and the prod ref rovrymhhffssilaftdwd is already in the committed CLAUDE.md.

Severity of Channel A. Low-to-moderate. The client name (“Phew Design Limited”) is Liam’s own organisation, and the Charnwood ITT is public-tender content (a published council ITT / PPN material). The Telehouse reference is a factual data-point about whose certifications apply, embedded in an eval rubric. Per Liam’s S289 decision, this is ACCEPTED for now and folded into this research; a dedicated scrub session is planned.

Mitigation lead (scrub-not-rewrite). The codebase already supports parameterising the client identity, so the scrub is mostly reading config instead of literals, not a rewrite:

  • lib/client-config.ts is a single-source client config. It already hardcodes entity_examples.organisation_name: 'Phew Design Limited' / organisation_short: 'Phew' / product_name: 'Phew Audit System' as the default config, and resolves per-client branding from NEXT_PUBLIC_CLIENT_ID against CLIENT_BRANDING_MAP (default, phew).
  • lib/branding/clients/phew.json + public/clients/phew/{logo,favicon}.* are the per-client assets — already separated from default.json.
  • NEXT_PUBLIC_CLIENT_ID is consumed by lib/client-config.ts, lib/env-client.ts, and several scripts (eval-holder-rule-ts.ts, reclassify-items.ts, restore-eval-corrupted-items.ts, wp-b-triage-report.ts).

So the scrub direction is: move literal client strings in scripts/ to read from CLIENT_CONFIG / NEXT_PUBLIC_CLIENT_ID, and relocate the two catalogue-*-itt.ts seed scripts out of the shipped tree (they are historical one-shot seeds explicitly marked “Do not re-run”, carry named-council ITT content, and have no reason to ship in the pipeline image). default.json becomes the genuinely generic config; the phew.* files would move to a private overlay (or stay, accepted, per the §9 decision).

4.3 Channel B — higher-severity content exposed only by the repo flip

Section titled “4.3 Channel B — higher-severity content exposed only by the repo flip”

These are not in the ghcr image; they become public only if the repo flips. Counts are tracked-file counts at HEAD.

PathTracked filesWhat it isSeverity
docs/client-documentation-corpus/33The ingest corpus: actual client bid-library markdown + binary-originals/ .docx, plus Telehouse-South-Fact-Sheet-2025.pdf (named third party), 04-named-clients-and-case-studies.md, 05-team-structure-and-key-people.md, company overview, brand voice.HIGH
docs/client-briefs/8Product / sector-intelligence briefs, gap-analysis trackers, “Liam-Final” strategy docs.HIGH
docs/testing/test-data/templates/9Real third-party tender documents: Charnwood ITT (.xls/.docx), British Council RFP set, EFA ITT vol8, SQ PPN-03-24, CSP checklist.MODERATE (some are public-tender artefacts; British Council RFP may not be)
docs/testing/uat/6UAT scenarios referencing Charnwood ITT method statements.MODERATE
.planning/1,269Process IP + historical specs/audits (see §5).MODERATE–HIGH
docs/themes/canonical-pipeline/66Phase-0 investigation docs naming Telehouse/Phew/Charnwood.LOW–MODERATE
docs/audits/28Classifier eval reports with Telehouse-attributed cert fixtures.LOW–MODERATE

The clearest hard blocker is docs/client-documentation-corpus/. This is the ingest corpus itself — actual proprietary client documentation (a real bid library, draft tender responses, named clients and case studies, team structure, and a third party’s fact-sheet PDF). It directly violates the theme 12 hard constraint and must be excluded or relocated before any public flip. There is no parameterisation story here (it is content, not config) — it must leave the tracked public tree (git-rm + history scrub, or move to a private sibling repo / private branch).

Note on git history. Excluding a file from the current tip does not remove it from history. For a public repo, sensitive content under docs/client-documentation-corpus/, docs/client-briefs/, and the client-named test-data must be purged from history (e.g. git filter-repo), not just deleted at HEAD — otherwise it remains retrievable from the public commit graph. This is a non-trivial, one-way operation and is a first-class PLAN item, not an afterthought. (See OQ-68-5.)

“phew”/“Telehouse” also appear in __tests__/fixtures/*-gold-standard.json, __tests__/lib/ai/classify.test.ts, components/entity-management/ entity-detail-panel.tsx, and lib/ai/skills/classification.md / lib/ai/skills/inlined.generated.ts. These are eval gold-standard fixtures and classification prompt examples. Severity is low (the client name is Liam’s own org), but they are in Channel B and would be part of a thorough scrub if the decision is “scrub fully” rather than “accept the client-name presence”.


.planning/ is git-TRACKED (not gitignored), 36 MB, 1,269 files, in two structurally distinct parts:

  • .planning/codebase/ — 7 current architecture documents (ARCHITECTURE.md, CONCERNS.md, CONVENTIONS.md, INTEGRATIONS.md, STACK.md, STRUCTURE.md, TESTING.md). These are live and cited: CLAUDE.md names .planning/codebase/ as the codebase map, and the write-tech-spec skill points at .planning/codebase/STRUCTURE.md. Removing these degrades agent grounding immediately.
  • .planning/.archive/ — the large historical store: .specs/ (~324 entries), .audits/ (~207), .continuation-prompts/ (~344), .research/, .plans/, .reviews/, .feasibility/, .reference/, etc. This is the bulk of the 1,269 files and the 36 MB, and it is where the process IP, stale specs, and client-named historical material concentrate (Charnwood/Telehouse appear throughout .planning/.archive/).

5.2 How it is indexed (and why removal has a recall cost)

Section titled “5.2 How it is indexed (and why removal has a recall cost)”

.planning/ is indexed by both code-intelligence systems:

  • GitNexus has .planning files in its graph (≈2,574 files in the broader graph).
  • ccc / cocoindex indexes it too, despite a **/.* exclude that appears to be a no-op against top-level dot-directories.
  • MemPalace is a separate MCP memory system — it is not a filesystem indexer of .planning/ and does not depend on it. So removing .planning/ does not touch MemPalace recall.

The trade-off is therefore concrete: keeping .planning/.archive/ preserves tool-assisted historical recall but (a) exposes process IP if the repo goes public and (b) surfaces stale specs in code-search, which can mislead agents. Removing it shrinks recall, and there is no live replacement yet (the docs-site is not deployed — §6).

OptionDescriptionProsCons
R1 — Retain private (status quo)Leave .planning/ tracked; do not go public until a better split exists.Zero recall loss; no work.Does not unblock public; IP exposed the moment we flip.
R2 — Split: keep codebase/, evict .archive/Keep the 7 current architecture docs tracked; move .planning/.archive/ out of the indexed tree (separate private branch/repo, or a tool-exclude that actually works).Preserves the live, cited codebase map; removes the bulk of IP + stale-spec noise; shrinks the public surface ~1,260 files.History scrub still needed for the public flip; need a working ccc/gitnexus exclude or a real relocation.
R3 — Retire .archive/ entirelyDelete the archive (history-purge for public).Smallest public surface; ends stale-spec pollution.Irreversible recall loss of all historical decisions; high regret risk; MemPalace does not cover it.
R4 — Archive externallyMove .archive/ to a private GitHub repo / cold store, keep a pointer.Preserves recall somewhere; clean public repo.Loses in-repo tool indexing of the archive; extra repo to maintain.

Do NOT remove .planning/ now. It is not the gate (the client corpus is), and the codebase docs are actively cited. The recommended sequence is R2, deferred: once the docs-site is live (so there is a real home for any public-facing architecture content), evaluate moving .planning/.archive/ out of the indexed/tracked tree while keeping .planning/codebase/. This is the disposition decision Liam should ratify (OQ-68-1) — but the execution is gated on the docs-site, not on this RESEARCH.


6. Area 2 — is the ID-9 Astro docs-site the right public-docs mechanism?

Section titled “6. Area 2 — is the ID-9 Astro docs-site the right public-docs mechanism?”

The Astro 5 + Starlight docs-site is BUILT and committed in-repo at docs-site/, but NOT deployed:

  • docs-site/astro.config.mjs:30 still has the placeholder site: 'https://vercel-default-subdomain.vercel.app'.
  • There is no Vercel deploy workflow for the docs-site (the 15 workflows in .github/workflows/ include docubot.yml, sync-source-docs.yml, review-docs-pr.yml, etc., but no docs-site-deploy / Vercel publish).
  • ID-9 is in_progress: 21 of 25 subtasks done. The open ones are decommission-gate / E2E-conversion / dangling-ref cleanup — and notably there is no completed “first deploy” subtask; deploy readiness is implied by the placeholder site value.
  • No docs-site runbook exists (docs/runbooks/ has none matching docs-site/astro/starlight). This is a documentation gap that PLAN should flag.

The docs-site is the intended mechanism for hosting public-facing docs separately from the code repo — that is precisely its design purpose, and it is the natural home for the generic product/architecture docs that today live in-repo (and which a public repo would otherwise expose in raw, unpolished form). It is the right answer to “where do public docs live, separate from code”.

But it is not yet a usable replacement. Until it is deployed with a real site URL and a deploy pipeline, there is no live surface to migrate in-repo docs to. So the docs-site cannot today substitute for any in-repo docs that we might want to remove before going public.

This produces the central sequencing question (OQ-68-2): do we gate the public-go on the docs-site being deployed, or do we go public first (clearing only the hard IP blockers) and migrate polished docs to the docs-site later? The two are separable — the repo can go public with raw docs/ present (minus the client corpus) and have the docs-site come later as the polished public face, or we hold the flip until the docs-site is the front door.


7. Area 4 — GitHub security-feature gains post-publication

Section titled “7. Area 4 — GitHub security-feature gains post-publication”

Public repos get, for free, the GitHub Advanced Security subset that is otherwise paid on private repos:

  • Dependabot alerts (vulnerable dependency detection) — already partially on; full alert + auto-PR flow on public.
  • Dependabot security updates (automated fix PRs).
  • Code scanning (CodeQL) — static analysis for security bugs, free for public repos.
  • Secret scanning (+ push protection) — detects committed secrets and can block pushes that introduce them; free for public repos, including partner patterns.

Current debt: 23 open Dependabot alerts (8 high / 11 medium / 4 low) on the default branch (live S289; the brief’s “3” is stale — §3). Going public turns the full alerting on and makes the high-severity items visible to anyone, so clearing or triaging the high-severity alerts should precede the flip (or be an immediate post-flip Subtask) rather than exposing open high-sev vulns on a public repo.

Secret scanning is doubly relevant here: it is both a gain (push protection prevents future leaks) and a gate (it will flag any historically committed secret across the whole history once enabled — see the history-scrub note in §4.3 / OQ-68-5).


8. Area 5 — container image visibility policy

Section titled “8. Area 5 — container image visibility policy”

ghcr.io/ai-solution-hub/kh-cocoindex-pipeline is PUBLIC (verified S289). This was the original S288 trigger: the package-public decision was held pending verification that the buildpack did not bake private docs into the image.

The image build context is a pruned scripts/ + requirements.txt only. The onprem-deploy.yml Inv-9 assertion further checks the image carries no pullmd / Playwright (AGPL boundary). So the buildpack-bakes-private-docs concern from S288 is resolved: the image does not contain docs/, .planning/, the Next.js app, docs-site, .claude, or tests. It contains the Python pipeline + the client-name leaks in scripts/ (Channel A, §4.2).

OptionDescriptionTrade-off
I1 — Keep public (status quo)Leave the cocoindex image public.Simplest; matches on-prem direction. But Channel A leaks stay public and any future scripts/ content is auto-public on each build.
I2 — Make privateFlip the package to private; pull with a token in Coolify.Closes Channel A exposure; adds a registry-auth step to the on-prem deploy (Coolify pull credential). Reversible.
I3 — Keep public + scrub scripts/Keep public, but complete the §4.2 scrub so the image carries no client identity.Best end-state if public is desired anyway; couples image-visibility to the scrub timeline.

The image-visibility policy is logically downstream of the repo-public decision: if the whole repo goes public, the image being public is moot; if the repo stays private, the image is the only public surface and I2/I3 become the levers for Channel A. Recommended: align the image policy with the repo decision rather than deciding it in isolation (OQ-68-4).


  1. OQ-68-1 — .planning/ disposition. Ratify the §5 direction? Recommended: R2 deferred (keep .planning/codebase/, evict .planning/.archive/ once the docs-site is live), not R3 (retire) or R1 (status quo). Which option?

  2. OQ-68-2 — Gate the public-go on docs-site deploy? Do we hold the repo flip until the ID-9 docs-site is deployed and is the polished public front door (sequential), or go public first after clearing only the hard IP blockers and migrate docs to the docs-site afterwards (parallel)? This sets the whole Task’s critical path.

  3. OQ-68-3 — Scrub scope. For the client identity (“Phew Design Limited” / Telehouse / Charnwood): (a) full parameterise-and-remove sweep across all 602 files; (b) scripts/ + image only (the already-public Channel A), accept the rest; or (c) accept the client name throughout (it is Liam’s own org) and scrub only genuine third-party / proprietary content (the client corpus, British Council RFP, team/case-study docs)? The S289 default is “accept for now, dedicated scrub session next”; this OQ pins the target scope for that session.

  4. OQ-68-4 — ghcr image visibility. Keep public (I1), make private (I2), or keep-public-after-scrub (I3)? Recommended: decide jointly with the repo flip — if the repo goes public, keep public; if not, I2/I3 to close Channel A.

  5. OQ-68-5 — History scrub. Do we require a full git-history purge (git filter-repo) of the client corpus + briefs + client-named test-data before going public (correct but one-way and disruptive), or accept that history-deletion happens at HEAD only with the understanding that the public commit graph would still hold the old content? For a genuinely client-protecting public repo, history scrub is effectively mandatory — this OQ confirms appetite and surfaces the cost.

  6. OQ-68-6 (secondary) — Dependabot debt timing. Clear the 8 high-severity Dependabot alerts before the flip, or flip and clear immediately after? Exposing open high-sev vulns on a public repo is a (small) reputational/risk cost.


A pragmatic, reversible sequence that respects the hard constraint and the S289 “accept-for-now” posture:

  1. Treat the client corpus as the only true blocker, not the client name. The gate on going public is Channel B proprietary contentdocs/client-documentation-corpus/ (33 files: real bid library, named clients/case studies, team structure, third-party Telehouse PDF), docs/client-briefs/ (8), and the non-public-tender docs/testing/test-data/ items (British Council RFP). These must be relocated to a private store and purged from history. The client name (Phew, Liam’s own org) and public-tender artefacts (Charnwood ITT, PPN SQ) are accepted per S289 and scrubbed opportunistically, not as a gate.

  2. Channel A (scripts/ leak) is already public via the ghcr image — so its cleanup is hygiene, not a gate. Parameterise the client literals in scripts/ against the existing CLIENT_CONFIG / NEXT_PUBLIC_CLIENT_ID machinery and relocate the two catalogue-*-itt.ts one-shot seed scripts out of the shipped tree. Schedule with the dedicated scrub session.

  3. .planning/: R2, deferred. Keep .planning/codebase/ (live, cited); plan to evict .planning/.archive/ once the docs-site is live, since that is where the IP + stale-spec noise concentrates and where eviction has the biggest surface reduction (~1,260 files) for the least recall cost.

  4. Sequence the docs-site as the public front door, but do not necessarily hard-gate on it (OQ-68-2). The docs-site (ID-9) is the right mechanism; finishing its deploy (real site URL + deploy workflow + a runbook — all currently missing) is the natural predecessor to evicting in-repo docs. If Liam wants public sooner, the repo can flip after the Channel B content purge with raw docs/ present, and the docs-site lands afterwards as the polished surface.

  5. Clear the high-severity Dependabot alerts around the flip and rely on the free public-repo security suite (code scanning, secret scanning + push protection) as the ongoing payoff — and as a guard against re-introducing the very leaks this Task cleans up.

  6. Keep everything reversible until the history scrub. Visibility flips (repo, ghcr image) are reversible; the history purge is the one-way door. Order the PLAN so the irreversible step (history filter-repo + public flip) is the last action, after content relocation, scrub, and Dependabot triage are all verified.

This keeps the hard constraint intact (client documentation and proprietary IP leave the public tree and its history), unblocks the security-tooling payoff, and aligns with the on-prem direction without forcing a premature or irreversible move. PRODUCT ({68.2}) should turn items 1–6 into ratified acceptance criteria and pin the OQ-68-* answers.


11. Ratification & corrections (S289, Liam)

Section titled “11. Ratification & corrections (S289, Liam)”

Terminology correction (load-bearing — supersedes any conflation above, incl. §10.1 “Phew, Liam’s own org”):

  • AI Solution Hub = our organisation (the vendor). Public-safe.
  • Phew (Phew Design Limited) = our first client. The hardcoded phew / phew design limited literals in scripts/ are therefore client identity, not org identity — they are genuinely sensitive and in scope for the scrub (Rec 2). “AI Solution Hub” appearing in code/docs is fine.
  • Knowledge Hub = the platform (the product itself).

Other correction: under docs/testing/test-data/, the only non-public item is the CSP, not the RFP (the §10.1 “British Council RFP” framing is corrected — the RFP is not the sensitive artefact; the CSP is).

OQ resolutions (ratified):

  • OQ-68-1 (.planning disposition): R2 — keep .planning/codebase/, defer .planning/.archive/ eviction until the docs-site is live.
  • OQ-68-2 (gate public-go on docs-site?): Moot — the docs-site is NOT public. Its purpose is the canonical Knowledge Hub platform documentation location (NOT Phew/client docs, NOT public marketing), kept accurate against the codebase by the already-deployed docs skills + CI actions. It is an internal-canonical surface, so it is not the “public front door” §10.4 framed. Hosting options (priority order): (a) docs.knowledge-hub-seven-kappa.vercel.app if Vercel allows that subdomain (the platform URL before the Phew domain went live); (b) temporarily on aisolutionhub.co.uk (owned) until a long-term domain is purchased; (c) a fresh Vercel project for its default domain. Deploying it is still prioritised (supports OQ-68-1 archive eviction).
  • OQ-68-3 (scrub scope): parameterise the client literals in scripts/ (org name “AI Solution Hub” stays). Tooling — see “Scrub tooling” below.
  • OQ-68-4 (ghcr visibility): I1 — keep public (cocoindex is MIT; nothing proprietary ships). Revisit only if a proprietary artefact ever enters the image build context.
  • OQ-68-5 (history scrub): agreed — full git filter-repo of the relocated client content; automate the content-site discovery via the OQ-68-3 tooling, then run the history purge as the last, one-way step.
  • OQ-68-6 (Dependabot timing): clear the 8 high-severity alerts BEFORE the flip.

Scrub tooling (answer to OQ-68-3 — find vs rewrite are different jobs):

  • Find (exhaustive site inventory): ast-dataflow string-literal-uses for the TS/TSX corpus + a grep sweep for Python / SQL / Markdown (ast-dataflow is TS-only). gitnexus / cocoindex-code (ccc) are semantic navigation tools, and gitnexus_rename only renames symbols, not string literals — neither rewrites literals, so they are find-aids at most here.
  • Rewrite: the AST-aware rewriters are ts-morph (TS — the lib ast-dataflow is built on, already used in scripts/codemods/) and ast-grep (sg --rewrite, covers TS and Python in one pass — best single tool for a cross-language literal swap).
  • Caveat — Rec 2 is parameterisation, not blind replacement. Swapping a literal for a getClientConfig() / NEXT_PUBLIC_CLIENT_ID lookup is a semantic edit needing per-site judgement (parameterise vs delete-the- historical-script vs leave-org-name). So the scrub session should: (1) ast-dataflow + grep to build the categorised site list; (2) a guided ts-morph codemod for the uniform parameterise cases; (3) manual for the nuanced ones. History removal (OQ-68-5) is git filter-repo, a separate git operation — no AST tool does it.

New scope surfaced by this ratification (carried to {68.2} PRODUCT / next session):

  • Relocate docs/client-documentation-corpus/ (+ client-briefs/) OUT of the repo and point a KH ingest at Liam’s local Mac filesystem instead — deliberately replicating how a real KH deployment points at a client’s file store (production-aligned, not a repo-embedded corpus). This also intersects ID-45/T7 (the ingest source root) and the bl-206 path-drift gate.
  • Define the required client-setup directory structure when KH points at a client’s files (what layout/conventions, if any, the ingest expects). This is likely already defined or referenced in the pipeline intended-architecture docs (docs/themes/canonical-pipeline/intended-architecture/) — confirm and surface it as the contract.
  • Housekeeping (next session): reconcile the task-view version drift (local cache v0.3.1 vs the CI/drift-workflow pin v0.2.0-task-view).