Date: 2026-07-07 Status: accepted Deciders: Thibault Souris (maintainer) Method: decision-loop — reality-check against a competitor code benchmark (BMAD, Spec Kit, OpenSpec, Spec Kitty), challenge, durable position
Context
runward check --strict (ADR-0001) verifies that every CRITICAL/HIGH rule mapped to a phase is accounted for in that phase's conformance manifest. A code-level benchmark of the four spec-driven competitors surfaced a real weakness by comparison: Spec Kitty invests explicitly in making its deterministic gate hard to neutralize (a non-vacuity tactic, a self-mutation test, a shrink-only allowlist ratchet), while runward's gate can pass vacuously. Three trivial gaming vectors exist today:
- Strip the mapping. Remove the
phases:frontmatter from a phase's rules and the expected set collapses to zero, so--strictturns green with nothing checked. - Empty n/a. Mark every rule
n/awith a one-word or placeholder reason; the gate accepts it. - Silent regression of the guard. Nothing proves the gate still catches a real violation after a refactor.
A gate that can be neutralized in one edit is not a gate. Since runward's central claim is precisely that it has the per-rule conformance gate no competitor has, that gate must resist obvious gaming. The decision is taken at the tooling boundary (the check command and the rule schema), never in a mission's domain, and it must stay deterministic with no LLM in the gate path.
Decision
Add deterministic non-vacuity guards to --strict, keeping the invariant intact (presence of a traced decision, never code quality; zero LLM):
- Routed-count floor. A pinned per-phase minimum of mapped CRITICAL/HIGH rules (
EXPECTED_MAPPED, e.g. architect ≥ 5, floor ≥ 10, govern ≥ 7). If the shipped rule set maps fewer than the floor,--strictfails anddoctorflags it. Lowering a floor is a visible, tracked edit — itself an ADR-worthy change — so the mapping cannot be silently stripped to pass. - Non-trivial
n/a. Ann/areason must be more than a placeholder: non-empty, above a minimum length, and not a bracketed template token. A lazy blanketn/ano longer passes. - Self-mutation test. The suite plants a real violation and asserts the gate catches it (red), pinning the guarantee that
--strictstill bites after any refactor. This formalizes what the smoke test already does into a named non-vacuity guarantee.
Explicitly out of scope: a shrink-only allowlist ratchet — runward has no violation-allowlist mechanism to ratchet, so the attack it defends against does not exist here. Noted, not built.
Alternatives discarded
- Trust the operator to notice a stripped mapping. Defeats the gate's purpose; the whole point is that neutralizing it must be loud, not silent.
- An LLM check of whether an
n/areason is legitimate. Violates the zero-LLM invariant of the gate and reintroduces the non-determinism ADR-0001 rejected. Legitimacy of ann/astays the operator's judgment at the gate; the tool only enforces that a real reason is present. - Shrink-only allowlist ratchet (Spec Kitty). Not applicable: no allowlist exists to ratchet. Adopt the principle (non-vacuity), not this specific mechanism.
Consequences
- Positive. The gate resists the three obvious gaming vectors; runward's differentiating claim ("the per-rule gate no one else has") is backed by a gate that is actually hard to neutralize.
- Negative, accepted. The routed-count floor must be updated when the mapping legitimately grows or shrinks — a deliberate, tracked edit (which is the point). A small maintenance surface on
check,doctorand the constants. - On other boundaries.
check --strictgains three deterministic guards;doctorgains a floor check; the smoke suite gains a self-mutation assertion. No change to the mission domain or to the zero-LLM invariant.
Reevaluation trigger (mandatory, dated)
Reopen if any of:
- (a) a new gaming vector is observed that these guards miss (e.g. a way to satisfy the manifest without a real decision);
- (b) the routed-count floor produces false positives on a legitimate mapping change often enough to be edited reflexively — a sign it should be derived, not pinned;
- (c) the
n/aminimum-length heuristic rejects genuine short reasons in practice.
Trigger set on: 2026-07-07 · Watched via: the conformance-gaming incident log and periodic review of the gate against new competitor hardening.
References
- ADR-0001 — the gate this hardens.
- Code benchmark of BMAD / Spec Kit / OpenSpec / Spec Kitty (2026-07-07) — Spec Kitty's
architectural-gate-non-vacuity.tactic.yamland shrink-only ratchet as the reference for hardening; its own audit notes most of those elements are aspirational, so the principle is adopted, not the unproven machinery. src/lib/conformance.ts,src/commands/check.ts,src/commands/doctor.ts— the surfaces this ADR touches.