Appearance
Code Review โ Docs Wiki (feature/docs-wiki) โ
- Date: 2026-07-16
- Branch:
feature/docs-wiki(16 commits,0a139a6..2c00ef0) - Scope: VitePress docs wiki as the Nx project
docs(Tasks 1โ5 ofdocs/superpowers/plans/2026-07-16-docs-wiki.md). Task 6 (Cloudflare Access gate) is operational and still pending. - Method: subagent-driven โ per-task spec+quality review with fix loops, then a whole-branch review on the most capable model.
Deterministic gate (all green) โ
| Check | Result |
|---|---|
bun test ./docs/.vitepress/sidebar.test.ts | 3 pass / 0 fail (11 assertions) |
bunx nx build docs | success โ docs/.vitepress/dist/index.html |
bunx nx lint docs | success (0 errors) โ with generated .vitepress/cache present |
bunx nx run-many -t lint (all 6 projects) | success, 0 errors (14 pre-existing no-explicit-any warnings in apps/web spec files, unrelated to this branch) |
git status | clean; dist/cache untracked (gitignored) |
Findings โ
๐ด Blocking โ
None.
๐ก Should-fix / Decision required โ
docsis in the product CI lint/build gate โ contrary to the spec.@nx/eslint/plugininfers alinttarget anddocs/project.jsondeclares abuildtarget, soci.yml(nx run-many -t lint test build) and.husky/pre-push(nx affected -t โฆ) both now runnx lint docs+nx build docs. The spec ยง"Nx targets & dependencies" says "the docs project stays out of the product web/api lint/test/build gate and the husky pre-push hook." Green today, but a future doc with unescaped Vue{{ }}(whichignoreDeadLinksdoes not cover) would failnx build docsand turn an unrelated code+docs PR's requiredcicheck red โ the coupling the spec meant to avoid. Decision: (a) accept docs in the gate (docs build is now CI-verified โ arguably desirable) and correct the spec sentence; or (b) exclude docs from the gate (--exclude=docson the run-many/affected calls, or a project tag). Not a code bug; the human picks which governs.- Sidebar spec never runs in CI (coupled to the above).
sidebar.test.tsruns only viabun test; there is no Nxtesttarget ondocs, sonx run-many -t testskips it and the scanner can regress unnoticed. If option (a) above is chosen, adding atesttarget (bun test) todocs/project.jsoncloses this; if (b), leave as-is.
๐ข Nits (reviewed โ acceptable, logged for the record) โ
docs/.vitepress/sidebar.ts:84โ thecontract-qacheck in the files loop is unreachable (dirs are skipped a level up at:74); harmless defensive dead code.docs/.vitepress/sidebar.ts:66-68โ file sort comparator isn't a strict weak order for a folder mixing dated + undated.md; all real folders are homogeneous, and JSsortnever throws โ worst case is a cosmetic ordering quirk.docs/.vitepress/sidebar.test.tsโ no assertion for thebuildSidebar-level H1-fallback / unreadable-file path (titleFromContent(null)is unit-tested;titleForFileis a trivial try/catch).docs/.vitepress/theme/custom.css:9โ--vp-c-brand-softhas no.darkoverride; the 20%-opacity lime reads fine on both themes.
What was built (per task) โ
- VitePress skeleton (
docs/.vitepress/config.mts,index.md,project.json,.gitignore) โ Nx projectdocsrooted atdocs/,srcExcludecontract-qa,ignoreDeadLinks, local search. Fix: narrowed.nxignoreso Nx discovers the project; kept vendored contract-qa out of eslint scope;<code v-pre>on two self-referential planning docs that literally contain{{ โฆ }}. - Sidebar scanner (TDD) (
sidebar.ts+sidebar.test.ts) โ cwd-independent (import.meta.url), H1 titles, date-desc sort, contract-qa/index excluded, empty folders omitted. 3/3 bun tests. - Live sidebar (
live-sidebar.ts) โ config-file mtime touch (notserver.restart()), because a pluginserver.restart()breaks local search (MiniSearch: duplicate ID, vitepress#4251). Controller-verified end-to-end: clean config-triggered restarts (0 duplicate-ID / 0 failed), search intact, git clean. Fix: swallow transientutimesrejection so a one-off fs error can't crash the dev server. - Brand accent theme (
theme/index.ts,theme/custom.css) โ thin Dispatch accent from#C1D841/#10130B; light-theme link colour darkened to#66761f(~5:1, clears WCAG AA). Also fixed a repo-wide build-then-lint failure by ignoring**/.vitepress/cache/**in eslint. - Deploy artifacts (
infra/cloudflare/docs.wrangler.toml,.github/workflows/deploy-docs.yml) โ manualworkflow_dispatchonly, publishesdocs/.vitepress/distto Pages projectdispatch-docs, secrets via${{ secrets.* }}, mirrors the existing web deploy. No issues.
Security โ
- No secrets committed;
dist/cachegitignored and untracked. - Sensitive files provably not served โ the built
dist/contains nogoogle_client_secret*.json, nosamples/*.pdf, nocontract-qa/**(VitePress serves only.md; there is nodocs/public/). - Deploy cannot self-fire (manual only). Internal docs (
authz-matrix.md,auth-setup.md,dispatch-production-design.md, โฆ) would be world-readable if deployed ungated โ the Cloudflare Access gate (Task 6) is a hard prerequisite before any real deploy, and the workflow must not gain apush:trigger until it's in place.
Verdict โ
READY to merge (code). Two things remain the human's call/action:
- The ๐ก decision above (docs in the CI gate โ accept & correct spec, or exclude).
- Task 6 โ Cloudflare Access gate โ operational, needs the Cloudflare account: stand up the
dispatch-docsPages project + an Access application (explicit email allow-list:damien@seeg.dev,damien@seeg.io,damien@seeg.co,damiens@gmail.com,damien@damien.in) covering the production hostname and*.dispatch-docs.pages.dev, verified to block anonymous access before the first real deploy.
Nothing has been pushed.