πŸ” Source Control, CI/CD & Development Practices

πŸ“‹ Summary

The repository was supplied as a single squashed commit, so the actual history of how the software was built β€” branching, commit habits, code review, slowdowns β€” cannot be seen and must be requested. What the repository does reveal is a disciplined, well-automated local process: a single script runs six quality gates (tests, type-checking, linting, a confidentiality scrub, a route/test-harness contract check and a production build), and the same gates run in GitHub Actions on every push and pull request. The documented workflow, however, is trunk-based with changes merged straight to main by fast-forward, with no pull-request review step, and the process documents are written for AI coding "sessions" working under one owner's direction. There is no security or dependency scanning in the pipeline, no automated deployment or migration step visible in the repository, and no branch protection that the repository can evidence. For a buyer this means good automated hygiene but little evidence of independent human review.

🎯 Rating

🟑 ●●●○○ 3 / 5 β€” Amber. Strong, mechanically enforced quality gates and CI, offset by no evidenced code review, no security scanning, hand-applied migrations, and a history that cannot be inspected.

πŸ” Findings

Repository structure and organisation

AreaContentsAssessment
src/appNext.js App Router pages, API routes (83 route files), QA harness (src/app/qa)Conventional for Next.js [Observed]
src/libDomain logic and helpers, co-located *.test.tsClean separation of pure logic [Observed]
src/components, src/typesShared UI, generated DB types[Observed]
supabase/92 migrations, baseline.sql, RLS tests (supabase/tests/)[Observed]
e2e/Live-deployment specs, journey specs (harness), acceptance walk[Observed]
scripts/Gates, journeys runner, ops, scrub, harness contract, board tooling[Observed]
audits/Python UI audit scripts (contrast, a11y, tokens)[Observed]
design/, docs/, root *.mdDesign compliance notes, handover, API reference, architecture[Observed]

Organisation is coherent and follows framework conventions. One oddity: a production route tree also contains the test harness (src/app/qa, gated at runtime by NEXT_PUBLIC_QA=1) β€” see Module 9.

Branching model

  • Determined from history: [Unavailable] β€” one commit (3789df6, 721 files, 125,806 insertions); git rev-parse --is-shallow-repository β†’ false, so history was squashed deliberately rather than truncated by the clone.
  • Documented model: trunk-based with short-lived worktree branches, rebased on main and merged with git merge --ff-only then pushed directly to origin main; "Never force-push". [Observed] docs/HANDOVER.md lines 26–60.
  • SECURITY.md: "main only. There are no release branches or tags; every deployment builds from main." [Observed]

Commit hygiene

[Unavailable] β€” commit size, message quality, frequency, dormant periods and recent slowdowns all require the unsquashed history. The documented convention (HANDOVER.md) requires a fixed committer identity, two trailers supplied by "the session reminder", "reasons not sources" in messages, and no model names. [Observed] This convention indicates commits are authored by AI coding sessions under the owner's identity. [Inferred]

Evidence of code review

  • No PR template, CODEOWNERS, or review configuration in .github/. [Observed] ls .github β†’ workflows/ only.
  • Documented landing path bypasses pull requests (fast-forward merge to main). [Observed] HANDOVER.md.
  • Review appears to happen as owner inspection of a "build board" (screenshots published as a web page) and a "comment ledger", i.e. product/visual review rather than code review. [Observed] HANDOVER.md "Where things stand", "The board". [Inferred] that no second human reviews code.
  • Branch protection settings live in GitHub, not the repository. [Unavailable β€” requires GitHub repository admin access.]

CI/CD

StagePresent?WhereNotes
Installβœ… Yesci.ymlnpm ci --legacy-peer-deps (flag flagged in-file as a workaround to remove)
Typecheckβœ… Yesci.ymltsc --noEmit β€” passes locally (exit 0)
Unit testsβœ… Yesci.ymlVitest β€” 687/687 pass locally
Confidentiality scrubβœ… Yesci.ymlscripts/scrub.js β€” passes (715 files)
Route ↔ harness contractβœ… Yesci.yml125 handlers agree
Lintβœ… Yesci.yml0 errors / 0 warnings locally
Production buildβœ… Yesci.ymlPlaceholder Supabase env
Each gate reports independentlyβœ… Yesif: ${{ !cancelled() }}Good practice, deliberately chosen
Journey (browser) tests❌ No β€” local only (~25–30 min)scripts/journeys.shComment in ci.yml explains why
Coverage threshold❌ Noβ€”
Dependency / vulnerability scan❌ Noβ€”24 known vulns undetected by CI (Module 8)
SAST / secret scanning❌ Noβ€”
DeployNot in repoβ€”Presumably Vercel's Git integration [Inferred]; Vercel config not in repo
Database migrationsManualSQL Editor or scripts/ops.sh sqlCLAUDE.md records a migration found missing in production (035) and migrations "written and not yet run" (065, 088, 091)
Acceptance walk against live siteManual dispatchwalk.ymlWrites to the target site; correctly never on push

Workflow permissions are least-privilege (contents: read) and runs are de-duplicated with concurrency. [Observed] ci.yml.

Automated checks and bypassability

  • Local: npm run gates (scripts/gates.sh) runs six gates by exit code and stops on first red β€” explicitly designed after two incidents where a red gate was missed by piping through grep. [Observed] script header comment.
  • Custom static gates enforced through unit tests: src/lib/write-results.test.ts (every awaited write must read its result), src/lib/schema-columns.test.ts (every column the code names must exist in baseline.sql). These are unusually strong, project-specific guard rails. [Observed]
  • Bypass: because the documented flow pushes directly to main, CI is after-the-fact; whether main is protected so a red CI blocks deploy cannot be determined. [Unavailable β€” GitHub branch protection and Vercel "ignored build step" settings.] CLAUDE.md itself records "Three pushes to main sat red … on 2026-09-06". [Observed]

🧾 Evidence

  • git log --all --format=… β†’ single commit; git show --stat HEAD β†’ 721 files, 125,806 insertions.
  • git rev-parse --is-shallow-repository β†’ false.
  • Files: .github/workflows/ci.yml, .github/workflows/walk.yml, scripts/gates.sh, docs/HANDOVER.md (lines 1–62), SECURITY.md, CLAUDE.md ("Verification", "Migrations").
  • Local runs: npx tsc --noEmit (exit 0), npx eslint (exit 0), npx vitest run (687 passed), node scripts/scrub.js, node scripts/harness-contract.js.

⚠️ Risks

RiskSeverityEffort
No evidenced human code review; changes land directly on main🟠 HighS (process)
No dependency/SAST/secret scanning in CI🟠 HighS
Squashed history removes the audit trail of who changed what and when🟠 High (diligence)β€”
Manual, per-deployment migrations with a record of drift between code and database🟠 HighM
Browser journey suite not in CI; regressions in UI wiring are only caught if someone runs it locally🟑 MediumM
Process documentation is tailored to AI coding sessions (worktrees, ports, "session reminder") and to one owner's review style; a conventional team will need to re-establish its own workflow🟑 MediumS–M
--legacy-peer-deps workaround in CIβšͺ LowS

βœ… Recommendations

RecommendationPriorityEffort
Request the full, unsquashed git history (and GitHub PR/issue data) as a condition of diligenceP0β€”
Introduce PR-based flow with required review and required status checks on mainP1S
Add dependency scanning (Dependabot/Renovate + npm audit), CodeQL or Semgrep, and secret scanningP1S
Automate migrations (Supabase CLI) with a check that each deployment's schema matches baseline.sqlP1M
Run the journey suite in CI (nightly or on PR, sharded)P2M
Rewrite HANDOVER.md for a human team; keep AI-session specifics separateP3S