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:

  1. the brief names a design contract under plans/contracts/ that exists on disk; or
  2. the brief names a ConstructionArtifact that the SPEC-033 B8 DoR gate (scripts/factory_decision.py decide) exits 0 on; or
  3. 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:

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

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.