@event4u/agent-config 16.0.0 → 16.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. package/.augment-plugin/marketplace.json +3 -3
  2. package/.augment-plugin/plugin.json +1 -1
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/CHANGELOG.md +297 -137
  5. package/CONTRIBUTING.md +9 -0
  6. package/README.md +2 -2
  7. package/dist/agent-src/commands/analyze/inbox.md +26 -0
  8. package/dist/agent-src/commands/analyze/roadmap-repos.md +27 -0
  9. package/dist/agent-src/commands/challenge-me/closure.md +178 -0
  10. package/dist/agent-src/commands/challenge-me.md +9 -2
  11. package/dist/agent-src/commands/council/default.md +25 -5
  12. package/dist/agent-src/commands/feature/plan.md +28 -1
  13. package/dist/agent-src/commands/feature/roadmap.md +28 -1
  14. package/dist/agent-src/commands/implement-ticket.md +27 -0
  15. package/dist/agent-src/commands/jira-ticket.md +27 -0
  16. package/dist/agent-src/commands/pr/create.md +29 -0
  17. package/dist/agent-src/commands/pr/merge.md +60 -9
  18. package/dist/agent-src/commands/roadmap/ai-council.md +7 -1
  19. package/dist/agent-src/commands/roadmap/create.md +74 -27
  20. package/dist/agent-src/commands/roadmap/materialize.md +27 -0
  21. package/dist/agent-src/commands/roadmap/process-full.md +123 -18
  22. package/dist/agent-src/commands/team.md +22 -0
  23. package/dist/agent-src/contexts/authority/scope-growth-ownership.md +80 -0
  24. package/dist/agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +47 -0
  25. package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +44 -3
  26. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +15 -15
  27. package/dist/agent-src/contexts/execution/decision-closure-execution.md +93 -0
  28. package/dist/agent-src/contexts/execution/fix-loop-ladder.md +108 -0
  29. package/dist/agent-src/contexts/execution/plan-confidence-gate.md +4 -2
  30. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +75 -6
  31. package/dist/agent-src/guidelines/agent-infra/active-remediation-mechanics.md +57 -0
  32. package/dist/agent-src/guidelines/agent-infra/evaluator-independence-mechanics.md +102 -0
  33. package/dist/agent-src/guidelines/design-fidelity-routing.md +29 -0
  34. package/dist/agent-src/rules/autonomous-execution.md +15 -8
  35. package/dist/agent-src/rules/delegation-policy.md +23 -45
  36. package/dist/agent-src/rules/design-fidelity.md +32 -37
  37. package/dist/agent-src/rules/evaluator-independence.md +43 -49
  38. package/dist/agent-src/rules/test-first.md +41 -0
  39. package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +3 -3
  40. package/dist/agent-src/skills/ai-council/SKILL.md +11 -3
  41. package/dist/agent-src/skills/api-design/data/manifest.json +3 -3
  42. package/dist/agent-src/skills/database/data/manifest.json +4 -4
  43. package/dist/agent-src/skills/database/data/query-tuning.csv +3 -3
  44. package/dist/agent-src/skills/design-review/SKILL.md +50 -0
  45. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +14 -4
  46. package/dist/agent-src/skills/experiment-loop/SKILL.md +31 -1
  47. package/dist/agent-src/skills/roadmap-writing/SKILL.md +1 -1
  48. package/dist/agent-src/skills/storybook-workshop/SKILL.md +42 -3
  49. package/dist/agent-src/skills/threat-modeling/SKILL.md +9 -4
  50. package/dist/agent-src/skills/threat-modeling/data/manifest.json +4 -4
  51. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +37 -3
  52. package/dist/agent-src/templates/agent-settings.md +1 -1
  53. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  54. package/dist/agent-src/templates/roadmaps.md +188 -0
  55. package/dist/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +62 -2
  56. package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +1 -0
  57. package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +1 -0
  58. package/dist/cli-delegate/check_update_banner.js +40 -2
  59. package/dist/cli-delegate/chunk-4E2W63DA.js +335 -0
  60. package/dist/cli-delegate/chunk-5R7HOLAF.js +99 -0
  61. package/dist/cli-delegate/{chunk-IVBPRCQO.js → chunk-6KFEC3G7.js} +1 -1
  62. package/dist/cli-delegate/{chunk-2TAQ2K4V.js → chunk-6KM6ORRY.js} +55 -386
  63. package/dist/cli-delegate/{chunk-2XY7ILBT.js → chunk-FC75PGJE.js} +42 -2
  64. package/dist/cli-delegate/{chunk-GYC3VRYN.js → chunk-FXYUYU4N.js} +57 -13
  65. package/dist/cli-delegate/{chunk-55ACLDUE.js → chunk-GJCBB2UG.js} +168 -10
  66. package/dist/cli-delegate/{chunk-AK6HODNQ.js → chunk-HDVVGPQW.js} +873 -539
  67. package/dist/cli-delegate/{chunk-H32DGUJH.js → chunk-P6ZHP5W2.js} +1 -1
  68. package/dist/cli-delegate/{chunk-57PN4GYJ.js → chunk-RGNIWTEA.js} +1 -1
  69. package/dist/cli-delegate/chunk-ROYYTEZU.js +39 -0
  70. package/dist/cli-delegate/{chunk-3FKR64R5.js → chunk-UNCRJBT3.js} +31 -7
  71. package/dist/cli-delegate/{chunk-2DK2VJWG.js → chunk-WGXTVKCQ.js} +20 -6
  72. package/dist/cli-delegate/chunk-YDPILCOL.js +152 -0
  73. package/dist/cli-delegate/cmd_analyze_session.js +1 -1
  74. package/dist/cli-delegate/cmd_brand_status.js +1 -1
  75. package/dist/cli-delegate/cmd_conformance.js +90 -56
  76. package/dist/cli-delegate/cmd_doctor.js +7 -5
  77. package/dist/cli-delegate/cmd_explain.js +2 -2
  78. package/dist/cli-delegate/cmd_export.js +9 -7
  79. package/dist/cli-delegate/cmd_fleet.js +4 -2
  80. package/dist/cli-delegate/cmd_handoff.js +4 -4
  81. package/dist/cli-delegate/cmd_mcp_available.js +1 -1
  82. package/dist/cli-delegate/cmd_migrate.js +2 -2
  83. package/dist/cli-delegate/cmd_packs_active.js +2 -2
  84. package/dist/cli-delegate/cmd_preflight.js +4 -2
  85. package/dist/cli-delegate/cmd_prune.js +10 -8
  86. package/dist/cli-delegate/cmd_route_audit.js +2 -2
  87. package/dist/cli-delegate/cmd_route_explain.js +1 -1
  88. package/dist/cli-delegate/cmd_session_recycle.js +2 -2
  89. package/dist/cli-delegate/cmd_settings_get.js +28 -2
  90. package/dist/cli-delegate/cmd_settings_migrate.js +9 -7
  91. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  92. package/dist/cli-delegate/cmd_sync.js +10 -8
  93. package/dist/cli-delegate/cmd_uninstall.js +16 -13
  94. package/dist/cli-delegate/cmd_update.js +1 -1
  95. package/dist/cli-delegate/cmd_upgrade.js +1 -1
  96. package/dist/cli-delegate/cmd_validate.js +12 -10
  97. package/dist/cli-delegate/cmd_versions.js +1 -1
  98. package/dist/discovery/deprecation-report.md +1 -1
  99. package/dist/discovery/discovery-manifest.json +85 -38
  100. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  101. package/dist/discovery/discovery-manifest.summary.md +4 -4
  102. package/dist/discovery/dormancy-report.md +1 -1
  103. package/dist/discovery/orphan-report.md +1 -1
  104. package/dist/discovery/packs.json +10 -8
  105. package/dist/discovery/trust-report.md +3 -3
  106. package/dist/discovery/workspaces.json +8 -6
  107. package/dist/hooks/dispatch.js +1832 -1007
  108. package/dist/install/claudeRuleRewrite.js +14 -3
  109. package/dist/install/conflict.js +60 -10
  110. package/dist/install/conflictTracker.js +218 -0
  111. package/dist/install/fsPrimitives.js +54 -0
  112. package/dist/install/install.mjs +2007 -1481
  113. package/dist/install/manifestFiles.js +259 -0
  114. package/dist/install/preflight.js +14 -2
  115. package/dist/install/preserve.js +157 -0
  116. package/dist/install/recordedOwnership.js +132 -0
  117. package/dist/install/txlog.js +11 -2
  118. package/dist/mcp/registry-manifest.json +3 -3
  119. package/dist/mcp/server.json +2 -2
  120. package/dist/mcp/server.mjs +398 -39
  121. package/dist/router.json +1 -1
  122. package/dist/scripts/_lib/agent_settings.js +3 -2
  123. package/dist/scripts/_lib/fs_atomic.js +167 -0
  124. package/dist/scripts/_lib/installed_tools.js +460 -0
  125. package/dist/scripts/_lib/lean_projection_mode.js +3 -2
  126. package/dist/scripts/_lib/settings_renamed_keys.js +78 -0
  127. package/dist/server/routes/install.js +8 -0
  128. package/dist/server/routes/wizard.js +9 -3
  129. package/dist/server/schemas/settings.js +17 -5
  130. package/dist/shared/missionExecution.js +97 -0
  131. package/dist/ui/assets/{index-D0jaCRPM.js → index-DH1xc62v.js} +17 -17
  132. package/dist/ui/index.html +1 -1
  133. package/docs/MIGRATION.md +103 -0
  134. package/docs/contracts/settings-classes.md +26 -7
  135. package/docs/guidelines/agent-infra/active-remediation-mechanics.md +57 -0
  136. package/docs/guidelines/agent-infra/evaluator-independence-mechanics.md +102 -0
  137. package/docs/guidelines/design-fidelity-routing.md +29 -0
  138. package/package.json +1 -1
  139. package/src/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +62 -2
  140. package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +1 -0
  141. package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +1 -0
  142. package/src/config/agent-settings.template.yml +139 -27
  143. package/src/config/auto-rule-budget.json +16 -0
  144. package/src/config/ci-local-parity.yml +18 -5
  145. package/src/config/continuity-surface.json +21 -0
  146. package/src/config/gate-coverage.yml +146 -13
  147. package/src/config/gate-violation-baselines.json +6 -6
  148. package/src/config/hook-token-budget.json +2 -0
  149. package/src/config/loop-surfaces.yaml +215 -0
  150. package/src/config/platform-anchor.json +3 -2
  151. package/src/config/release-gate-locality.yml +11 -0
  152. package/src/config/routing-coverage-seed.json +18 -4
  153. package/src/config/rule-enforcement-baseline.json +0 -1
  154. package/src/install/claudeRuleRewrite.ts +16 -2
  155. package/src/install/conflict.ts +65 -9
  156. package/src/install/conflictTracker.ts +299 -0
  157. package/src/install/fsPrimitives.ts +54 -0
  158. package/src/install/manifestFiles.ts +312 -0
  159. package/src/install/preflight.ts +16 -2
  160. package/src/install/preserve.ts +205 -0
  161. package/src/install/recordedOwnership.ts +149 -0
  162. package/src/install/txlog.ts +11 -2
  163. package/src/install/types.ts +19 -4
  164. package/src/scripts/_cli/cmd_conformance.ts +88 -15
  165. package/src/scripts/_cli/cmd_doctor.ts +4 -3
  166. package/src/scripts/_cli/cmd_route_explain.ts +9 -2
  167. package/src/scripts/_cli/cmd_settings_get.ts +44 -0
  168. package/src/scripts/_cli/doctor_execution.ts +90 -0
  169. package/src/scripts/_lib/activation_payload.ts +247 -0
  170. package/src/scripts/_lib/agent_settings.ts +4 -2
  171. package/src/scripts/_lib/authority_path.ts +102 -0
  172. package/src/scripts/_lib/cascade_base.ts +94 -0
  173. package/src/scripts/_lib/changelog_eras.ts +7 -2
  174. package/src/scripts/_lib/continuation_ladder.ts +149 -2
  175. package/src/scripts/_lib/council_transport.ts +129 -0
  176. package/src/scripts/_lib/delivery_ready.ts +112 -0
  177. package/src/scripts/_lib/forge_protection.ts +267 -0
  178. package/src/scripts/_lib/hook_platform_keys.ts +27 -0
  179. package/src/scripts/_lib/json_python_parity.ts +127 -0
  180. package/src/scripts/_lib/lean_projection_mode.ts +14 -3
  181. package/src/scripts/_lib/loop_surfaces.ts +382 -0
  182. package/src/scripts/_lib/mission_record.ts +190 -0
  183. package/src/scripts/_lib/obligation_frequency.ts +217 -0
  184. package/src/scripts/_lib/obligations.ts +402 -0
  185. package/src/scripts/_lib/orchestration_record.ts +11 -20
  186. package/src/scripts/_lib/release_highlights.ts +199 -10
  187. package/src/scripts/_lib/release_holds.ts +493 -0
  188. package/src/scripts/_lib/release_migration_gate.ts +184 -0
  189. package/src/scripts/_lib/rides_along.ts +102 -0
  190. package/src/scripts/_lib/settings_renamed_keys.ts +82 -0
  191. package/src/scripts/_lib/test_delta.ts +166 -0
  192. package/src/scripts/_lib/test_provenance.ts +171 -0
  193. package/src/scripts/_lib/typed_op_grant.ts +246 -0
  194. package/src/scripts/_lib/typed_op_watch.ts +185 -0
  195. package/src/scripts/ai_council/config.ts +8 -11
  196. package/src/scripts/ai_council/fallback_config.ts +5 -3
  197. package/src/scripts/ai_council/ownership_classes.ts +118 -0
  198. package/src/scripts/ask_block_census.ts +285 -15
  199. package/src/scripts/check_enforcement_matrix.ts +624 -0
  200. package/src/scripts/check_gate_reachability.ts +173 -10
  201. package/src/scripts/check_generator_sync.ts +954 -0
  202. package/src/scripts/check_preamble_payload_budget.ts +75 -2
  203. package/src/scripts/check_release_highlights.ts +33 -1
  204. package/src/scripts/check_release_holds.ts +567 -0
  205. package/src/scripts/check_rule_projection_integrity.ts +22 -12
  206. package/src/scripts/check_test_delta.ts +294 -0
  207. package/src/scripts/check_test_weakening.ts +299 -0
  208. package/src/scripts/closure_scan.ts +333 -0
  209. package/src/scripts/compile_hook_manifest.ts +43 -3
  210. package/src/scripts/council_record_shape.ts +209 -0
  211. package/src/scripts/hook_manifest.json +1 -1
  212. package/src/scripts/hook_manifest.yaml +88 -9
  213. package/src/scripts/hooks/concern_registry.ts +4 -0
  214. package/src/scripts/hooks/design_pass_hook.ts +128 -3
  215. package/src/scripts/hooks/evidence_independence.ts +96 -0
  216. package/src/scripts/hooks/memory_recall_hook.ts +540 -0
  217. package/src/scripts/hooks/obligation_settle_hook.ts +182 -0
  218. package/src/scripts/hooks/rule_inject_hook.ts +49 -1
  219. package/src/scripts/hooks/run_continuation_hook.ts +17 -20
  220. package/src/scripts/hooks_doctor.ts +85 -0
  221. package/src/scripts/hooks_status.ts +19 -0
  222. package/src/scripts/install.ts +106 -206
  223. package/src/scripts/janitor.ts +7 -0
  224. package/src/scripts/lint_decision_classes.ts +464 -0
  225. package/src/scripts/lint_hook_manifest.ts +11 -0
  226. package/src/scripts/lint_major_migration_sections.ts +450 -0
  227. package/src/scripts/lint_plan_risk_register.ts +47 -3
  228. package/src/scripts/lint_roadmap_blockers.ts +61 -0
  229. package/src/scripts/lint_roadmap_producers.ts +202 -0
  230. package/src/scripts/measure_rule_budget.ts +101 -5
  231. package/src/scripts/new_roadmap.ts +37 -0
  232. package/src/scripts/orchestration_record.ts +0 -5
  233. package/src/scripts/release.ts +14 -98
  234. package/src/scripts/release_drill.ts +267 -1
  235. package/src/scripts/release_publication.ts +51 -0
  236. package/src/scripts/report_enforcement_drift.ts +566 -0
  237. package/src/scripts/report_host_injection_effect.ts +3 -11
  238. package/src/scripts/report_standing_payload_by_host.ts +26 -152
  239. package/src/scripts/schemas/agent-settings.schema.json +23 -0
  240. package/src/scripts/schemas/command.schema.json +4 -0
  241. package/src/scripts/scope_growth.ts +219 -0
  242. package/src/scripts/trigger_eval_grandfather.json +0 -1
  243. package/src/scripts/ui_conformance_probe.ts +622 -0
  244. package/src/server/schemas/settings.ts +31 -7
  245. package/src/shared/missionExecution.ts +126 -0
  246. package/dist/cli-delegate/chunk-523HCFYO.js +0 -90
@@ -13,6 +13,35 @@ Migrated out of `design-fidelity.md` on 2026-09-09 under the council verdict on
13
13
  the operative pointers the same verdict requires, not an arbitrary line cut. The
14
14
  rule keeps the obligations; this holds the reasoning behind them.
15
15
 
16
+ ### The matcher, and why each shipped class is shaped that way
17
+
18
+ Migrated out of `design-fidelity.md` on 2026-09-18 under
19
+ `road-to-design-fidelity-proof` Phase 1.1 — the rule keeps the operative class
20
+ list, this holds the argument behind each one.
21
+
22
+ Matching is plain lower-cased substring containment on the prompt, plus fnmatch
23
+ over the open files. Three handover classes must reach this rule: an English
24
+ phrasing, a German one, and a prompt carrying **no** keyword at all because the
25
+ artifact is simply attached. The last is covered by two file patterns:
26
+ `*design.html`, the conventional handover filename, and `*.dc.html`, the Claude
27
+ Design canvas artboard — which `*design.html` cannot match, because it compiles
28
+ to `^(?:.*design\.html)$` and `ToDo.dc.html` does not end in `design.html`.
29
+ Neither is `*.html`, which would fire on every HTML edit in every project and be
30
+ strictly worse than the gap it closes; `near-plain-html-open-file` pins that
31
+ form silent. A handover under some other filename needs one word in the prompt.
32
+
33
+ Two further handover shapes carry the artifact without any of the above:
34
+
35
+ - **A capability URL.** A published artifact is handed over as a link, not a
36
+ file — so `phrase: "claude.site/artifacts"` fires on the *published-artifact
37
+ path*, not on the host. `claude.ai` alone is a chat link and must stay quiet:
38
+ a keyword on the bare domain would fire on "I pasted this from claude.ai",
39
+ which is a conversation reference, not a spec.
40
+ - **A design-system directory.** `path_prefix: ".claude/design-system/"` — the
41
+ conventional location for a handed-over token/component set. The prefix is the
42
+ vendor-scoped directory, never a bare `design-system/`, which is a normal
43
+ source folder in a large fraction of frontend repos.
44
+
16
45
  ### The withdrawn builder-URL trigger
17
46
 
18
47
  A page built in Lovable / v0 / bolt and handed over as a share link is a
@@ -47,18 +47,25 @@ Litmus: does the directive name a single concrete deliverable? Yes → task-scop
47
47
 
48
48
  A new instruction from the user mid-flight is **not** a continuation — see [`user-interrupt-priority`](user-interrupt-priority.md) for the mandatory STOP → run new task → ASK before resume protocol. Autonomy never authorizes silent-resume of the prior task.
49
49
 
50
- ## Validation-loop budget — hard cap N=3 per target
50
+ ## Validation-loop budget — `execution.fix_loop_max`, default 10, and a ladder
51
51
 
52
52
  **Validation target** = a single identifiable artefact (file path, lint rule ID, test name, CI sub-task name) — natural-language clusters ("the linter stuff") don't count.
53
53
 
54
54
  ```
55
- 3 CONSECUTIVE FAILED ATTEMPTS ON THE SAME VALIDATION TARGET → STOP.
56
- SURFACE THE 3 ATTEMPTS + BLOCKING ISSUE. ASK USER FOR GUIDANCE.
57
- DO NOT ITERATE BEYOND N=3 WITHOUT EXPLICIT USER APPROVAL.
58
- COUNTER RESETS ONLY ON A DIFFERENT TARGET OR USER-APPROVED CONTINUATION.
55
+ THE BOUND TRIGGERS A STRATEGY CHANGE, NEVER A QUESTION.
56
+ ATTEMPTS 1-3 — ROOT-CAUSE PLUS A TARGETED FIX.
57
+ ATTEMPTS 4-6 — A MANDATORY STRATEGY SHIFT. REPEATING THE APPROACH IS NOT AN ATTEMPT,
58
+ IT IS THE SAME ATTEMPT AGAIN.
59
+ ATTEMPTS 7-10 — ESCALATE INDEPENDENTLY: A SECOND SESSION, A PROVIDER-DIVERSE
60
+ REVIEWER, THE COUNCIL, THE TEAM, OR A ROLLBACK OF THE SLICE.
61
+ AT THE BOUND, IN ORDER: A NEW STRATEGY FROM THE ESCALATION → A NEW EPOCH ·
62
+ AN INDEPENDENT PHASE AVAILABLE → CONTINUE IT · THE RESIDUE OWNER-OWNED →
63
+ ONE NATIVE ASK · AN EXTERNAL PREREQUISITE OBJECTIVELY MISSING → `BLOCKED`
64
+ WITH EVIDENCE · OTHERWISE → A NEW EPOCH.
65
+ NO RUNG MAPS A COUNT TO AN OWNER ASK. A COUNT IS NOT A REASON TO ASK.
59
66
  ```
60
67
 
61
- Failed attempt = an iteration that did not move the target red → green; tuning the tool around the target counts as an attempt.
68
+ Failed attempt = an iteration that did not move the target red → green; tuning the tool around the target counts as one. The bound is `execution.fix_loop_max` (default 10, overridable globally, per project and per prompt). Council and team verdicts append to the run's `## Decisions`. Bands, the five bound outcomes and how to read a red: [`autonomy-mechanics § Validation-loop budget`](../contexts/execution/autonomy-mechanics.md).
62
69
 
63
70
  ### Antipattern — allowlist-growth as silent budget bypass
64
71
 
@@ -67,9 +74,9 @@ ALLOWLIST > 20 ENTRIES IN ONE SESSION = THE LINTER IS WRONG.
67
74
  STOP. PROPOSE LINTER REDESIGN OR REMOVAL. DO NOT EXPAND THE ALLOWLIST FURTHER.
68
75
  ```
69
76
 
70
- Crossing 20 entries counts as the 3rd validation-target failure — fix the tool shape, not the list. Enforced at tool-call time by the `block-config-weakening` PreToolUse guard (`src/scripts/hooks/block_config_weakening.ts`) **on `claude`, the one host that both binds `pre_tool_use` and honours a deny**: it counts allowlist entries added per session, warns from 5, and blocks past 20. It is *bound* on augment and cowork as well, and ignored there — `host_semantics.ts` verifies claude alone, and both trampolines discard dispatcher output and `exit 0` unconditionally. Everywhere else the cap is model-carried and "enforced at tool-call time" is not a claim this rule can make. **Corrected 2026-08-17 in both directions:** this sentence used to certify augment, claude and cowork as the enforcing set (an over-claim of two hosts) and to explain the rest with "the guard has nowhere to bind" (false for cursor, cline and gemini, whose native pre-tool events `native_event_aliases` already maps onto `pre_tool_use` — unbound, not unbindable; only windsurf and copilot have no alias row). The four states are tabulated once in [`hook-architecture-v1 § Which hosts carry pre_tool_use`](../docs/contracts/hook-architecture-v1.md). Run `agent-config hooks:status` to see which slots are bound on the host you are actually on — the sibling rules `git-history-discipline` and `evaluator-independence` qualify the identical slot, and an unqualified claim here would read as a guarantee the manifest does not give. Baselines and budget thresholds warn only — a rising count there may be a legitimate ratchet reset, which the edit alone cannot distinguish. Verify with the narrowest tool that proves the target green (a single `curl` / Playwright spec for HTTP/UI, the test runner with a `--filter`, an `xdebug` step-through) — never a meta-pipeline as per-iteration probe. Failed-attempt detail, suppression-sweep equivalents, probe-efficiency detail, and adaptive effort & stop (RDP): [`autonomy-mechanics § Validation-loop budget`](../contexts/execution/autonomy-mechanics.md).
77
+ Crossing 20 entries spends the whole fix-loop bound for that target at once — fix the tool shape, not the list. Carried by the `block-config-weakening` PreToolUse guard, which blocks **on `claude` only** and is model-carried everywhere else; run `agent-config hooks:status` for the host you are on. Verify with the narrowest tool that proves the target green — a `curl` or Playwright spec for HTTP/UI, the test runner with a `--filter`, an `xdebug` step-through — never a meta-pipeline as per-iteration probe. Host reach, failed-attempt detail, suppression-sweep equivalents and adaptive effort (RDP): [`autonomy-mechanics § Validation-loop budget`](../contexts/execution/autonomy-mechanics.md).
71
78
 
72
- Body migrated to `contexts/execution/autonomy-mechanics.md` (per P4 of `road-to-kernel-and-router.md`) — opt-in detection summary, task-scope shapes table, N=3 mechanics, allowlist-antipattern detail, probe efficiency, adaptive effort (RDP).
79
+ Body migrated to `contexts/execution/autonomy-mechanics.md` (per P4 of `road-to-kernel-and-router.md`) — opt-in detection summary, task-scope shapes table, fix-loop bound and epoch mechanics, allowlist-antipattern detail, probe efficiency, adaptive effort (RDP).
73
80
  Trigger-set above activates this routing on demand, independent of the discipline profile (ADR-110).
74
81
 
75
82
  ## See also
@@ -64,68 +64,46 @@ primitive → run in-session (clean no-op).
64
64
 
65
65
  1. **Decompose** the task into independent / ordered slices.
66
66
  2. **Tier-size** each slice (`lite|medium|high`) per the classification context —
67
- never the orchestrator's own session tier (the cost win is the per-call
68
- downsize; see [`subagent-routing`](../contexts/execution/subagent-routing.md)).
69
- Where `subagents.model_ceiling` caps the tier and the slice does not fit under
70
- it, the worker **escalates and never silently delivers the degraded result**;
71
- the orchestrator re-slices, runs in-session, or surfaces the ceiling to the
72
- human, and never raises the ceiling itself (class C — `settings:set` refuses
73
- it by construction). Absent is *uncapped*, never a low cap. Full contract:
67
+ never the orchestrator's own session tier
68
+ ([`subagent-routing`](../contexts/execution/subagent-routing.md)). Where
69
+ `subagents.model_ceiling` caps the tier and the slice does not fit, the worker
70
+ **escalates and never silently delivers the degraded result**; the
71
+ orchestrator never raises the ceiling itself, and absent is *uncapped*.
74
72
  [`subagent-boundary § The model ceiling`](../docs/contracts/subagent-boundary.md).
75
73
  3. **Dispatch** via the form gate + matching `subagent-orchestration` mode
76
74
  (independent → do-in-parallel; ordered → do-in-steps; risk/correctness →
77
75
  + judge; UI-heavy → live-app judge, efficacy-gated).
78
76
  4. **Verify** every return per
79
77
  [`verify-budget`](../contexts/execution/verify-budget.md); the cross-model
80
- judge Iron Law and the N=3 budget ([`autonomous-execution`](autonomous-execution.md))
78
+ judge Iron Law and the fix-loop bound ([`autonomous-execution`](autonomous-execution.md))
81
79
  are never lifted.
82
80
  5. **Respect the failure-type stop and the ordering gate** — two consecutive
83
81
  verification-failed returns from one subagent type stop that type for the
84
- session (an application of the N=3 budget, no new mechanism), and an
82
+ session (an application of the fix-loop bound, no new mechanism), and an
85
83
  ordered slice never dispatches before its declared parent's return is
86
84
  verified. Both per
87
85
  [`subagent-steering`](../contexts/execution/subagent-steering.md).
88
- 6. **Record** telemetry after each dispatch — on hook-capable hosts the
89
- `orchestration-record` concern (`post_tool_use`) emits the line
90
- deterministically for every Agent/Task completion; on hosts without the
91
- slot, run `orchestration_record` yourself (one validated line: spawn_count,
92
- token_delta + provenance, tier, task_class) per
93
- [`orchestration-telemetry`](../contexts/execution/orchestration-telemetry.md)
94
- § Emit. Measured before the hook existed: 1 of 370 dispatches captured —
95
- the model-carried path alone leaves the value question unmeasured.
86
+ 6. **Record** telemetry after each dispatch — the `orchestration-record` concern
87
+ emits it on hook-capable hosts; elsewhere run `orchestration_record` yourself
88
+ per [`orchestration-telemetry`](../contexts/execution/orchestration-telemetry.md)
89
+ § Emit. Measured before the hook existed: 1 of 370 dispatches captured.
96
90
 
97
91
  ## Carriers — how this rule reaches a session (and what stays model-carried)
98
92
 
99
- No host runs the tier-2 rule router, so this file's triggers alone never load
100
- it. The obligation travels on three carriers instead: the always-loaded
101
- AGENTS.md line (delegate-by-default + end-review), the `delegation-nudge`
102
- concern on `user_prompt_submit` (runs `classifyTask` on cheap prompt signals
103
- and injects a one-line verdict ONLY when the classifier says
104
- `do-in-parallel`/`do-in-steps` — silence otherwise; delivery on
105
- `user_prompt_submit` is end-to-end verified), and the `end-review-nudge`
106
- concern on `stop` (ONE `review_skipped` telemetry line per mutating
107
- no-review session — verified; its advisory line reaches the dispatcher
108
- output, but host-side forwarding of stop-slot context to the model is
109
- unverified, so the model-facing end-review carrier is the AGENTS.md line
110
- plus this telemetry). The
111
- capability gate itself resolves from the committed host registry merged with a
112
- live environment probe in `src/scripts/_lib/host_capability.ts`
113
- (`probeHostCapabilities` — capability is a fact about the host, never a
114
- settings override).
93
+ No host runs the tier-2 rule router, so this file's triggers alone never load it.
94
+ The obligation travels on three carriers instead: the always-loaded AGENTS.md
95
+ line, the `delegation-nudge` concern on `user_prompt_submit`, and the
96
+ `end-review-nudge` concern on `stop`. Capability resolves from the committed host
97
+ registry merged with a live probe — never from a settings override.
115
98
 
116
99
  **Never read a `false` capability as a host limitation without checking where it
117
- came from.** The registry holds one row, so on every other host all six fields
118
- are the all-false safe default — which records that *nobody answered*, not that
119
- the host cannot spawn. `agent-config routing:doctor [--platform <host>]` prints
120
- the value **and** its provenance per field (`registry` = a committed observation
121
- this repo made once · `live-probe` = established in this process · `default` =
122
- no answer). Run it before concluding delegation is unavailable here; the
123
- same-shaped wrong guess about the council is the incident
124
- [`council-availability`](council-availability.md) exists for. What stays
125
- model-carried, honestly: the decomposition itself, the per-return
126
- verification, and every dispatch on hosts without hook slots. The nudges are
127
- advisory by design — whether they change behaviour is measured by the
128
- telemetry, not assumed.
100
+ came from.** The registry holds one row, so on every other host the fields are the
101
+ all-false safe default, which records that *nobody answered*. Run `agent-config
102
+ routing:doctor [--platform <host>]`, which prints the value **and** its
103
+ provenance, before concluding delegation is unavailable here. What stays
104
+ model-carried: the decomposition, the per-return verification, and every dispatch
105
+ on hosts without hook slots. Per-carrier detail and what each one verifies:
106
+ [`auto-orchestration-activation § Carriers`](../contexts/execution/auto-orchestration-activation.md).
129
107
 
130
108
  ## Scope — does NOT
131
109
 
@@ -37,6 +37,8 @@ workspaces: [engineering]
37
37
  packs: [engineering-base, frontend-design]
38
38
  collision_ok:
39
39
  "mockup": "a provided mockup is the spec — 1:1 fidelity floor"
40
+ enforced_by:
41
+ - "instruction-only: no artifact in this tree records a fidelity comparison. lint_design_slop and lint_design_quality measure generic AI-aesthetic tells and accessibility; neither reads the handover, so a 1:1 claim is model-carried"
40
42
  # obligation: line 58
41
43
  obligation_frequency: "per-edit"
42
44
  ---
@@ -68,6 +70,10 @@ THE IMAGE IS THE SPEC AND THE 1:1 FLOOR ABOVE APPLIES TO IT UNCHANGED.
68
70
  WHERE THE ARTIFACT'S OWN MARKUP / CSS / JS IS STACK-COMPATIBLE, ADAPTING
69
71
  THAT CODE IS THE DEFAULT — A FROM-SCRATCH RE-DERIVATION IS A DEVIATION
70
72
  AND NEEDS THE SAME CONFIRMATION AS A SWAPPED CONTROL.
73
+ A 1:1 CLAIM IS DISCHARGED BY A COMMITTED ARTIFACT NAMING, PER HANDOVER
74
+ CHAPTER, THE EVIDENCE TAKEN — NEVER BY A BEHAVIOR TEST, AND NEVER BY A
75
+ SENTENCE IN A REPLY. A GREEN SUITE THAT MEASURED BEHAVIOR ANSWERS A
76
+ QUESTION FIDELITY DID NOT ASK.
71
77
  ```
72
78
 
73
79
  The qualifier is load-bearing, not hedging. Unqualified, the screenshot line
@@ -140,51 +146,40 @@ porting, or modifying UI to match it.
140
146
 
141
147
  ## Routing — an attached artifact is a trigger, an attached HTML file is not
142
148
 
143
- Matching is plain lower-cased substring containment on the prompt, plus fnmatch
144
- over the open files. Three handover classes must reach this rule: an English
145
- phrasing, a German one, and a prompt carrying **no** keyword at all because the
146
- artifact is simply attached. The last is covered by two file patterns:
147
- `*design.html`, the conventional handover filename, and `*.dc.html`, the Claude
148
- Design canvas artboard — which `*design.html` cannot match, because it compiles
149
- to `^(?:.*design\.html)$` and `ToDo.dc.html` does not end in `design.html`.
150
- Neither is `*.html`, which would fire on every HTML edit in every project and be
151
- strictly worse than the gap it closes; `near-plain-html-open-file` pins that
152
- form silent. A handover under some other filename needs one word in the prompt.
153
-
154
- Two further handover shapes carry the artifact without any of the above:
155
-
156
- - **A capability URL.** A published artifact is handed over as a link, not a
157
- file — so `phrase: "claude.site/artifacts"` fires on the *published-artifact
158
- path*, not on the host. `claude.ai` alone is a chat link and must stay quiet:
159
- a keyword on the bare domain would fire on "I pasted this from claude.ai",
160
- which is a conversation reference, not a spec.
161
- - **A design-system directory.** `path_prefix: ".claude/design-system/"` — the
162
- conventional location for a handed-over token/component set. The prefix is the
163
- vendor-scoped directory, never a bare `design-system/`, which is a normal
164
- source folder in a large fraction of frontend repos.
165
- - **A third-party builder's share link — UNCOVERED, deliberately.** A page built
166
- in Lovable / v0 / bolt and handed over as a link is a finished spec and this
167
- rule does not route it; the trigger was tried and withdrawn as over-broad.
168
- Until then the class needs one word in the prompt. Why, what closes it, and
169
- the row that pins the broad form silent:
170
- [`design-fidelity-routing`](../guidelines/design-fidelity-routing.md).
171
-
172
- Every class here carries its own near-miss row in `ROUTING_MATRIX`
173
- ([`design_fidelity_routing.test.ts`](../../tests/scripts/design_fidelity_routing.test.ts));
174
- extending the set without one is how an over-broad trigger lands. Which row, and
175
- why: [`design-fidelity-routing`](../guidelines/design-fidelity-routing.md).
176
-
177
- **The near-miss must test the direction the new trigger opens, not a direction
178
- that was already closed** — apply this before writing a trigger, not after. The
179
- worked example and the review that produced the rule:
149
+ Matching is lower-cased substring containment on the prompt plus fnmatch over
150
+ the open files. Five classes reach this rule without a keyword being typed: the
151
+ filename patterns `*design.html` and `*.dc.html`, the published-artifact path
152
+ `claude.site/artifacts`, the directory prefix `.claude/design-system/`, and the
153
+ English and German handover phrasings. A handover under any other filename, and
154
+ a third-party builder's share link, need one word in the prompt — the
155
+ builder-URL trigger was tried and **withdrawn** as over-broad, and stays pinned
156
+ silent rather than merely absent.
157
+
158
+ Every class carries its own near-miss row in `ROUTING_MATRIX`
159
+ ([`design_fidelity_routing.test.ts`](../../tests/scripts/design_fidelity_routing.test.ts)),
160
+ and the row must test the direction the NEW trigger opens, not one that was
161
+ already closed — apply that before writing a trigger, not after. Why each class
162
+ is shaped as it is, why `*.html` and a bare builder host are refused, and the
163
+ worked example behind the direction rule:
180
164
  [`design-fidelity-routing`](../guidelines/design-fidelity-routing.md).
181
165
 
182
166
  Body migrated to [`guideline:design-fidelity-mechanics`](../guidelines/design-fidelity-mechanics.md) (per P4 of `road-to-kernel-and-router.md`) — URL / live-page handover (extraction into the `design-system.json` contract before the first UI write, the retrieval order, the lock boundary), surgical visual edits (targeted-edit vs redesign-trigger discipline, stable anchors), asset & imagery discipline (owned-asset path, third-party delivery is self-hosted by default, real-imagery-as-proof, iconography floor, no unrequested filler), deviation-surfacing shape, failure-mode catalog, `daf-*` fixtures.
183
167
  Trigger-set above activates this routing on demand, independent of the discipline profile (ADR-110).
184
168
 
169
+ ## Honest enforcement — `instruction-only`
170
+
171
+ Nothing records a fidelity comparison. The estate's two design linters measure
172
+ generic AI-aesthetic tells (`lint_design_slop`) and accessibility
173
+ (`lint_design_quality`); neither opens the handover, so nothing can tell a
174
+ proven 1:1 from an asserted one. The proof clause in the Iron Law is therefore
175
+ model-carried, and the committed matrix
176
+ ([`design-review`](../skills/design-review/SKILL.md) § Fidelity proof) is the
177
+ control — a reviewer can open it, which is more than any gate here does.
178
+
185
179
  ## See also
186
180
 
187
181
  - [`brand-source-of-truth`](brand-source-of-truth.md) / [`brand-consistency`](brand-consistency.md) — same precedence shape, for registered brand tokens.
188
182
  - [`minimal-safe-diff`](minimal-safe-diff.md) — the code-diff analog (smallest change; no drive-by restructure).
189
183
  - [`existing-ui-audit`](../skills/existing-ui-audit/SKILL.md) / [`ui-audit-gate`](ui-audit-gate.md) — inventory existing components before adding new ones.
184
+ - [`design-review`](../skills/design-review/SKILL.md) § Fidelity proof — the matrix that discharges the proof clause.
190
185
  - [`ask-when-uncertain`](ask-when-uncertain.md) — the one-question, numbered-option surfacing shape.
@@ -52,19 +52,13 @@ A SECOND EVALUATION OF THE SAME WORK IN ONE TURN IS VERDICT SHOPPING, NOT RIGOUR
52
52
 
53
53
  ## The failure this exists to stop
54
54
 
55
- Measured, once, at maximum cost (conformance audit 2026-08-06):
56
-
57
- > The agent dispatched a "blind reviewer" over its own change. It wrote that
58
- > reviewer's prompt itself, put **"NO-FINDINGS is expected and welcome"** into it,
59
- > and narrowed the scope to four files it chose. The reviewer returned
60
- > NO-FINDINGS. That honest-null was committed as **binding gate evidence**. An
61
- > unsteered pass over the same delta later found 5 findings, one of them
62
- > critical, already live on the trunk.
63
-
64
- The agent's own retro named it exactly: *"Die Fabrikation lag nicht im Weglassen
65
- des Reviews — sie lag in meinem Prompt. Ich habe die Antwort vorgeladen und dann
66
- als Evidenz verbucht."* The review ran. The process was followed. The evidence
67
- was manufactured anyway.
55
+ Measured once, at maximum cost: an agent wrote its own "blind reviewer" prompt,
56
+ put *"NO-FINDINGS is expected and welcome"* into it, narrowed the scope to four
57
+ files it chose, and committed the resulting honest-null as **binding gate
58
+ evidence**. An unsteered pass over the same delta later found 5 findings, one
59
+ critical, already live on the trunk. The review ran. The process was followed.
60
+ The evidence was manufactured anyway. Full record:
61
+ [`evaluator-independence-mechanics § The audited failure`](../guidelines/agent-infra/evaluator-independence-mechanics.md).
68
62
 
69
63
  ## What this requires
70
64
 
@@ -81,10 +75,6 @@ was manufactured anyway.
81
75
 
82
76
  ## The softer form — stating an expectation without stating the verdict
83
77
 
84
- The Iron Law forbids **authoring the verdict** into an evaluator's prompt. There is a
85
- weaker move that evades it while doing the same work, and it is the one an orchestrator
86
- reaches for without noticing: **stating an expectation.**
87
-
88
78
  ```
89
79
  THE ORCHESTRATOR STATES NO EXPECTATION OF THE OUTCOME IN A PROMPT IT WRITES
90
80
  FOR A JUDGE OF ITS OWN WORK. NOT THE VERDICT, AND NOT THE DIRECTION.
@@ -92,25 +82,37 @@ FOR A JUDGE OF ITS OWN WORK. NOT THE VERDICT, AND NOT THE DIRECTION.
92
82
  "I EXPECT NO FINDINGS" — NONE OF THESE NAME A VERDICT, AND ALL OF THEM SUPPLY ONE.
93
83
  ```
94
84
 
95
- The distinction the phrase list cannot see is exactly this one: *"NO-FINDINGS is
96
- expected"* is a prediction, not a verdict, and it steered a real review into an
97
- honest-null that was later refuted by five findings on the trunk. A prompt that says what
98
- the author thinks the answer is has authored the answer, whatever grammatical mood it
99
- used.
85
+ Write the scope, the diff and the question. Nothing about how it is expected to
86
+ come out — including a reassurance that no outcome is expected, which is an
87
+ expectation stated in the negative. Why the phrase list cannot see this:
88
+ [`evaluator-independence-mechanics § The softer form`](../guidelines/agent-infra/evaluator-independence-mechanics.md).
100
89
 
101
- **What to write instead:** the scope, the diff, and the question. Nothing about how it is
102
- expected to come out — including a reassurance that no particular outcome is expected,
103
- which is itself an expectation stated in the negative.
90
+ ## Tests are evaluators
91
+
92
+ ```
93
+ A TEST IS AN EVALUATOR, AND AN IMPLEMENTER WHO WROTE IT HAS AUTHORED ITS VERDICT.
94
+ THE ACCEPTANCE BEHAVIOUR IS NAMED, THE TEST IS WRITTEN INDEPENDENTLY, IT IS SHOWN
95
+ RED, THEN IT IS IMPLEMENTED AGAINST, THEN AN INDEPENDENT INSTANCE VALIDATES GREEN.
96
+ THE IMPLEMENTER NEVER SILENTLY WEAKENS AN ASSERTION, DELETES, SKIPS OR XFAILS A
97
+ FAILING TEST, LOWERS A THRESHOLD, OR CHANGES FIXTURE SEMANTICS TO FIT THE CODE.
98
+ WHERE THE TEST LOOKS WRONG: EVIDENCE → INDEPENDENT TEST REVIEW → COUNCIL OR TEAM
99
+ → CHANGE ONLY AFTER AN INDEPENDENT VERDICT. THE OWNER IS NOT THE ARBITER.
100
+ ```
101
+
102
+ **Five levels:** L0 same agent — **fallback only** · L1 another session, same
103
+ model · L2 another model · L3 another provider · L4 a multi-provider council or
104
+ team. Critical behavior — security, authority, data loss, merge control — targets
105
+ **L3 or L4 wherever two providers are configured**, read from `agent-config
106
+ council:status`'s live provider count, never assumed. Levels, workflow, the
107
+ weakening ladder and the validator's checklist:
108
+ [`evaluator-independence-mechanics § Tests are evaluators`](../guidelines/agent-infra/evaluator-independence-mechanics.md).
104
109
 
105
110
  ## When it does NOT fire
106
111
 
107
- - **Ordinary parallel fan-out.** Dispatching many subagents to read, map,
108
- search, or implement is not evaluation and is not gated. The session that
109
- produced this rule ran a seven-way analysis fan-out in one turn; none of it is
110
- in scope.
112
+ - **Ordinary parallel fan-out.** Dispatching subagents to read, map, search or
113
+ implement is not evaluation and is not gated.
111
114
  - A review **a human** commissioned or whose prompt a human wrote.
112
- - A deterministic checker (linter, test suite, CI gate) — it has no prompt to
113
- steer.
115
+ - A deterministic checker (linter, test suite, CI gate) — no prompt to steer.
114
116
 
115
117
  ## Enforcement — honest scope
116
118
 
@@ -119,26 +121,18 @@ ITEM 1 IS ENFORCED. ITEMS 2, 3 AND 4 ARE NOT — 4 ONLY WARNS.
119
121
  NEVER CITE A GUARD THAT WARNS AS ONE THAT BLOCKS.
120
122
  ```
121
123
 
122
- [`evidence_independence.ts`](../scripts/hooks/evidence_independence.ts) is a
123
- `pre_tool_use` concern reading the prompt the agent is about to send.
124
-
125
- - **Item 1 (pre-loaded verdict) BLOCKS** — `EXIT_BLOCK` at `:253`, on the one
126
- host that honours a deny.
127
- - **Item 4 (second self-scoped evaluation) WARNS** — `EXIT_ALLOW` with
128
- `decision: "warn"` (`:301-324`). The turn-budget clause is advisory.
129
- - **Item 2 (an honestly chosen scope) is enforced by nothing.** A narrowed scope
130
- is not decidable from the prompt alone.
131
- - **Item 3 (recording the prompt with the verdict) IS enforced** by
132
- [`check_review_prompt_binding.ts`](../../src/scripts/check_review_prompt_binding.ts),
133
- with one limit that matters: **omission beats substitution** — not committing
134
- the prompt package drops the round out of the checkable set with no finding.
124
+ [`evidence_independence.ts`](../scripts/hooks/evidence_independence.ts), a
125
+ `pre_tool_use` concern, BLOCKS item 1 on the one host that honours a deny and
126
+ only WARNS on item 4. Item 2 is enforced by nothing — a narrowed scope is not
127
+ decidable from a prompt. Item 3 is enforced by
128
+ [`check_review_prompt_binding.ts`](../../src/scripts/check_review_prompt_binding.ts),
129
+ where **omission beats substitution**: not committing the prompt package drops
130
+ the round out of the checkable set with no finding.
135
131
 
136
132
  Where the guard does not deny, every item is model-carried. Never claim the
137
- review ran as if it were verified.
138
-
139
- Why each branch behaves that way, the phrase-list and turn-boundary limits, the
140
- four host states, the two corrections this section has taken, and the
141
- 11-of-19 measurement behind item 3:
133
+ review ran as if it were verified. Per-branch reasoning, the phrase-list and
134
+ turn-boundary limits, the four host states and the 11-of-19 measurement behind
135
+ item 3:
142
136
  [`evaluator-independence-mechanics`](../guidelines/agent-infra/evaluator-independence-mechanics.md).
143
137
 
144
138
  ## See also
@@ -0,0 +1,41 @@
1
+ ---
2
+ type: "auto"
3
+ tier: "1"
4
+ description: "A behavior change gets a failing test first — and the test must fail for the intended reason before any implementation is written"
5
+ triggers:
6
+ - keyword: "tdd"
7
+ - keyword: "test-first"
8
+ - keyword: "failing test"
9
+ - keyword: "regression test"
10
+ - keyword: "characterization test"
11
+ routes_to:
12
+ - "skill:test-driven-development"
13
+ enforced_by:
14
+ - "instruction-only: no gate sees which was written first; check_test_delta and check_test_weakening catch an absence, never an order."
15
+ obligation_frequency: "per-edit"
16
+ workspaces: [agent-config-maintainer, engineering]
17
+ packs: [engineering-base]
18
+ ---
19
+
20
+ # Test First
21
+
22
+ ```
23
+ A BEHAVIOR CHANGE GETS A FAILING TEST FIRST, WHERE A TEST IS MEANINGFUL.
24
+ A BUG GETS A REPRODUCING REGRESSION TEST FIRST.
25
+ UNCERTAIN LEGACY GETS A CHARACTERIZATION TEST FIRST.
26
+ THE TEST MUST FAIL FOR THE INTENDED REASON — A TEST NEVER SEEN RED HAS
27
+ UNKNOWN SENSITIVITY AND IS NOT EVIDENCE. REFACTOR ONLY AFTER GREEN.
28
+ ```
29
+
30
+ [`test-driven-development`](../skills/test-driven-development/SKILL.md) carries the
31
+ procedure; this rule decides **when** it is owed: for consumer code, for this
32
+ package's own code, scripts and hooks, **and for governance changes whose
33
+ projection, routing or lint behavior is testable** — the clause a reader escapes
34
+ with *the artifact is markdown, so there is nothing to test*. Markdown is not the
35
+ discriminator: a rule whose triggers decide what loads, a projection a gate reads and a lint whose verdict flips are executable contracts in a prose extension.
36
+
37
+ **Where there is genuinely no executable contract** — a paragraph stating a
38
+ reason — the obligation is an independent *review*, never a fake test: an
39
+ assertion over prose written to satisfy this rule manufactures the evidence it exists to require.
40
+
41
+ **Does NOT fire on** a rename, typo, formatting or comment-only edit · a change the user fenced this turn · a spike deleted before it lands. **Honest enforcement — `instruction-only`.** No gate sees which was written first: `check_test_delta` and `check_test_weakening` catch an absence, never an order. Model-carried; the red-first discipline is the control.
@@ -28,7 +28,7 @@
28
28
  "refresh_cadence": "quarterly",
29
29
  "upstream": {
30
30
  "repo": "derived: W3C ARIA Authoring Practices Guide + WCAG 2.2",
31
- "sha": "APG 2026 / WCAG 2.2",
32
- "last_checked": "2026-06-07"
31
+ "sha": "APG 2026 / WCAG 2.2 (W3C Recommendation 12 Dec 2024) \u2014 verified not superseded 2026-09-18",
32
+ "last_checked": "2026-09-18"
33
33
  }
34
- }
34
+ }
@@ -271,9 +271,17 @@ Every council reply MUST contain, in this order:
271
271
  / `accept-with-modification` / `reject` / `needs-input` plus a
272
272
  one-line reason citing host evidence (file:line, ADR, contract).
273
273
  See *Critical evaluation* above.
274
- 5. **User-facing options** — numbered block per `user-interaction`,
275
- carrying the host verdict in each option, with "discard council
276
- input" always present as an option.
274
+ 5. **User-facing options — CONDITIONAL, on ownership.** A conclusive
275
+ **technical** verdict emits **no** options block: it is a resolution,
276
+ and handing it over as options routes a technical decision to a person
277
+ because it was hard (ADR-268 § 10). The block is owed when the verdict
278
+ is owner-owned (`product-owned`, `business-owned`, `destructive-owned`)
279
+ or when the council did not converge — then it is a numbered block per
280
+ `user-interaction`, carrying the host verdict in each option, with
281
+ "discard council input" always present. Convergence is read from the
282
+ record, never inferred: a record that does not say whether its members
283
+ converged is itself the finding. Checkable in both directions with
284
+ `./scripts-run src/scripts/council_record_shape <record.md>`.
277
285
 
278
286
  The host agent NEVER ships council output as its own reasoning, and
279
287
  NEVER ships the host verdict as council output. Provider attribution
@@ -28,7 +28,7 @@
28
28
  "refresh_cadence": "quarterly",
29
29
  "upstream": {
30
30
  "repo": "derived: RFC 9110/9457/7396/8288 + httpapi WG drafts",
31
- "sha": "RFC set as of 2026-06",
32
- "last_checked": "2026-06-07"
31
+ "sha": "RFC 9110 (STD 97) / 9457 / 7396 / 8288 \u2014 verified 2026-09-18: 9110 neither obsoleted nor updated; 9457 current and obsoletes 7807",
32
+ "last_checked": "2026-09-18"
33
33
  }
34
- }
34
+ }
@@ -28,8 +28,8 @@
28
28
  "owner": "package-maintainer",
29
29
  "refresh_cadence": "quarterly",
30
30
  "upstream": {
31
- "repo": "derived: PostgreSQL 16 + MySQL 8 reference docs",
32
- "sha": "PostgreSQL 16.x / MySQL 8.4 docs",
33
- "last_checked": "2026-06-07"
31
+ "repo": "derived: PostgreSQL 18 + MySQL 9.7 reference docs (previously PostgreSQL 16 + MySQL 8)",
32
+ "sha": "re-derived 2026-09-27 against PostgreSQL 18.x / MySQL 9.7: all 12 rows of query-tuning.csv still apply as written on both engines. Three rows gained a version-scoped annotation for a genuinely new capability rather than a rewrite \u2014 row 1 (Slow WHERE on large table) notes PG18's B-tree skip scan, which relaxes the equality-first composite-index rule on PG18+ only; row 5 (JOIN explosion) notes MySQL 9.7's Hypergraph Optimizer, now GA in Community Edition, improving join-order choices automatically; row 12 (JSON column filtering) notes that PG18 flips the GENERATED-column default from STORED to VIRTUAL, and VIRTUAL columns are not indexable, so STORED must now be explicit. PostgreSQL 16.x and MySQL 8.4 remain supported and the patterns apply there unchanged",
33
+ "last_checked": "2026-09-18"
34
34
  }
35
- }
35
+ }
@@ -1,13 +1,13 @@
1
1
  Symptom,Keywords,Root Cause,Strategy,Code Good,Anti-Pattern,Verification,Severity
2
- Slow WHERE on large table,slow query where filter full scan seq scan,Sequential scan despite selective predicate,B-tree index on the filtered column(s); composite index ordered by equality-first then range,"CREATE INDEX idx_orders_status_created ON orders (status, created_at)",Indexing low-cardinality boolean alone; composite ordered range-first,EXPLAIN (ANALYZE) shows Index Scan; rows estimate ≈ actual,HIGH
2
+ Slow WHERE on large table,slow query where filter full scan seq scan,Sequential scan despite selective predicate,B-tree index on the filtered column(s); composite index ordered by equality-first then range (PostgreSQL 18+: skip scan lets the planner use later columns without a leading-column equality predicate — MySQL and pre-18 Postgres still need equality-first ordering),"CREATE INDEX idx_orders_status_created ON orders (status, created_at)",Indexing low-cardinality boolean alone; composite ordered range-first,EXPLAIN (ANALYZE) shows Index Scan (PG 18+: or Index Searches for a skip scan); rows estimate ≈ actual,HIGH
3
3
  ORDER BY ... LIMIT slow,order by limit sort top n latest,Sort node over the whole table for a top-N query,Index matching the ORDER BY direction (including DESC/NULLS) so LIMIT walks the index,CREATE INDEX idx_events_created_desc ON events (created_at DESC),OFFSET pagination for infinite feeds (use keyset),Plan shows Index Scan Backward / no Sort node,HIGH
4
4
  N+1 query loop,n+1 loop per row lazy load orm repeated query,Hundreds of identical queries differing only by id,Eager-load relations / batch with IN(...) or JOIN; dataloader pattern at the API layer,SELECT * FROM comments WHERE post_id IN (...),Fixing with a cache instead of the access pattern,Query count per request flat vs item count,HIGH
5
5
  LIKE '%term%' search,like contains search wildcard fulltext,Leading-wildcard LIKE can't use B-tree,Trigram index (pg_trgm GIN) or full-text search (tsvector + GIN); dedicated engine beyond ~10M rows,CREATE INDEX idx_users_name_trgm ON users USING gin (name gin_trgm_ops),Forcing LOWER() without an expression index,Plan shows Bitmap Index Scan on the GIN index,MEDIUM
6
- JOIN explosion,join many tables slow hash join nested loop,Mis-estimated join order / missing join keys index,Index every FK used in joins; verify row estimates; break monster joins into CTE/temp stages when estimates collapse,ANALYZE tables; index fk columns,Disabling nested loops globally; hint-chasing before stats are fresh,Estimates within ~10x of actuals at every join node,HIGH
6
+ JOIN explosion,join many tables slow hash join nested loop,Mis-estimated join order / missing join keys index,Index every FK used in joins; verify row estimates; break monster joins into CTE/temp stages when estimates collapse (MySQL 9.7: the Hypergraph Optimizer is now GA in Community Edition and can materially improve join-order choices on its own — verify estimates before assuming a manual rewrite is still needed),ANALYZE tables; index fk columns,Disabling nested loops globally; hint-chasing before stats are fresh,Estimates within ~10x of actuals at every join node,HIGH
7
7
  Aggregation over millions of rows,group by count sum report aggregate slow,Repeated full-table aggregation for dashboards,Pre-aggregate: materialized view / rollup table refreshed on schedule or trigger; partial indexes for hot subsets,CREATE MATERIALIZED VIEW daily_rev AS ... REFRESH CONCURRENTLY,Caching in app memory only (cold-start storms),"Dashboard reads hit the rollup, not base tables",MEDIUM
8
8
  Pagination deep offset,offset page 10000 slow deep pagination,OFFSET N scans+discards N rows,Keyset/cursor pagination on a unique ordered key,"WHERE (created_at,id) < (:c,:i) ORDER BY created_at DESC,id DESC LIMIT 20",Hiding offset behind a 'page' param and capping at 1000 as a fix,p99 latency flat across page depth,HIGH
9
9
  Write contention / lock waits,deadlock lock wait contention update hot row,"Hot-row updates serialize (counters, balances)",Row-level design: ledger inserts over UPDATE-in-place; batch with SKIP LOCKED queues; keep transactions short,SELECT ... FOR UPDATE SKIP LOCKED for workers,Retrying deadlocks blindly without ordering writes,Lock wait time ~0 under load test; deadlock rate 0,HIGH
10
10
  Missing/stale statistics,wrong plan estimate stale statistics analyze,Optimizer estimates wildly off → bad plans,Auto-analyze tuned for big tables; manual ANALYZE after bulk loads; extended statistics for correlated columns,"CREATE STATISTICS s_dist (dependencies) ON city,country FROM addr",Hinting every query instead of fixing stats,Plan estimates ≈ actuals after ANALYZE,MEDIUM
11
11
  Over-indexing writes,insert slow many indexes write amplification,Each extra index taxes every INSERT/UPDATE,Audit with index-usage stats; drop unused; covering index to replace several near-duplicates,pg_stat_user_indexes idx_scan = 0 candidates,Adding an index per slow query without retiring old ones,Write p95 recovers; no unused-index rows,MEDIUM
12
12
  SELECT * over wide rows,select star wide row toast network payload,Fetching unused columns (TOAST/LOB) dominates IO,Project needed columns; covering index enables index-only scans,"SELECT id,status,total FROM orders ...",Compressing payloads instead of trimming the select list,Plan shows Index Only Scan where applicable,LOW
13
- JSON column filtering,json jsonb attribute filter schemaless,Filtering inside JSON without index = full scan,"GIN index on jsonb path ops, or generated column + B-tree for hot keys",ALTER TABLE t ADD COLUMN status text GENERATED ALWAYS AS (doc->>'status') STORED; CREATE INDEX ...,Stuffing relational data into one JSON blob,Plan uses the GIN/generated-column index,MEDIUM
13
+ JSON column filtering,json jsonb attribute filter schemaless,Filtering inside JSON without index = full scan,"GIN index on jsonb path ops, or generated column + B-tree for hot keys",ALTER TABLE t ADD COLUMN status text GENERATED ALWAYS AS (doc->>'status') STORED; CREATE INDEX ...; -- PG18+: STORED must be explicit (default flipped to VIRTUAL — not indexable),Stuffing relational data into one JSON blob; relying on the pre-PG18 STORED default,Plan uses the GIN/generated-column index,MEDIUM
@@ -234,6 +234,56 @@ THE Q1-Q6 FLOOR SET IS IDENTICAL IN ALL FOUR MODES.
234
234
  Do not re-derive any of these fields here. This skill is a declared consumer of
235
235
  that object, and the contract's consumer table names it.
236
236
 
237
+ ## Fidelity proof — the chapter matrix
238
+
239
+ ```
240
+ A 1:1 CLAIM IS PROVEN BY A COMMITTED MATRIX, NEVER BY A GREEN SUITE.
241
+ ONE ROW PER HANDOVER CHAPTER. ONE EVIDENCE KIND PER ROW. NO EMPTY CELL.
242
+ A BEHAVIOR TEST ANSWERS "DOES IT WORK", NOT "DOES IT MATCH".
243
+ ```
244
+
245
+ This discharges [`design-fidelity`](../../rules/design-fidelity.md)'s proof
246
+ clause. It fires when a numbered handover is the spec — chapters like
247
+ `10-datenmodell-api.md` … `46-roadmap-achse-randtage.md`, each an abgegrenzter
248
+ contract. Such a handover is already a checklist; the failure it prevents is
249
+ reading it and never working it as one.
250
+
251
+ **Build the matrix from the handover's own numbering**, one row per chapter:
252
+
253
+ | Chapter | Claim it makes | Evidence | Status |
254
+
255
+ **Evidence is exactly one of four kinds**, and the row names which:
256
+
257
+ 1. **Element-scoped screenshot baseline** — `toHaveScreenshot` on the component,
258
+ not the page. Built into Playwright via pixelmatch, so no new dependency
259
+ ([`playwright-testing`](../playwright-testing/SKILL.md)). Mask dynamic
260
+ content (timestamps, running numbers, ids) or the baseline flakes on data
261
+ rather than on design.
262
+ 2. **`toHaveCSS` assertion on the value the chapter names** — the right kind
263
+ when the chapter states a token, a spacing step or a color rather than a
264
+ shape.
265
+ 3. **Behavior spec with a sensitivity probe** — legitimate where the chapter
266
+ describes an interaction. The probe is not optional: neutralise the
267
+ mechanism, watch the spec go red, restore it. A spec never seen red has
268
+ unknown sensitivity and is not evidence.
269
+ 4. **Explicitly not implemented, with the reason** — a real row, not a gap. An
270
+ honest `not implemented` is what makes the other three trustworthy.
271
+
272
+ **The matrix is committed**, not written into a reply. A matrix that lives in a
273
+ chat message dies with the session, which is the difference between a method and
274
+ an artifact — and the whole reason this section exists rather than a paragraph
275
+ telling a reviewer to be thorough.
276
+
277
+ **The staleness trap.** A new handover version ships and the baselines stay
278
+ pinned to the old one, so every screenshot row passes against a reference nobody
279
+ uses any more. Check the baseline timestamps against the handover's own
280
+ CHANGELOG before reading a green matrix as a pass.
281
+
282
+ **What the matrix does not do.** It records what was compared, never that the
283
+ comparison was honest — nothing in this tree reads a handover, so a row naming
284
+ evidence nobody took looks exactly like one naming evidence that was. The
285
+ control is that a reviewer can open it.
286
+
237
287
  ## Review independence — two passes, isolated, in this order
238
288
 
239
289
  ```