New Capability: Build Verification Gate

New Capability: Build Verification Gate

Date: March 15, 2026 Origin: Corrective Action — recurring pattern of running 7-minute full website builds for SSR-only changes, flagged by Chris as a persistent failure across many sessions Impact: Structural enforcement prevents unnecessary builds; saves 5-7 minutes per SSR-only code change Resolves: Leadership/reports/2026-03-15-corrective-unnecessary-full-builds.md


What Was Built

A PreToolUse hook on Bash that intercepts full website build commands and surfaces a decision gate before execution. When V (or any agent) attempts to run pnpm build or npm run build targeting apps/website/, the hook fires and presents the SSR vs static decision matrix. The operator sees the gate, determines whether the change affects static content, and either proceeds with the full build or switches to tsc --noEmit (~15 seconds).

This is the second structural enforcement hook in the system. The first — the Dewey Decimal lookup hook — fires on Edit|Write and surfaces codebase classification context. Both follow the same principle: behavioral rules fail when they depend on the operator remembering to follow them. Structural gates force the decision point into the workflow itself.

The hook is one component of a four-layer prevention system built to resolve the corrective action:

  1. Hook (structural gate): Intercepts build commands, surfaces decision matrix
  2. Infrastructure Trigger: vf-self-correction.md entry catches the behavior pattern
  3. Anti-Rationalization: Counters "better safe than sorry — run the full build"
  4. Critical Lesson + Build Notes: MEMORY.md now distinguishes SSR type-check from full static build

Infrastructure Changes

Change Before After
PreToolUse hooks 1 hook (Dewey on Edit|Write) 2 hooks (+ Build Gate on Bash)
vf-self-correction.md Infrastructure Triggers 7 triggers 8 triggers (+ full build for SSR)
vf-self-correction.md Verification Rationalizations 5 entries 6 entries (+ "better safe than sorry")
MEMORY.md Build Notes "Website build: ~5-6 minutes" (neutral) Explicit SSR/static distinction with tsc --noEmit alternative
MEMORY.md Critical Lessons No build verification rule Full build prevention rule with CAR reference

Implementation

File Purpose
.claude/hooks/build-check.sh PreToolUse hook — intercepts website build commands, surfaces decision gate
/mnt/d/.claude/settings.local.json Hook registration — Bash matcher added to PreToolUse array
skills/enforcement/vf-self-correction.md Infrastructure Trigger + anti-rationalization entry
memory/MEMORY.md Critical Lesson + rewritten Build Notes
agents/instruction-optimizer/data/incident-log.json Incident logged for pattern analysis
Leadership/reports/2026-03-15-corrective-unnecessary-full-builds.md Corrective Action Report (root cause analysis)

Usage

The hook is automatic. No invocation needed. It fires whenever a Bash command matches a website build pattern.

What triggers it

# All of these trigger the gate:
cd apps/website && npx pnpm build
cd apps/website && npm run build
npx pnpm build                          # bare build (could be in website dir)

What stays silent

# These do NOT trigger the gate:
cd apps/portal && npx pnpm build         # portal builds are unaffected
cd apps/website && npx tsc --noEmit      # type check — correct SSR approach
git status                                # non-build commands
node scripts/hubspot/api.js              # unrelated bash

The decision it presents

===========================================================
  BUILD VERIFICATION GATE
===========================================================

  STOP. Do ANY changed files affect static content?

  YES (full build needed):
    - getStaticPaths changes
    - Sanity data queries
    - Build config (astro.config.mjs)
    - New static routes

  NO (type check only — 15s instead of 7min):
    - SSR pages (prerender = false)
    - Command Center / admin pages
    - API routes
    - Component-only changes

  SSR pages are built by Vercel on-demand.
  They are NOT in the static build output.

  For SSR-only changes, use instead:
    cd apps/website && npx tsc --noEmit

  Decision matrix: skills/build-verification/SKILL.md
===========================================================

The SSR verification path

# For Command Center, admin, or any prerender=false page changes:
cd /mnt/d/Projects/value-first-operations/apps/website && npx tsc --noEmit
# ~15 seconds. Catches type errors. Then commit and push.

Leader Applications

V (Operations)

Primary beneficiary. V builds Command Center pages, agent visualizations, and admin interfaces — all SSR. The gate prevents V from defaulting to full builds on every commit. The 4-tier decision matrix (skills/build-verification/SKILL.md) becomes structurally enforced rather than optional reference material.

This also establishes a pattern: when a behavioral rule fails repeatedly, escalate to a structural hook. The Dewey hook proved this works for file classification. The build gate proves it works for operational decisions.

Sage (Customer)

No direct application. Sage does not execute website builds.

Pax (Finance)

No direct application. Pax does not execute website builds.


Dependencies

Dependency Status Notes
Node.js (for JSON parsing in hook) Confirmed Used to extract command from tool input
/mnt/d/.claude/settings.local.json hook registration Confirmed PreToolUse Bash matcher configured
skills/build-verification/SKILL.md Confirmed Referenced in hook output as decision matrix source
Unix line endings on hook script Confirmed Fixed CRLF from Write tool; sed -i 's/\r$//' applied

Verification

# Should fire the gate:
echo '{"tool_input":{"command":"cd apps/website && npx pnpm build"}}' | \
  /mnt/d/Projects/value-first-operations/.claude/hooks/build-check.sh

# Should stay silent:
echo '{"tool_input":{"command":"git status"}}' | \
  /mnt/d/Projects/value-first-operations/.claude/hooks/build-check.sh

echo '{"tool_input":{"command":"cd apps/portal && npx pnpm build"}}' | \
  /mnt/d/Projects/value-first-operations/.claude/hooks/build-check.sh

Both tests pass. Hook fires on website builds, stays silent on everything else.


Design Principle

Documentation alone does not change behavior. The build-verification skill existed since its creation and explicitly documented "Don't: Run full build for every change" as an anti-pattern. It was never consulted. Enforcement triggers in vf-self-correction.md reduce the failure rate but still depend on the operator reading and internalizing them at session start.

Structural hooks eliminate the dependency on memory. The Dewey hook doesn't ask V to remember to check the codebase index — it surfaces the classification automatically on every edit. The build gate doesn't ask V to remember the 4-tier decision matrix — it surfaces the decision automatically on every build attempt.

Rule: If a behavioral correction fails twice, escalate to a structural hook.