Skip to content

Development Governance Overview

How the mcc-systems governance model works and why it is built the way it is. Every mechanism is described along with the failure mode it addresses and the protection it provides.

Understanding the rationale matters for anyone working in the codebase. Each rule exists for a reason, and knowing the reason makes it easier to apply the rule correctly in situations not explicitly covered, and harder to accidentally bypass a protection that looks like unnecessary overhead.


The central design principle: plan before execute

The workflow separates two distinct activities: planning (Claude.ai) and executing (Claude Code). Claude.ai reads the codebase, traces dependencies, checks for regressions, verifies against reference documents, and produces step-by-step instructions with explicit constraints. Claude Code executes those instructions, one step at a time, and reports back.

This separation means every change is analysed and reviewed before it is made. The governance happens in the planning phase. By the time Claude Code touches a file, the risks have already been identified and the instructions already account for them.

A practical consequence: none of this requires active management during a session. The regression checks, dependency tracing, documentation updates, file size verifications, and diff checks all happen automatically as part of the workflow. The developer's attention stays on the business problem.


CLAUDE.md: standing instructions for Claude Code

CLAUDE.md in the repo root is the single instruction file that Claude Code reads at the start of every session. It is the mechanism that delivers the governance model to Claude Code at runtime — without it, the rules exist only in Claude.ai and never reach the tool that executes code.

CLAUDE.md defines: monorepo structure and file locations, the default environment (dev), the one-step-at-a-time workflow with report-back gates, regression prevention requirements, file size enforcement rules, database change management rules, pricing integrity rules, portal isolation rules, and pointers to every reference document Claude Code must consult.

There is only one CLAUDE.md — in the repo root. It covers both apps. No app-level CLAUDE.md files exist, because splitting it would risk the two copies diverging.


Regression prevention

This is the largest and most important category. Most of the governance model exists, in one way or another, to prevent changes from breaking things that were already working. This is the hardest problem in software development — not building new features, but ensuring new features don't silently damage existing ones.

Read project state and reference documents before any work begins

Every Claude Code instruction file begins with a mandatory step: read _project-state.md and any relevant docs/ reference documents for the functional area being modified, before making any changes.

Without this, Claude Code begins each session with no knowledge of recent decisions, constraints discovered in previous sessions, frozen files, or design choices already made. It will repeat solved problems, undo recent work, or make decisions that contradict the current architecture. This step gives the AI accurate institutional memory before it writes a single line.

End-to-end flow tracing

Before any fix or feature is proposed, the full flow is traced end-to-end: frontend components, Edge Functions, hooks, types, utilities, and any downstream consumers of whatever is being changed.

Symptoms and causes are often in different files. A bug visible in a React component may originate in an Edge Function's data shape. Fixing the symptom without understanding the cause produces fixes that appear to work but break something else further along the chain.

Downstream dependency identification

Before any code change, every file that will be modified is identified alongside every file that imports, consumes, or depends on what is being changed. If a file hasn't been read, no confidence can be justified that it won't be broken.

Changes that seem isolated rarely are. A function signature change, a data shape adjustment, or a narrowed conditional can silently break callers that weren't considered. This check makes the full scope of every change explicit before anything is touched.

Reference document check

Before modifying any area covered by a reference document in docs/live/, that document is read and the proposed change is verified against every stage and scenario it describes. The contract lifecycle document, for example, must be read before touching any proposal, lock, unlock, blur overlay, banner, or signing behaviour. Any change that breaks the behaviour documented in docs/live/ is treated as a regression, regardless of whether the new behaviour seems reasonable in isolation.

Reference documents capture intended behaviour, design decisions, and known edge cases that aren't visible from reading the code alone. Without reading them, it's easy to "fix" something that was working correctly, or introduce a change that is consistent with one stage of a workflow but silently breaks another.

Flagging functional areas with no reference document

When work touches a functional area with no reference document in docs/, this is flagged explicitly, and a recommendation is made about whether one should be created before proceeding.

If no document exists, there is no authoritative baseline to verify against. Creating the document first means the intended behaviour is captured before changes are made — so there is something to check the new code against.

Explicit statement of what was and wasn't verified

When no reference document exists for an area being changed, the planning step explicitly states what existing behaviour has been verified, and what could not be confirmed as safe.

"This should be fine" is not a verification. Explicit acknowledgement of uncertainty makes it clear where risk is concentrated, so a decision can be made about whether to accept it or investigate further. Nothing is silently assumed to be safe.

Claude Code is told explicitly what must not change

Every instruction file explicitly states which files and behaviours must not be affected. Claude Code does not infer constraints from context.

Claude Code will optimise for completing the described task. Without explicit constraints, it may refactor, reorganise, or "improve" things outside the scope of the brief — with good intentions and bad outcomes. Explicit boundaries prevent this.

Final regression check after instructions are written

After writing a Claude Code instruction file, a final check is performed: for every file being modified, the question is asked — what else uses this file, this function, this data shape, or this condition? If that question can't be answered with confidence, the missing files are requested before the instructions are finalised.

Regression risk is assessed before execution, not discovered after.

Diff verification on every file rewrite

Every time a new version of a file is produced, a diff against the previous version is performed. The changes are listed, unintended changes are confirmed absent, and any removed comments or code not explicitly discussed are flagged.

Full file rewrites are the most common way to silently lose existing functionality. This check makes the guarantee explicit: only what was asked for changed.

Legacy frozen files are explicitly protected

A defined set of legacy files are under hard freeze and must never be modified — including Contract.tsx, ContractClauses.tsx, TenderResponse.jsx, and related files. This constraint is stated explicitly in every instruction that touches adjacent code.

These files support live client-facing contracts with legal and commercial significance. The risk of unintended side effects outweighs any potential benefit of modifying them.

Intentional decisions documented to prevent "fixes"

Decisions that look like bugs but are intentional are explicitly documented — for example, staleTime: 0 on the BMS QueryClient, 22 hardcoded legacy tender redirect routes, accepted file size overrides, and portal URL-based access control. These are recorded in docs/admin/audit/accepted-exceptions.md, and automated checks are configured not to flag them.

Without this documentation, a future session will identify these as apparent problems and fix them. The fix breaks real behaviour. Documentation turns an invisible trap into a clearly marked decision.

Automated nightly health check and weekly AI review

Two automated checks run on GitHub Actions to catch problems early.

The nightly health check runs at 3am UTC every day. It is fully deterministic — no AI involved. It checks:

  • File sizes against enforced limits
  • Forbidden patterns: unguarded console.log, hardcoded emails, hardcoded API keys
  • All three builds (BMS, Portal, TypeScript)
  • Migration files against conventions: RLS enabled, timestamps, triggers, trigger naming
  • Duplicate constants
  • Bundle sizes against baselines (flagging growth beyond 20%)
  • Front matter conventions: bans status: in docs/user/ pages (prevents silent MkDocs nav icons)
  • Docs index integrity: ensures every doc in scope is indexed, all indexed paths exist, all tags are valid
  • Production sync: whether all migrations have been applied and all Edge Functions are deployed

If anything fails, the GitHub Action goes red and sends a notification. Reports are saved to docs/admin/audit/health-reports/.

The weekly AI review runs Monday at 4am UTC. It collects the week's nightly reports, the repo structure, top files by size, and the enforcement rules, then sends them to the Claude API for architectural review. It looks for things the nightly check can't catch — architecture drift, files approaching size thresholds, inconsistencies between apps, and trends across the week. If it finds must-fix items, it creates a GitHub Issue.

Both checks can also be run manually — the nightly check via npm run health-check from the repo root, and either check from the GitHub Actions tab.

Regressions that accumulate gradually are caught automatically. The system monitors itself without any human effort.

Full detail: docs/admin/automated-health-check.md

Weekly documentation review

A third automated check runs every Sunday at 4am AEST / 5am AEDT (Saturday 6pm UTC). It scans reference documentation against current source code using the Claude API to find accuracy problems — statements contradicting code, stale file paths, internal contradictions, and missing file references.

Documentation coverage (ensuring new features have reference docs) is not handled by this scanner. It's enforced via the development workflow — every Claude Code instruction file includes a documentation checkpoint that writes or updates reference docs as part of the feature.

The scan maintains a baseline of open issues in docs/admin/audit/doco-reports/baseline.json. Weekly runs are incremental — only re-checking docs affected by the last 7 days of changes. If new issues are found, the GitHub Action creates an Issue with the documentation label.

This complements the nightly health check (structural and deployment issues) and the weekly AI review (architectural drift) by catching a class of problem neither can detect: documentation that has drifted from the code it describes.

Full detail: docs/admin/automated-doco-review.md

Automated test suite

A test suite of 442 tests across 38 files covers all three codebases (BMS, client portal, Edge Functions). Unit tests (421 tests, 29 files) verify pricing calculations, access control, proposal/contract lifecycle rules, date formatting, and Edge Function handler behaviour — they run on every push to GitHub via test.yml. Integration tests (21 tests, 9 files) run the real operation code against the dev Supabase database to verify multi-table orchestration flows and the Edge Function date formatting pipeline — they run on every push to master, nightly at 3am AEST, and on manual dispatch via test-integration.yml.

The tests are a mechanical regression defence — they catch broken behaviour automatically, without relying on anyone remembering to check a reference document or manually test an affected flow. They complement the nightly health check (which catches structural and deployment issues) and the weekly AI review (which catches architectural drift).

Full detail: Automated testing

Timezone governance

All date/time formatting across the BMS, client portal, and Edge Functions is locked down to centralised utility files that format in the configured timezone (Australia/Sydney). This is enforced at multiple layers: ESLint no-restricted-syntax rules fail the BMS build if banned date formatting patterns are used outside the utility file; ~153 unit tests across 3 utility files verify correct output across DST transitions, midnight boundaries, and edge cases; an Edge Function integration test verifies the full getTimezone() → format pipeline end-to-end; a weekly AI review scanner greps for banned patterns across all source files; and CLAUDE.md rules instruct CC to use the utility files for all date formatting.

Full detail: docs/live/date-time-handling.md


Code integrity and file quality

File size limits with mandatory verification after every code-modifying step

Every file has a 300-line default limit, with specific overrides documented in docs/admin/audit/file-size-limits.json. After every step that creates or modifies source files, Claude Code checks the line count of every file touched and compares it against its limit. If any file exceeds its limit, it stops and reports back rather than continuing.

Large files are harder to edit accurately, more likely to contain duplicated logic, and more likely to produce regression bugs. Critically, this check happens after every step — not once at the end — so breaches are caught before they compound.

File splitting decisions made collaboratively

When a file size limit is breached, the decision about whether and how to split is made collaboratively between Glenn and Claude.ai — not delegated to Claude Code. Specific principles govern when splitting genuinely reduces complexity versus when it just spreads tightly coupled code across multiple files.

Automatic splitting can produce worse outcomes than a large file. Fragments that require constant cross-referencing, hooks that close over half the parent's state, components with many props threaded from the parent — these are harder to work with, not easier. The decision stays with humans.

Structural patterns specified explicitly in instructions

When Claude Code is instructed to create new pages or components, the required structural pattern is stated explicitly, with the exact reference file named. "Follow existing patterns" is never used.

Abstract instructions produce inconsistent results. Claude Code defaults to bare HTML or its own inferred structure, which rarely integrates correctly with shared layout components. Named reference files produce consistency.

New record creation pattern enforced

New record creation must never use a form-based component. Instead, a blank record is silently inserted via the database client and the user is immediately redirected to the edit page.

Inconsistent creation patterns produce inconsistent UX and inconsistent data. Enforcing a single pattern means every new record follows the same flow, with no risk of half-completed form submissions creating partial records.

Dashboard isolation

The dashboards section in the BMS (src/resources/dashboards/) is isolated from the core BMS by strict rules enforced at multiple levels:

  • Dashboard code can read from any table but can only write to dashboard_* tables
  • Dashboard code cannot import from other resource folders — enforced at build time by ESLint
  • Dashboard code cannot modify files outside its own directory, with three specific exceptions for routing and navigation

These rules are enforced automatically by ESLint at build time, so violations fail the build rather than silently entering the codebase.

This isolation means Jordan can build dashboards with full autonomy without any risk of breaking the core BMS or Client Portal. It is a deliberate architectural boundary, not a convention that relies on discipline to hold.

Full detail: docs/admin/dashboard-development-guide.md


Database and deployment safety

All database changes via migration files

Every change to the database — schema changes, reference data, seed data, data fixes — must be captured in a migration file in the repository. Direct writes via the Supabase SQL Editor, Dashboard, or any other tool are prohibited.

Changes made directly in the database are invisible to version control. They cannot be reviewed, reversed, or replicated to another environment reliably. If the database is ever reset, direct changes are lost. Migration files ensure every change is tracked, reproducible, and survives environment resets.

For a detailed explanation of the two environments and why migration files matter, see Development environment & database change management. For migration and schema conventions, see docs/admin/migration-schema-conventions.md.

New table requirements

Every new table must include: created_at and updated_at timestamps, a trigger to auto-update updated_at on every row change, row-level security enabled, and an auth policy. Trigger functions use the set_ prefix. The nightly health check enforces these requirements automatically — a new table that doesn't meet the checklist fails the build.

These requirements are not optional conventions. They exist because tables created without them have historically caused silent failures in auth-protected queries and stale data bugs that are difficult to trace.

No hardcoded UUIDs in migration WHERE clauses

Migrations that target specific rows must identify those rows using stable natural keys — name, code, or another column whose value is identical across environments. UUID-based targeting is prohibited.

Dev and production environments generate different UUIDs. A migration written with a dev UUID will silently do nothing on production, with no error message to indicate why.

Edge Functions deploy to dev by default

All Edge Function deployments in Claude Code instructions use the dev project reference by default. Production deployment requires explicit instruction.

An untested Edge Function deployed to production can break the live client portal immediately. The dev-first default means every deployment is tested in isolation before it reaches production.

No commit, push, or production deployment by Claude Code

Claude Code is never instructed to commit to Git, push to GitHub, or deploy to production. Build steps and dev Edge Function deployments are included. Production deployment is always a deliberate, human-initiated action.

This keeps a human decision point between "code was written" and "code is live." Autonomous commits bypass the review that happens at each report-back stage.

Production deployment safety nets

Production deployment has multiple layers of protection. Database migrations deploy via a PowerShell script (deploy-prod.ps1) that Glenn runs manually — there is no automated path to production for schema changes. Edge Functions deploy via a separate script (deploy-edge-prod.ps1) that updates a deploy manifest, creating a record of what is deployed and when. The nightly health check then verifies that production is in sync with the repo — flagging any unapplied migrations or outdated Edge Functions so drift is caught immediately.

These layers mean that deploying to production is always a deliberate sequence of human actions with a verification step after, not a single command that can be run accidentally.

Full detail: docs/live/deployment-safety-nets.md

Critical deployment flags applied automatically

Required flags such as --no-verify-jwt are included in every relevant deployment instruction automatically.

This project uses URL-based access control, not Supabase Auth. If JWT verification is enabled, every Edge Function call is rejected. Including this flag automatically means it's never accidentally omitted.

GitHub identity never changed

Two GitHub accounts are configured with SSH aliases and per-repo identity. Claude Code is never instructed to change remotes or git identity.

Commits attributed to the wrong account corrupt the audit trail. Identity stability ensures every commit is reliably attributed without any manual configuration.


Oversight and review

Discrete steps with report-back gates

Every instruction file is broken into discrete steps. Each step ends with a requirement for Claude Code to stop, report back, and wait for confirmation before proceeding to the next step.

If Claude Code completes all steps in one pass and something goes wrong midway, it can be very difficult to identify where the mistake occurred — and later steps may have built on top of the error. Report-back gates catch mistakes at the step where they happen.

Instructions in downloadable files, reviewed before pasting

All Claude Code instructions are provided as downloadable files. Glenn reads them before pasting into Claude Code.

This keeps a human review point between planning and execution. If something looks wrong or contradicts something known about the current state, it can be caught before Claude Code acts on it.

Report-backs formatted for reliable copying

For every report-back step, Claude Code is instructed to format its entire response as a code block, producing a copy button in the VS Code extension interface.

Glenn relays Claude Code's reports to Claude.ai for review. Accurate, complete copying is essential — the code block format makes this reliable without any extra effort.


Institutional memory and documentation

_project-state.md updated after every session

Every Claude Code instruction file ends with a mandatory step: update _project-state.md to reflect what was completed — schema changes, new files, decisions made, design choices.

The state file is what gives the AI accurate context at the start of every session. Keeping it current is what makes that context reliable — and it happens automatically, every session.

State file entries document why, not just what

State file entries must explain why a change was made — the problem being solved, why the solution works the way it does, and any design choices — not just list what files changed.

A list of changed files has no diagnostic value months later. The "why" is what allows any future reader to understand whether a behaviour is an intentional design decision or an incidental side effect, and whether changing it would be safe.

Monthly state file rollover

At the end of each month, _project-state.md is archived with a date-stamped filename and a fresh file is started.

A state file that grows indefinitely becomes too large for effective use. Rolling it over monthly keeps the active file focused on recent and current work, while the full history remains accessible in the archive.

Structured documentation directories

Documentation is organised into directories with clear, distinct purposes. The deciding factor is audience and intent:

  • docs/live/ — Feature documentation for built and deployed features. The primary regression defence. Claude Code must read the relevant doc before modifying files in that area.
  • docs/admin/ — Development governance, conventions, audit config, and reports.
  • docs/user/ — Human-readable documentation for Jordan, Gian, and future staff.
  • docs/plans/ — Living project plans for multi-session bodies of work.

Without structure, documentation is unreliable — it's unclear whether a document describes current behaviour or an earlier plan. The directory structure makes the purpose and reliability of any document immediately clear from its location.


Summary

Every mechanism above was introduced in response to a real failure mode, a real risk, or a real inefficiency encountered during development. None are theoretical.

Regression prevention is the thread running through most of them. The consistent experience of working within this governance model is a high degree of confidence that new work won't break existing work — because every change has been traced, verified, and constrained before Claude Code acts on it.

The mechanisms are also designed to be self-operating. The regression checks, the dependency tracing, the documentation updates, the file size verifications, the diff checks — all of it happens automatically as part of the workflow. The developer's attention stays where it is most valuable: on the business problem.