πŸ“š Documentation Review

πŸ“‹ Summary

Midshift is unusually heavily documented for a one-developer product: roughly 46,000 words of Markdown across a README, an architecture document, an API reference, a deployment guide, a security policy and a very long working-rules file (CLAUDE.md), plus source code in which about one line in five is a comment. Much of it is candid and useful β€” the architecture document openly lists what is missing (no error tracker, no tested backups, no review gate before production). However, the documents are written as a running decision log by and for an AI-assisted development workflow, they are dense and hard for a newcomer to navigate, and they have drifted from the code in several places, including facts that matter: how to set up a fresh database, whether a security migration has been applied, and who to contact about a vulnerability. Of 16 specific claims checked against the code, 3 are current, 3 are partly current, 9 have drifted and 1 is an unfilled placeholder. A new team could take the product over, but would need a short, correct onboarding path, an operations runbook and a data-model diagram first.

🎯 Rating

🟑 ●●●○○ 3 / 5 β€” Adequate (Amber). Coverage is broad and the API reference is near-complete (82 of 83 route files documented), but material drift on onboarding and security facts, contradictions between documents, and the absence of runbooks and incident procedures mean the documentation cannot yet be relied on without verification.

πŸ” Findings

1. Inventory

DocumentLinesAudience / purposeAssessment
README.md151Product summary, architecture sketch, getting started, verification, mapGood shape; several stale facts (see Β§3)
ARCHITECTURE.md766Topology, runtime, auth, data model, flows, config, release, operations, debt, dependenciesStrongest document; candid about gaps; one Mermaid topology diagram; "verified against the code on 2026-09-04" and stale in places
CLAUDE.md832Working rules for AI coding sessions; migration register; parked decisions; gotchasVery dense decision log, 61 dated entries (latest 2026-09-28); contains the only migration register
AGENTS.md5One instruction to AI agents ("This is NOT the Next.js you know")Agent-tooling artefact, not human docs
SECURITY.md53Vulnerability reporting, SLAs, scope, incident recordPlaceholder contact; stale migration statement
docs/API.md218Every API route: method, path, auth, purpose, body/response, side effectsNear-complete; prose tables, no machine-readable spec
docs/HANDOVER.md319"For a session that picks the build up mid-stream": worktree workflow, design board on claude.ai, queueWritten for AI sessions; depends on an external board and "comment ledger"
docs/NEW_DEPLOYMENT.md222Standing up a client deployment; regions; what SQL cannot configureValuable; internally contradictory on migrations
docs/DESIGN_CHECKS.md1,094UI design gate and screen audit inventoryVery detailed; design-process doc
docs/STYLE_GUIDE.md117UI tokens, type scale, patternsReference
docs/TESTING_ROUND.md95Runbook for a user-testing roundProcess doc
docs/WALK_LIVE.md93Running the acceptance walk against the live siteStep-by-step, good
docs/UTM_REFERENCE.md113UTM builder requirementsIndex describes it against a removed function
docs/NAMING_CONVENTION.txt, NAMING_WORKSHOP_HANDOUT.txt169, 113End-user convention and workshop handoutGood end-user material
docs/README.md33Index of docs/Omits three live documents (HANDOVER.md, DESIGN_CHECKS.md, WALK_LIVE.md)
docs/archive/*351 totalClosed audits and round-1 tester guideCorrectly labelled as archived
design/COMPLIANCE.md258POPIA / contractual readiness, standaloneUseful for legal review; not legal advice by its own statement
.env.example, .env.ops.example64, 30Environment templates with commentsGood; minor stale comments
In-app helpβ€”src/app/(app)/workspace/help/help-view.tsx, 11 sectionsEnd-user help exists in-product
Inline comments12,361 comment lines vs 44,380 code lines in src/Comment-to-code ratio 0.28 (comments are ~22% of non-blank lines)High density; comments explain why (decision history), consistent with the stated convention

[Observed] Line counts from wc -l; comment counts from the shared cloc facts.

2. Style

  • Decision-log narrative. Documents record why things changed, with dates and post-mortems ("Three pushes to main sat red that way on 2026-09-06…", CLAUDE.md:649). This preserves reasoning well but buries current-state facts among history; e.g. the migrations section of CLAUDE.md runs to ~250 lines and lists migrations out of numeric order. [Observed]
  • AI-session orientation. CLAUDE.md, AGENTS.md and docs/HANDOVER.md are explicitly instructions to AI coding sessions ("For a session that picks the build up mid-stream", docs/HANDOVER.md:3), including how to publish screenshots to a claude.ai artifact board (docs/HANDOVER.md:62-93). A human team inherits a workflow built around one owner plus AI agents. [Observed]
  • Density. Long sentences, private vocabulary ("the door", "the strip", "the board", "the ledger", "planted"), and cross-references by section name. High cost to a newcomer. [Observed]
  • Candour. ARCHITECTURE.md Β§9–10 states plainly: no error tracker, no uptime probe, no SLO, no alerting, backups untested, no review gate between commit and production, no retention for logs. This is a strength for due diligence. [Observed] ARCHITECTURE.md:522-560,505-519

3. Accuracy check (16 claims sampled)

#Claim (where)What the code showsVerdict
1Branding, owner and domain "come from environment variables" (README.md:31-32)Organisation name/logo/website are rows in settings read by src/lib/branding.ts:14-19,168; only productName comes from env (src/lib/config.ts:13); OWNER_EMAIL is still env. The README's own env table (line ~84) contradicts its earlier sentence.Drifted (partly: owner is env)
2"Ask … with voice input" (README.md:28-29)Web Speech API used at src/app/(app)/workspace/ask-sheet.tsx:130-131, mic button line 159Current
3Ask is rule-based, no model provider (README.md, ARCHITECTURE.md Β§2)src/lib/ask-intent.ts is keyword rules; no AI SDK in package.jsonCurrent
4Migration 040 "is deliberately unrun" (SECURITY.md:36)supabase/baseline.sql:13-19 says 040 is in and ran in production; CLAUDE.md says applied 2026-09-06; supabase/tests/040_rls.sql and scripts/rls-check.sh existDrifted (also contradicts docs/NEW_DEPLOYMENT.md:88 "RUNS now" vs :200 "stays unrun")
5Security contact (SECURITY.md:5)security@example.com, with a note to replace itPlaceholder β€” no working disclosure channel
6Fresh DB: run baseline, "then any migration numbered above 061 (the baseline is 001-061)" (README.md:70-71; docs/NEW_DEPLOYMENT.md:70-72,195)Baseline header: "migrations 001–090 and 092 united (091 is not folded in)" (supabase/baseline.sql:2); the same header later also says "001–078" and "58 files". Following the README re-runs 062–092 on top of a schema that already contains them.Drifted 🟠 (High β€” onboarding instruction)
7docs/API.md documents "every route handler"83 route files on disk; 82 documented. Missing: PATCH /api/campaigns/[id]/ad-units/[unitId]/cap (copywriter sets a format's character cap for every unit of that format). Documented-but-absent paths are only the retired /api/dam-references and /api/plugin/*, both correctly marked as removed.Mostly current
8API.md auth vocabulary: "edit" = canEditCampaign (docs/API.md:24)23 route files now gate with canEditArea / canApprove (discipline-scoped), 14 with canEditCampaign. The vocabulary table has no "area/discipline" term; it is described only inside individual rows.Partly current
9Vercel has "One cron" (ARCHITECTURE.md:87, diagram line ~68)vercel.json schedules two: purge-review 03:00 and overdue 07:00. .env.example:22 also says CRON_SECRET gates only purge-review.Drifted
10Data model: baseline "creates 40 tables" and lists them (ARCHITECTURE.md:223-235)44 distinct create table in supabase/baseline.sql; the section's table list omits brief_versions, campaign_products, campaign_questions, media_strategy_lines, season_findingsDrifted
11Unit tests: "26 files, 254 tests" (ARCHITECTURE.md:488)Measured: 70 files, 687 testsDrifted (dated 2026-09-07, understated)
12Journey suite: "14 chain files, 330+ tests" (CLAUDE.md:589,614; README.md:97)21 chain-*.spec.ts and 25 spec files in e2e/journeys/; scripts/journeys.sh:107 runs all *.spec.tsDrifted
13"CI's Build step runs AFTER lint, so a lint error skips the build entirely" (CLAUDE.md:649).github/workflows/ci.yml gives every step if: ${{ !cancelled() }}, so build runs regardless; ARCHITECTURE.md Β§8 describes the fix correctlyDrifted (CLAUDE.md stale; ARCHITECTURE current)
14088 "is written and NOT YET RUN … Nothing selects the columns yet"; parse bridge in src/lib/artwork-aspect.ts (CLAUDE.md:376-381)ratio_w/ratio_h are in supabase/baseline.sql:255; frameSpec reads them (src/lib/ad-frame.ts:66,81-82); admin routes write themDrifted
15Global role model admin | editor | reviewer (CLAUDE.md Parked decisions)TypeScript and API validators say so (src/types/database.ts:3), but the database user_role enum has no reviewer (supabase/baseline.sql:46-49)Partly current (docs match code, code does not match schema)
16Copy-deck baseline: 22 units, 0 warnings; Present wall cut; /present/<token> not found; classic routes 308-redirectcopy-deck-parser.baseline.test.ts:14-16; no present page under src/app; next.config.ts:23-33 redirectsCurrent
β€”Addendum from the journey run (Module 7), not part of the 16-claim sample: README lists "Ask β€” a rule-based assistant over the record … with voice input" as a featuree2e/journeys/chain-home-tracking.spec.ts:149,960 skips 7 tests because the Ask button is not rendered: "Ask is parked until the API exists"Unclear β€” the route and logic exist (src/lib/ask-intent.ts, src/app/api/ask), but the button is not rendered in the QA build; whether it is exposed in production is [Unavailable]

Additional minor drift [Observed]: docs/README.md describes UTM_REFERENCE.md against "today's generateUtm()", which was removed (src/lib/utils.ts:10); .env.example keeps comment headers for retired season/domain variables with no variable beneath; README.md "Provenance" says the repository began 31 August 2026 and SECURITY.md says 2026-09-01, while the audited repository is a single squashed commit of 2026-10-06; ARCHITECTURE.md Β§11 correctly flags google-auth-library and date-fns as declared but unused (confirmed: no imports in src, scripts, e2e).

Tally (16 claims): current 3 (#2, #3, #16); partly current 3 (#7, #8, #15); drifted 9 (#1, #4, #6, #9, #10, #11, #12, #13, #14); placeholder 1 (#5). Drift clusters in counts and dated status statements, which the documents restate in several places without any check.

4. API documentation completeness

AspectStatusTag
Route coverage82 of 83 route files (98.8%); missing …/ad-units/[unitId]/cap[Observed]
Per-route auth rule, purpose, side effects (logActivity, notifications, emails)Present for every documented route, unusually thorough[Observed]
Request/response shapesProse in table cells (e.g. docs/API.md:89 is a single several-hundred-word cell); no types, no examples, no error catalogue beyond a shared status-code paragraph[Observed]
Machine-readable spec (OpenAPI/JSON Schema)None[Observed]
Versioning / stability promiseNone; API is internal to the Next.js app[Observed]
Drift controlscripts/harness-contract.js checks routes against the QA harness, not against docs/API.md; the cap route shows docs can fall behind silently[Observed]
Freshness stamp"read from the code on 2026-09-07" (docs/API.md:3) while later routes (085, 086 era, 2026-09-13/14) are included β€” the stamp itself is stale[Observed]

5. Could a new team take over? Gaps in priority order

PriorityMissing or weakWhy it matters
1A correct, short onboarding path (fresh database, environment, first admin, seed data)README and NEW_DEPLOYMENT give a wrong migration instruction and contradict each other on 040
2Operations runbook and incident procedure β€” no on-call, no alerting, no restore procedure, no "site down" stepsARCHITECTURE.md Β§9 confirms none exist; SECURITY.md has no real contact
3Environment matrix β€” which deployments exist, their regions, plans, which migrations each has runMigration register lives only in CLAUDE.md prose; scripts/migrations-applied.sql exists but its results are not recorded per deployment
4Entity-relationship diagram / data dictionary for the 44 tables (legacy and orphaned tables marked)Only a grouped table list, already stale
5Machine-readable API spec generated or checked against codePrevents silent drift
6Separation of human docs from AI-agent instructions and a current-state architecture without the decision history inlineLowers the cost of reading; history can move to ADRs
7Externally held knowledge brought in: product direction, data-protection posture, open-decisions "comment ledger", the claude.ai design board (docs/README.md:31-33; docs/HANDOVER.md:62-70,231-235)Key-person and tool dependency
8Changelog / release notesARCHITECTURE.md Β§8: "no version tags and no changelog beyond the migration register"

🧾 Evidence

  • wc -l README.md ARCHITECTURE.md CLAUDE.md AGENTS.md SECURITY.md docs/*.md docs/*.txt design/COMPLIANCE.md docs/archive/*.md; wc -w over Markdown docs β†’ 46,219 words.
  • Route diff: find src/app/api -name route.ts (83) vs paths extracted from docs/API.md with grep -o '/api/[^]*'andcomm β†’ one undocumented (/cap`), two documented-as-retired.
  • grep -rl "canEditArea\|canApprove" src/app/api | wc -l β†’ 23; canEditCampaign β†’ 14.
  • cat vercel.json β†’ two crons. cat .github/workflows/ci.yml β†’ !cancelled() on each gate.
  • grep -oiE 'create table …' supabase/baseline.sql | sort -u | wc -l β†’ 44; head -25 supabase/baseline.sql (inconsistent 001–090/001–078/058 statements).
  • ls e2e/journeys/chain-*.spec.ts | wc -l β†’ 21; ls e2e/journeys/*.spec.ts | wc -l β†’ 25.
  • grep -n ratio_w supabase/baseline.sql src -r; src/lib/ad-frame.ts:64-82.
  • grep -rln "SpeechRecognition" src β†’ ask-sheet.tsx.
  • grep -oE '20[0-9]{2}-[0-9]{2}-[0-9]{2}' CLAUDE.md | wc -l β†’ 61.
  • Path existence check over every backticked src/…, scripts/…, docs/… path in the five main docs: all resolve except retired src/lib/plugin-auth.ts (correctly described as gone).

⚠️ Risks

#RiskSeverityEffort
D1Wrong fresh-deployment instructions: README and NEW_DEPLOYMENT say the baseline is 001–061 and to run every later migration; the baseline already contains up to 092 (except 091). Re-running data migrations (e.g. 062, 064) on an already-seeded schema relies on each being idempotent, which is claimed but not verified for all. A new deployment could be mis-built or silently miss 091.🟠 HighS
D2No working vulnerability-disclosure channel (security@example.com) and a stale statement that a security migration is unrun β€” misleads researchers and auditors.🟠 HighS
D3No incident / operations runbook while there is also no monitoring or alerting; a new team would discover outages from users.🟠 HighM
D4Documentation drift with no automated check (counts, table lists, cron count, migration status, one undocumented route); readers cannot tell which statements are current.🟑 MediumM
D5Key-person and tool dependency in the docs: handover process built around one owner, AI sessions and an external claude.ai board / comment ledger; product direction held outside the repository.🟑 MediumM
D6Migration register only in CLAUDE.md prose, for possibly several deployments, with contradictions (088 "not run" yet folded into baseline).🟑 MediumS
D7High reading cost: dense narrative, private vocabulary and AI-agent instructions mixed with human documentation slow onboarding.βšͺ LowM

βœ… Recommendations

#RecommendationPriorityEffort
1Correct the onboarding path in README.md and docs/NEW_DEPLOYMENT.md: baseline contents (001–090, 092), then exactly which migrations to run (091); fix the baseline header's internal contradictions; remove "040 stays unrun".🟠 HighS
2Replace the placeholder security contact; update SECURITY.md scope notes to reflect 040 applied; add a security.txt.🟠 HighS
3Write an operations runbook: deploy/rollback, migration procedure, backup/restore (and test one), cron failure, Resend failure, Supabase outage, who to call. Pair with minimal monitoring.🟠 HighM
4Create a per-deployment environment matrix (region, plan tier, migrations applied with date, env vars set, cron secret set) outside CLAUDE.md, generated from scripts/migrations-applied.sql output.🟠 HighS
5Add an ER diagram and data dictionary generated from supabase/baseline.sql, marking legacy/orphaned tables and enum values.🟑 MediumS–M
6Document the /cap route; extend scripts/harness-contract.js (or a new test) to fail when a route file is absent from docs/API.md; consider generating an OpenAPI description from route validators.🟑 MediumM
7Remove counts and "verified on " figures from prose docs or generate them; refresh ARCHITECTURE.md §2, §5, §8 and CLAUDE.md (journeys, CI, 088).🟑 MediumS
8Split human-facing documentation from AI-agent instructions; move decision history into dated ADRs and keep ARCHITECTURE.md as current state only. Index all live docs in docs/README.md.βšͺ LowM
9Bring externally held product-direction, compliance-posture and open-decision records into the data room or repository.🟑 MediumS