RUL-022 — No implementation dispatch without a ratified design artifact
Ruling
The workflow is design → contract diagram → generate → fill in → test, and it
is not optional. An implementation subagent (builder, wirer, refactorer)
may only be dispatched when one of these holds:
- the brief names a design contract under
plans/contracts/that exists on disk; or - the brief names a
ConstructionArtifactthat the SPEC-033 B8 DoR gate (scripts/factory_decision.py decide) exits 0 on; or - the brief carries an explicit
DESIGN_WAIVER: <reason>line.
Threshold agreed with Mohamed, 2026-07-27: the gate binds any dispatch that creates a new module or changes a public signature. Pure edits in place, mechanical fixes and bounded lint/type cleanup are waivable — but the waiver is declared in the brief and therefore visible in the transcript, never silent.
Design and inspection agents (analyst, auditor, reviewer, test-writer,
Explore, Plan) are never gated: they are what produces the artifact, and
gating them would deadlock the workflow.
Evidence
The machinery to do this correctly was already complete and simply went unused:
scripts/factory_decision.py decide— SPEC-033 B8 decision phase + DoR gate (factory/decision/phase.py:run_decision_phase,assumptions/dor.py:check_dor), exit 0 ready / exit 1 blocked, with blocking items from the shape, C4, C3, assumption, residual and anchor detectors.scripts/factory_conformance.py— B2 AST≡design conformance (ADR-0007/0008).- The AST toolkit generators:
gen-skeleton,gen-protocol,gen-dto,gen-tests,pattern,interface. - The
analystagent, whose stated job is a TRACED contract diagram plus a TDD test plan "that deterministic generation (gen-skeleton) can turn into ~half the code."
Nothing forced a caller through any of it. On 2026-07-27 two implementation
subagents were dispatched straight from prose briefs with no contract. Both
hand-wrote code that generation would have emitted structurally correct, and
both then spent their run chasing the consequences — unresolved imports
(scripts.check_worktree_envs, tests.plugins.git_sentinel), unused symbols,
and an object-vs-WatchTargets type error — against heavy serial gates. Cost:
~262K and ~343K subagent tokens, 106 and 148 tool calls.
The enforcement gap was structural, not a lapse of attention: every other
standing rule in this repo is backed by a PreToolUse hook (no-xdist.sh,
no-doubles-py.sh, no-banned-deps.sh, force-test-observation.sh), and every
one of them guards Bash, Write or Edit. None guarded Agent — the one
tool that dispatches implementation work.
Enforcement
- hook .claude/hooks/require-design-before-build.sh
Verification
.claude/hooks/require-design-before-build.sh is registered PreToolUse on
matcher Agent in .claude/settings.json. It reads the dispatch JSON on stdin
and exits 2 when subagent_type is builder/wirer/refactorer and no
contract path resolves, no DoR-passing artifact is named, and no
DESIGN_WAIVER: <reason> line is present — printing the remediation (dispatch
analyst for plans/contracts/<slug>.{contract.json,mmd}, then gen-skeleton,
then re-dispatch). It exits 0 silently otherwise.
Malformed input, absent fields and a non-Agent tool_name all ALLOW: a hook
that crashes must not become a hook that blocks all work. factory_decision.py
is consulted only when the brief actually names an artifact file, never
speculatively, so the hook stays in the low-millisecond range on every dispatch.
Binding contract: plans/contracts/rul-022-design-gate.contract.json.
Tests: tests/scripts/test_require_design_before_build.py.