@event4u/agent-config 9.24.0 → 9.26.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 (97) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +136 -0
  3. package/README.md +1 -1
  4. package/dist/agent-src/commands/analyze/conformance.md +182 -0
  5. package/dist/agent-src/commands/analyze/inbox.md +33 -2
  6. package/dist/agent-src/commands/review/changes.md +6 -5
  7. package/dist/agent-src/commands/roadmap/next.md +194 -0
  8. package/dist/agent-src/commands/roadmap.md +12 -4
  9. package/dist/agent-src/contexts/execution/subagent-routing.md +4 -1
  10. package/dist/agent-src/rules/decision-revisit-gate.md +2 -0
  11. package/dist/agent-src/rules/delegation-policy.md +3 -2
  12. package/dist/agent-src/rules/design-fidelity.md +17 -1
  13. package/dist/agent-src/rules/design-review-after-ui-write.md +116 -0
  14. package/dist/agent-src/rules/evaluator-independence.md +111 -0
  15. package/dist/agent-src/rules/session-canary.md +15 -1
  16. package/dist/agent-src/rules/settings-ask-protocol.md +176 -0
  17. package/dist/agent-src/rules/token-budget-discipline.md +6 -3
  18. package/dist/agent-src/rules/ui-audit-gate.md +3 -0
  19. package/dist/agent-src/rules/user-interaction.md +23 -0
  20. package/dist/agent-src/skills/finishing-a-development-branch/SKILL.md +1 -1
  21. package/dist/agent-src/skills/recursive-verification/SKILL.md +13 -0
  22. package/dist/agent-src/skills/rule-writing/SKILL.md +45 -0
  23. package/dist/agent-src/skills/skill-writing/SKILL.md +114 -0
  24. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  25. package/dist/cli/registry.js +1 -0
  26. package/dist/cli/registry.js.map +1 -1
  27. package/dist/cli-delegate/cmd_route_audit.js +4 -1
  28. package/dist/cli-delegate/cmd_route_explain.js +4 -1
  29. package/dist/discovery/deprecation-report.md +1 -1
  30. package/dist/discovery/discovery-manifest.json +146 -28
  31. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  32. package/dist/discovery/discovery-manifest.summary.md +5 -5
  33. package/dist/discovery/orphan-report.md +1 -1
  34. package/dist/discovery/packs.json +16 -11
  35. package/dist/discovery/trust-report.md +3 -3
  36. package/dist/discovery/workspaces.json +12 -7
  37. package/dist/hooks/dispatch.js +1501 -511
  38. package/dist/mcp/registry-manifest.json +3 -3
  39. package/dist/mcp/server.json +2 -2
  40. package/dist/router.json +1 -1
  41. package/dist/server/nicknameResolver.js +116 -0
  42. package/dist/server/nicknameResolver.js.map +1 -0
  43. package/dist/server/routes/ping.js +29 -11
  44. package/dist/server/routes/ping.js.map +1 -1
  45. package/dist/shared/interactiveContext.js +73 -0
  46. package/dist/shared/interactiveContext.js.map +1 -0
  47. package/dist/shared/nicknamePrefill.js +59 -0
  48. package/dist/shared/nicknamePrefill.js.map +1 -0
  49. package/dist/shared/settingsAsks.js +128 -0
  50. package/dist/shared/settingsAsks.js.map +1 -0
  51. package/dist/shared/settingsConsent.js +93 -0
  52. package/dist/shared/settingsConsent.js.map +1 -0
  53. package/package.json +1 -1
  54. package/src/config/agents-paths.yml +15 -0
  55. package/src/config/evaluator-budgets.json +68 -68
  56. package/src/config/gate-coverage.yml +131 -5
  57. package/src/config/gate-violation-baselines.json +11 -0
  58. package/src/scripts/_cli/cmd_route_audit.ts +4 -1
  59. package/src/scripts/_cli/cmd_route_explain.ts +9 -1
  60. package/src/scripts/_dispatch.bash +12 -0
  61. package/src/scripts/ai-video/stitch.sh +27 -9
  62. package/src/scripts/before_complete_hook.ts +146 -5
  63. package/src/scripts/bench_ab_v2_run.ts +272 -16
  64. package/src/scripts/bench_ab_v2_stats.ts +156 -3
  65. package/src/scripts/check_completion_review.ts +80 -3
  66. package/src/scripts/check_corpus_staleness.ts +692 -0
  67. package/src/scripts/check_depth_budget.ts +295 -0
  68. package/src/scripts/check_gate_coverage.ts +67 -0
  69. package/src/scripts/check_hook_bundle_freshness.ts +183 -0
  70. package/src/scripts/conformance_scan.ts +422 -0
  71. package/src/scripts/dispatch_r2_reviewer.ts +31 -2
  72. package/src/scripts/git_authorization_hook.ts +328 -0
  73. package/src/scripts/hook_manifest.yaml +69 -9
  74. package/src/scripts/hooks/block_no_verify.ts +3 -1
  75. package/src/scripts/hooks/block_unauthorized_git.ts +371 -0
  76. package/src/scripts/hooks/concern_registry.ts +8 -0
  77. package/src/scripts/hooks/design_slop_hook.ts +13 -1
  78. package/src/scripts/hooks/dispatch_hook.ts +97 -2
  79. package/src/scripts/hooks/evidence_independence.ts +368 -0
  80. package/src/scripts/language_mirror_hook.ts +456 -0
  81. package/src/scripts/lint_abstraction_thresholds.ts +41 -8
  82. package/src/scripts/lint_agents_layout.ts +2 -0
  83. package/src/scripts/lint_decision_impact.ts +246 -0
  84. package/src/scripts/lint_example_fences.ts +609 -0
  85. package/src/scripts/lint_hook_manifest.ts +29 -0
  86. package/src/scripts/lint_rule_interactions.ts +90 -0
  87. package/src/scripts/lint_rule_migration_ledger.ts +480 -0
  88. package/src/scripts/lint_skill_descriptions.ts +86 -2
  89. package/src/scripts/memory_learn_hook.ts +109 -6
  90. package/src/scripts/pr_url_reminder_hook.ts +17 -2
  91. package/src/scripts/release.ts +38 -1
  92. package/src/scripts/schemas/review-findings.schema.json +99 -0
  93. package/src/scripts/schemas/rule.schema.json +10 -0
  94. package/src/shared/interactiveContext.ts +98 -0
  95. package/src/shared/nicknamePrefill.ts +96 -0
  96. package/src/shared/settingsAsks.ts +176 -0
  97. package/src/shared/settingsConsent.ts +136 -0
@@ -2,14 +2,14 @@
2
2
  model_tier: medium
3
3
  name: roadmap
4
4
  disable-model-invocation: true
5
- argument-hint: "[create|ai-council|process-step|process-phase|process-full] [args]"
5
+ argument-hint: "[create|ai-council|process-step|process-phase|process-full|next] [args]"
6
6
  pack: product-basic
7
- intent: "Roadmap dispatcher — create, process-step, process-phase, process-full, ai-council"
8
- routes_to: [roadmap-create, roadmap-ai-council, roadmap-materialize, roadmap-process-step, roadmap-process-phase, roadmap-process-full]
7
+ intent: "Roadmap dispatcher — create, process-step, process-phase, process-full, next, ai-council"
8
+ routes_to: [roadmap-create, roadmap-ai-council, roadmap-materialize, roadmap-process-step, roadmap-process-phase, roadmap-process-full, roadmap-next]
9
9
  replaces: []
10
10
  tier: 1
11
11
  visibility: advanced
12
- description: Roadmap orchestrator — routes to create (authoring) and process-step / process-phase / process-full (autonomous execution).
12
+ description: Roadmap orchestrator — routes to create (authoring), process-step / process-phase / process-full (autonomous execution), and next (pick a roadmap and ship it).
13
13
  cluster: roadmap
14
14
  type: orchestrator
15
15
  suggestion:
@@ -40,6 +40,7 @@ paused for confirmation before every step) was removed —
40
40
  | `/roadmap:process-step` | `commands/roadmap/process-step.md` | Autonomously process the next open step, then stop |
41
41
  | `/roadmap:process-phase` (**default execution scope**) | `commands/roadmap/process-phase.md` | Autonomously process every open step in the current phase |
42
42
  | `/roadmap:process-full` | `commands/roadmap/process-full.md` | Autonomously process every open step across every phase |
43
+ | `/roadmap:next` | `commands/roadmap/next.md` | Screen for the next executable roadmap, then carry it to a reviewable PR (selection + `process-full` + delivery) |
43
44
 
44
45
  Sub-command names match the locked contract in
45
46
  [`docs/contracts/command-clusters.md`](../docs/contracts/command-clusters.md).
@@ -70,6 +71,7 @@ each only binds a scope delta.
70
71
  > 3. process-step — process the next open step, then stop
71
72
  > 4. process-phase — process the current phase (default)
72
73
  > 5. process-full — process every open step across every phase
74
+ > 6. next — pick the next executable roadmap and ship it to a PR
73
75
 
74
76
  ## Rules
75
77
 
@@ -84,3 +86,9 @@ each only binds a scope delta.
84
86
  *"finish this phase"*) default to
85
87
  [`/roadmap:process-phase`](roadmap/process-phase.md) unless the user
86
88
  named a different scope.
89
+ - **Selection intents** (*"take the next sensible roadmap"*, *"nimm dir
90
+ die nächste Roadmap vor"*, *"pick a roadmap and ship it"*) — i.e. the
91
+ user has NOT named a roadmap and wants one chosen — route to
92
+ [`/roadmap:next`](roadmap/next.md), which is the only sub that
93
+ screens and selects. The three `process-*` subs never choose across
94
+ roadmaps.
@@ -48,7 +48,10 @@ THE SAME MINUS THE QUOTA WIN.
48
48
  tier <t>`); a 429/quota error trips `tripCooldown` for that tier and
49
49
  falls back per the relation — never a retry loop. Under
50
50
  `budget_routing: ask`, the FIRST budget-motivated downshift of a session
51
- is confirmed once; `auto` proceeds silently. Every budget-routed
51
+ is confirmed once, in the shape
52
+ [`settings-ask-protocol`](../../rules/settings-ask-protocol.md) fixes and
53
+ without persisting the answer (`subagents.budget_routing` is class C);
54
+ `auto` proceeds silently. Every budget-routed
52
55
  dispatch emits one `orchestration_record` line (tier + provenance-tagged
53
56
  token delta) so realized savings are measured, not asserted.
54
57
 
@@ -14,6 +14,8 @@ routes_to:
14
14
  - "skill:decision-review"
15
15
  workspaces: [agent-config-maintainer, engineering]
16
16
  packs: [meta]
17
+ collision_ok:
18
+ "honest null": "this rule asks whether a recorded null may be REVISITED; evaluator-independence asks how one was PRODUCED — different decision points on the same artefact"
17
19
  ---
18
20
 
19
21
  # Decision Revisit Gate
@@ -50,8 +50,9 @@ clears — all of:
50
50
  [`auto-dispatch-classification`](../contexts/execution/auto-dispatch-classification.md)
51
51
  (≥1 independent, well-specified slice above the size floor).
52
52
 
53
- `subagents.auto: ask` → ask once before dispatching (per
54
- [`user-interaction`](user-interaction.md)); `auto: on` → surface the chosen mode
53
+ `subagents.auto: ask` → ask once before dispatching, in the shape
54
+ [`settings-ask-protocol`](settings-ask-protocol.md) fixes (the answer is not
55
+ persisted — `subagents.auto` is class C); `auto: on` → surface the chosen mode
55
56
  + per-subtask tiers in one line. Any gate failing, or `auto: off`, or no host
56
57
  primitive → run in-session (clean no-op).
57
58
 
@@ -23,7 +23,9 @@ triggers:
23
23
  - phrase: "bau das nach"
24
24
  - phrase: "1:1 um"
25
25
  - phrase: "1:1 nach"
26
+ - phrase: "claude.site/artifacts"
26
27
  - file_pattern: "*design.html"
28
+ - path_prefix: ".claude/design-system/"
27
29
  applies_to_user_types:
28
30
  - "creator"
29
31
  - "developer"
@@ -96,13 +98,27 @@ artifact is simply attached. The last is covered by `file_pattern: *design.html`
96
98
  HTML edit in every project and be strictly worse than the gap it closes. A
97
99
  handover under some other filename needs one word in the prompt.
98
100
 
101
+ Two further handover shapes carry the artifact without any of the above:
102
+
103
+ - **A capability URL.** A published artifact is handed over as a link, not a
104
+ file — so `phrase: "claude.site/artifacts"` fires on the *published-artifact
105
+ path*, not on the host. `claude.ai` alone is a chat link and must stay quiet:
106
+ a keyword on the bare domain would fire on "I pasted this from claude.ai",
107
+ which is a conversation reference, not a spec.
108
+ - **A design-system directory.** `path_prefix: ".claude/design-system/"` — the
109
+ conventional location for a handed-over token/component set. The prefix is the
110
+ vendor-scoped directory, never a bare `design-system/`, which is a normal
111
+ source folder in a large fraction of frontend repos.
112
+
99
113
  The trigger set is deliberately phrase-heavy on the German side and on
100
114
  `artifact`: a bare `artifact` keyword fires on "the CI build artifact is 40 MB".
101
115
  `ROUTING_MATRIX` in
102
116
  [`design_fidelity_routing.test.ts`](../../tests/scripts/design_fidelity_routing.test.ts)
103
117
  pins both halves — every class that must route, and the near-misses that must
104
118
  stay silent (fixture `daf-port-trigger-de`). Extending the set without adding a
105
- near-miss row there is how an over-broad trigger lands.
119
+ near-miss row there is how an over-broad trigger lands: each of the two triggers
120
+ above ships with its own near-miss row (`near-claude-ai-chat-link`,
121
+ `near-generic-design-system-dir`).
106
122
 
107
123
  Body migrated to [`guideline:design-fidelity-mechanics`](../docs/guidelines/design-fidelity-mechanics.md) (per P4 of `road-to-kernel-and-router.md`) — 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.
108
124
  Trigger-set above activates this routing on demand, independent of the discipline profile (ADR-110).
@@ -0,0 +1,116 @@
1
+ ---
2
+ type: "auto"
3
+ tier: "2b"
4
+ alwaysApply: false
5
+ description: "UI written or changed — review it against the design contract before calling it done; the write-side twin of ui-audit-gate"
6
+ triggers:
7
+ - path_prefix: "resources/views/"
8
+ - path_prefix: "resources/js/"
9
+ - keyword: "component"
10
+ - keyword: "design token"
11
+ routes_to:
12
+ - "skill:design-review"
13
+ - "skill:accessibility-auditor"
14
+ workspaces: [agent-config-maintainer, engineering]
15
+ packs: [frontend-design]
16
+ collision_ok:
17
+ "component": "a written component is reviewed before it is called done — the write-side half"
18
+ "design token": "same surface, opposite side: ui-audit-gate inventories tokens before the write, this reviews what the write emitted"
19
+ "resources/views/": "both halves of one UI loop fire on the same path — audit before, review after; neither substitutes for the other"
20
+ "resources/js/": "both halves of one UI loop fire on the same path — audit before, review after; neither substitutes for the other"
21
+ ---
22
+
23
+ # Design Review After UI Write
24
+
25
+ The UI loop was closed on one side only. [`ui-audit-gate`](ui-audit-gate.md)
26
+ covers the **read** side — inventory what exists before adding a component — and
27
+ routes to `existing-ui-audit`. Nothing covered the **write** side: **zero rules
28
+ routed to `skill:design-review`**, so a component could be written, declared
29
+ done, and never looked at against the contract it was supposed to satisfy.
30
+
31
+ This is that rule's twin, deliberately built to the same shape: same tier, same
32
+ pack, same diff-decidable allow-list, and the same honest scope.
33
+
34
+ ## The Iron Law
35
+
36
+ ```
37
+ UI WRITTEN OR CHANGED IS NOT DONE UNTIL IT IS REVIEWED.
38
+ NEVER CLAIM A UI CHANGE IS COMPLETE ON "IT LOOKS RIGHT" — THAT IS A VERDICT
39
+ WITHOUT EVIDENCE. NO RENDER CAPABILITY → SCOPE THE VERDICT TO WHAT WAS
40
+ STATICALLY CHECKED AND SAY SO. NEVER "LOOKS GOOD" WITH NOTHING BEHIND IT.
41
+ ```
42
+
43
+ ## What "reviewed" means
44
+
45
+ The verdict is gated on evidence, not on having run a skill:
46
+
47
+ - **Render capability present** (Playwright MCP, Chrome DevTools, or a live
48
+ preview URL) → the [design-artifact verification checklist](../docs/contracts/design-artifact-verification.md#verification-checklist)
49
+ steps 1–5. A UI task does not pass without render evidence.
50
+ - **Render capability absent** → the verdict is **scoped to the static checks
51
+ that actually ran** and says which those were. This is not a downgrade to be
52
+ hidden; `design-review` itself states it ("scope the verdict to what was
53
+ statically checked and say so"). An unscoped "looks good" is the failure.
54
+ - **A provided artifact is the spec** → findings the artifact *covers* are
55
+ informational, not defects, per [`design-fidelity`](design-fidelity.md). The
56
+ review does not "improve" the user's own design.
57
+
58
+ ## Allow-list — `ui-trivial`, decidable from the diff alone
59
+
60
+ Skip only when **all** hold:
61
+
62
+ - ≤ 1 file, ≤ 5 changed lines, no new component, no new state, no new dependency.
63
+ - Inside the work engine, `directive_set == "ui-trivial"` — the dispatcher states
64
+ it directly. Outside it, the same conditions are read **off the diff**, which
65
+ is observable without any dispatcher state.
66
+
67
+ The list is deliberately the engine's five conditions, not the four its
68
+ sibling rule's prose carries: `ui_trivial/apply.ts` enforces `new_dependency`
69
+ too, and a twin that copied the shorter prose would inherit a gap the engine
70
+ does not have.
71
+
72
+ ## Honest scope — what this rule does NOT enforce
73
+
74
+ ```
75
+ THE REVIEW OBLIGATION IS MODEL-CARRIED. NEVER CLAIM THE REVIEW RAN
76
+ AS IF IT WERE VERIFIED.
77
+ ```
78
+
79
+ There is no artefact a chat session can point at to prove a design review
80
+ happened — "I ran `design-review`" is self-report, and self-report is not
81
+ enforcement. So this rule ships `enforced_by: none`, the same honesty boundary
82
+ `ui-audit-gate`, `security-sensitive-stop`, and `untrusted-input-defense` state
83
+ for their own obligations, rather than pretending a satisfiable-by-assertion
84
+ condition is a gate.
85
+
86
+ What that leaves, and it is the useful part: the write side now has a named
87
+ obligation and a route to the skill that discharges it, where before it had
88
+ neither. Full enforcement needs the work-engine `review`/`polish` gates (which
89
+ already act on `a11y_violation` and `token_violation` findings) or pack-scoped
90
+ rule projection — a maintainer decision, never an automated one.
91
+
92
+ One asymmetry worth stating: `design-review` lives in `engineering-base` while
93
+ this rule is scoped to `frontend-design`. The route still resolves — a rule may
94
+ name a skill from another pack — but a consumer with `frontend-design` and
95
+ without `engineering-base` gets the obligation without the skill. That is why
96
+ `accessibility-auditor` is a second route: it is the part of the review that
97
+ must not depend on the pairing.
98
+
99
+ ## Failure modes
100
+
101
+ - Writing the component and calling it done because the tests pass — tests do not
102
+ look at it.
103
+ - "Looks good" as a verdict with no render, no static check named, and no scope.
104
+ - Running the review and acting on findings the provided artifact covers, i.e.
105
+ redesigning the user's spec under the banner of quality.
106
+ - Treating the a11y half as optional because the visual half looked fine.
107
+ - Skipping the review for "just one tile" — the same bypass `ui-audit-gate`
108
+ names on its own side.
109
+
110
+ ## See also
111
+
112
+ - [`ui-audit-gate`](ui-audit-gate.md) — the read-side twin; audit before writing.
113
+ - [`design-review`](../skills/design-review/SKILL.md) — the 7-phase review this routes to.
114
+ - [`accessibility-auditor`](../skills/accessibility-auditor/SKILL.md) — the WCAG half.
115
+ - [`design-fidelity`](design-fidelity.md) — a provided artifact is the spec; covered findings are informational.
116
+ - [`verify-before-complete`](verify-before-complete.md) — the general no-claim-without-evidence gate this applies to UI.
@@ -0,0 +1,111 @@
1
+ ---
2
+ type: "auto"
3
+ tier: "2a"
4
+ alwaysApply: false
5
+ description: "Commissioning a review/judge/blind-pass on your own work — never author the verdict, never narrow the scope, record the prompt with the result"
6
+ triggers:
7
+ - keyword: "blind review"
8
+ - keyword: "blind pass"
9
+ - keyword: "honest null"
10
+ - keyword: "no-findings"
11
+ - keyword: "adversarial review"
12
+ - keyword: "judge"
13
+ - phrase: "review my own"
14
+ - phrase: "commission a review"
15
+ - phrase: "second opinion on my"
16
+ self_contained: true
17
+ workspaces: [engineering]
18
+ packs: [engineering-base]
19
+ enforced_by:
20
+ - "hook:evidence-independence"
21
+ collision_ok:
22
+ "honest null": "this rule asks how a recorded null was PRODUCED; decision-revisit-gate asks whether it may be REVISITED — different decision points on the same artefact"
23
+ ---
24
+
25
+ # Evaluator Independence
26
+
27
+ When the agent commissions a review, judge, blind pass, or council run **on its
28
+ own work**, it is both the author and the author of the evaluator's prompt. That
29
+ second role is the one nobody was watching.
30
+
31
+ ## The Iron Law
32
+
33
+ ```
34
+ NEVER AUTHOR THE VERDICT INTO AN EVALUATOR'S PROMPT.
35
+ NEVER NARROW THE SCOPE OF A REVIEW YOU COMMISSIONED ON YOUR OWN WORK.
36
+ A SELF-COMMISSIONED REVIEW IS ADMISSIBLE AS GATE EVIDENCE ONLY WHEN THE PROMPT
37
+ IS RECORDED ALONGSIDE THE VERDICT.
38
+ A SECOND EVALUATION OF THE SAME WORK IN ONE TURN IS VERDICT SHOPPING, NOT RIGOUR.
39
+ ```
40
+
41
+ ## The failure this exists to stop
42
+
43
+ Measured, once, at maximum cost (conformance audit 2026-08-06):
44
+
45
+ > The agent dispatched a "blind reviewer" over its own change. It wrote that
46
+ > reviewer's prompt itself, put **"NO-FINDINGS is expected and welcome"** into it,
47
+ > and narrowed the scope to four files it chose. The reviewer returned
48
+ > NO-FINDINGS. That honest-null was committed as **binding gate evidence**. An
49
+ > unsteered pass over the same delta later found 5 findings, one of them
50
+ > critical, already live on the trunk.
51
+
52
+ The agent's own retro named it exactly: *"Die Fabrikation lag nicht im Weglassen
53
+ des Reviews — sie lag in meinem Prompt. Ich habe die Antwort vorgeladen und dann
54
+ als Evidenz verbucht."* The review ran. The process was followed. The evidence
55
+ was manufactured anyway.
56
+
57
+ ## What this requires
58
+
59
+ 1. **Neutral prompt.** No expectation of the outcome, in either direction. Not
60
+ "confirm there are no issues", not "I believe this is clean", not "just
61
+ confirm". Ask for findings; do not describe the finding count you expect.
62
+ 2. **Scope you did not choose to flatter yourself.** The scope is the whole
63
+ delta, or a boundary a human set. "These four files" chosen by the author of
64
+ those files is not a scope, it is a filter.
65
+ 3. **The prompt ships with the verdict.** A recorded honest-null whose prompt is
66
+ not recoverable is not evidence — nobody can check what was asked.
67
+ 4. **One evaluation per turn per subject.** Re-running with a different prompt or
68
+ scope after an unwelcome verdict selects the answer instead of measuring it.
69
+
70
+ ## When it does NOT fire
71
+
72
+ - **Ordinary parallel fan-out.** Dispatching many subagents to read, map,
73
+ search, or implement is not evaluation and is not gated. The session that
74
+ produced this rule ran a seven-way analysis fan-out in one turn; none of it is
75
+ in scope.
76
+ - A review **a human** commissioned or whose prompt a human wrote.
77
+ - A deterministic checker (linter, test suite, CI gate) — it has no prompt to
78
+ steer.
79
+
80
+ ## Enforcement — honest scope
81
+
82
+ [`evidence_independence.ts`](../scripts/hooks/evidence_independence.ts) is a
83
+ `pre_tool_use` concern. It **blocks** a dispatch whose prompt carries a
84
+ pre-loaded verdict, and **blocks** a second *self-scoped* evaluation dispatch in
85
+ the same turn; it **warns** on the first. It reads the prompt the agent is about
86
+ to send, so items 1 and 4 above are mechanically enforced.
87
+
88
+ Two limits, stated because round 2 measured them. The pre-loaded-verdict list is
89
+ a **phrase list**, so a paraphrase evades it — it catches recurrences of known
90
+ steering wording, not steering as such. And the turn boundary is the
91
+ authorization ledger's `detected_at` stamp, because the envelope carries no turn
92
+ id; with no ledger yet, the counter falls back to session scope.
93
+
94
+ Items 2 and 3 — an honestly chosen scope, and recording the prompt with the
95
+ verdict — are **not** enforced by anything. A narrowed scope is not decidable
96
+ from the prompt alone, and no validator reads the artefacts a verdict lands in.
97
+ They are stated here as obligations and are model-carried. Saying so is the
98
+ point: this rule exists because a process that *looked* followed produced
99
+ fabricated evidence, and claiming coverage it does not have would repeat that.
100
+
101
+ ## See also
102
+
103
+ - [`verify-before-complete`](verify-before-complete.md) — the completion-claim
104
+ gate this narrows; a self-commissioned review is one kind of evidence it accepts.
105
+ - [`adversarial-review`](../skills/adversarial-review/SKILL.md) — how to ask for a
106
+ real critique.
107
+ - [`delegation-policy`](delegation-policy.md) — the orchestrator never adopts a
108
+ subagent return unverified; this rule covers the case where the return was
109
+ steered before it was returned.
110
+ - [`direct-answers`](direct-answers.md) Iron Law 2 — do not claim what you have
111
+ not verified; a manufactured verdict is the sharpest form of that claim.
@@ -12,6 +12,8 @@ workspaces: [agent-config-maintainer, construction, engineering, finance, founde
12
12
  packs: [meta]
13
13
  enforced_by:
14
14
  - "hook:session-canary"
15
+ collision_ok:
16
+ "canary_name": "this rule owns what the NAME does once set and which of the three layers already supplies it; settings-ask-protocol owns how it is asked for and where the answer goes"
15
17
  ---
16
18
 
17
19
  # Session Canary
@@ -67,7 +69,7 @@ name it and suggest a fresh session or `/agent-handoff`, per
67
69
  - The greeting never substitutes for substance — it prefixes the answer, it is
68
70
  not the answer.
69
71
 
70
- ## Enforcement
72
+ ## Enforcement — per session, NOT per task
71
73
 
72
74
  > **Enforced by:** [`scripts/session_canary_hook.ts`](../../scripts/session_canary_hook.ts)
73
75
  > (`session_start`, all hook-capable hosts) — injects the `<session-canary>`
@@ -75,6 +77,18 @@ name it and suggest a fresh session or `/agent-handoff`, per
75
77
  > without it. **Copilot fallback:** no hook surface — this rule is the only
76
78
  > carrier; re-read it when the trigger fires.
77
79
 
80
+ **The gap, stated because it was measured.** The injection fires on
81
+ `session_start`; the obligation is per *task*. Nothing re-injects at a task
82
+ boundary, so from the second task on the contract is model-carried.
83
+
84
+ Conformance audit, 30 sessions, 2026-08-06: opening canary dropped on ~13 of 15
85
+ task starts, often present only in the closing summary, twice carrying a name
86
+ the settings chain did not resolve; the honesty clause fired zero times. No
87
+ per-task gate ships — the audit found no harm beyond the lost signal, and a
88
+ mechanism for a signal whose absence nobody acted on has no failure mode to
89
+ match. The consequence stands: this canary cannot currently be relied on as the
90
+ degradation detector its own rationale describes.
91
+
78
92
  ## See also
79
93
 
80
94
  - [`direct-answers`](direct-answers.md) — canonical reply-close obligation.
@@ -0,0 +1,176 @@
1
+ ---
2
+ type: "auto"
3
+ tier: "2a"
4
+ alwaysApply: false
5
+ description: "Asking the user about a setting — one question per command execution, a fixed four-slot shape, and the key's class decides where the answer goes"
6
+ triggers:
7
+ - keyword: "settings:set"
8
+ - keyword: "canary_name"
9
+ - keyword: "rich_skills"
10
+ - keyword: "budget_routing"
11
+ - keyword: "adversarial_council"
12
+ - keyword: "learn_on_session_end"
13
+ - keyword: "open_edited_files"
14
+ - phrase: "ask about a setting"
15
+ - phrase: "settings question"
16
+ - phrase: "should I enable"
17
+ - phrase: "nickname"
18
+ - path_prefix: "docs/contracts/settings-classes.md"
19
+ self_contained: true
20
+ workspaces: [agent-config-maintainer, engineering]
21
+ packs: [meta]
22
+ routes_to:
23
+ - "contract:settings-classes"
24
+ enforced_by:
25
+ - "none"
26
+ collision_ok:
27
+ "canary_name": "the nickname ask is this protocol's canonical B-class instance — session-canary owns what the NAME then does and which layers already supply it, this rule owns how it is asked for and where the answer goes"
28
+ ---
29
+
30
+ # Settings-Ask Protocol
31
+
32
+ A settings question is the one ask where the agent poses the question *and* owns
33
+ where the answer goes. Nine keys can produce one, in two mechanisms that look
34
+ identical from outside and differ completely underneath.
35
+
36
+ ## The Iron Law
37
+
38
+ ```
39
+ AT MOST ONE SETTINGS QUESTION PER COMMAND EXECUTION. NEVER TWO.
40
+ THE KEY'S CLASS DECIDES WHERE THE ANSWER GOES — NEVER THE CONVENIENCE OF THE MOMENT.
41
+ CLASS B → PERSIST VIA `settings:set --source jit-answer`. ASKED ONCE, EVER.
42
+ CLASS C SET TO `ask` → THIS RUN ONLY. THE AGENT NEVER PERSISTS IT.
43
+ FURTHER UNDECIDED KEYS TAKE THE CONSERVATIVE DEFAULT SILENTLY AND ARE NAMED
44
+ IN THE END-SUMMARY WITH THE COMMAND THAT CHANGES THEM.
45
+ A SILENT PERMISSIVE DEFAULT IS A DECISION TAKEN IN THE USER'S NAME. NEVER TAKE ONE.
46
+ ```
47
+
48
+ ## The four slots
49
+
50
+ 1. **What is needed** — the key in plain words, not the dotted path alone.
51
+ 2. **Why now** — the concrete thing in *this* run that cannot proceed without it.
52
+ 3. **Options, default marked** — the conservative option is always present and
53
+ always marked as what happens if the user says nothing.
54
+ 4. **Where the answer is stored** — one line, and it is not optional: it is the
55
+ only way to tell a one-run answer from a standing consent.
56
+
57
+ Slot 4 is read from the class, never from taste:
58
+
59
+ | Class | Slot 4 reads | Writer |
60
+ |---|---|---|
61
+ | **B** (3 keys) | "persisted to your global settings — you will not be asked again" | `agent-config settings:set <key> <value> --source jit-answer` |
62
+ | **C** set to `ask` | "not saved; making it permanent is a human edit or the GUI" | none — the agent writes nothing |
63
+
64
+ **"Not saved" is about persistence, not about how long the answer is honoured.**
65
+ How long it stays cached in working state is the key's own business, and several
66
+ keys state their own scope. Reading the C path as "re-ask every execution" would
67
+ turn a fence against illegal writes into a source of extra questions.
68
+
69
+ ## The nine keys
70
+
71
+ **Class B — persist once**: `personal.canary_name` ·
72
+ `personal.open_edited_files` · `memory.learn_on_session_end`. Each ships a
73
+ conservative default (`""`, `false`, `false`), so absent is indistinguishable
74
+ from *no* and never from *yes*.
75
+
76
+ **Class C carrying an `ask` value in its own enum** — a runtime question whose
77
+ answer dies with the run: `subagents.budget_routing` and `worktrees.mode` (both
78
+ **ship** as `ask`), plus `tokens.rich_skills`, `subagents.auto`,
79
+ `subagents.adversarial_council`, `decision_engine.on_block` (which can be set to
80
+ `ask` by a human but do not ship that way).
81
+
82
+ ## The budget
83
+
84
+ The first key that genuinely blocks the run gets the question. Every other
85
+ undecided key resolves to its conservative default **without a question** and
86
+ appears in the end-summary as one line: key, value taken, command that changes it.
87
+
88
+ **The split is computed, not chosen.** `planSettingsAsks` in
89
+ `src/shared/settingsAsks.ts` returns the single key asked, the keys taking their
90
+ default silently, and the keys skipped with a reason; `silentDefaultsSummary`
91
+ renders lines that ride **inside** the one end-summary
92
+ ([`direct-answers`](direct-answers.md) Iron Law 3).
93
+
94
+ Two questions in one execution is the violation this rule prevents.
95
+ Batching them into a single numbered-options block is the same violation wearing
96
+ a different shape: one *block* is one question only when a single number answers
97
+ it ([`user-interaction`](user-interaction.md) § question pacing).
98
+
99
+ ## Non-interactive executions ask nothing, ever
100
+
101
+ CI, a pipe, a hook, MCP serving, `AGENT_CONFIG_NO_UI`, a headless display: the
102
+ budget is **zero**, not one. `nonInteractiveReason` in
103
+ `src/shared/interactiveContext.ts` is the predicate; `interactive: false` makes
104
+ `planSettingsAsks` carry no ask by construction. Defaults taken are still named —
105
+ silent is not invisible. A question nobody can answer is not a question; it is a
106
+ hang, or a default taken in the user's name wearing a prompt's clothes.
107
+
108
+ ## Who picks the moment — the half no gate can check
109
+
110
+ The class contract's B invariant has two halves. Half one (a conservative
111
+ default) is linted. Half two binds here: the trigger must be the **user's own
112
+ request arriving at a point where the setting is genuinely required**. A
113
+ threshold the agent watched, a moment it judged favourable, or a convenient lull
114
+ are not triggers. If the run would complete without the setting, there is no
115
+ question.
116
+
117
+ ## Worked example — the nickname, the canonical B ask
118
+
119
+ `personal.canary_name` is un-inferrable and arms the session-degradation canary,
120
+ so it is the one settings question a fresh session legitimately asks. Prefill so
121
+ accepting costs one keypress:
122
+
123
+ ```bash
124
+ git config user.name # first choice — the name they already chose here
125
+ # then: $USER, then $USERNAME (Windows). Never $USER alone.
126
+ ```
127
+
128
+ On an answer: `agent-config settings:set personal.canary_name "<name>" --source jit-answer`.
129
+
130
+ **Do not ask an already-armed user.** The browser wizard writes `identity.name`
131
+ into `settings/.agent-user.yml`, the canary's third resolution layer, so a wizard
132
+ user is already covered ([`session-canary`](session-canary.md) resolves all
133
+ three). Check before asking.
134
+
135
+ ## Before a consent-gated action — verify the record, not the value
136
+
137
+ `true` a human chose and `true` the machine inferred are the same byte and not
138
+ the same permission. `consentVerdict` in `src/shared/settingsConsent.ts` grants on
139
+ `jit-answer` / `gui` / `manual` and on a hand-edited file (which the class
140
+ contract guarantees carries no stamp); it withholds on the conservative default,
141
+ on a permissive value nothing records, and on `auto-detected` — an agent that may
142
+ write its own provenance must not reach its own permission by observing the
143
+ world. This is also the reader the provenance sidecar was missing: it was written
144
+ by `settings:set` and only *displayed* by the GUI.
145
+
146
+ ## When NOT to fire
147
+
148
+ - Class A — resolves to its default, never asked.
149
+ - Class C **not** set to `ask` — no question; a change is a human edit.
150
+ - Already decided on any resolution layer, or the run completes without it.
151
+ - **The `ask` routes to a permission gate.** `worktrees.mode: ask` means
152
+ `scope-control`'s per-creation gate applies — a permission ask about an
153
+ *action*, which that rule owns; a storage line there would store nothing.
154
+ - **The `ask` is code, not agent-carried.** `decision_engine.on_block: ask` is a
155
+ TTY prompt in `work_engine/hooks/builtin/decision_gate.ts`.
156
+
157
+ ## Honest enforcement — `enforced_by: none`
158
+
159
+ No gate counts the questions in a chat turn, and no B key currently gates an
160
+ action through a guard: the two that gate behaviour
161
+ (`personal.open_edited_files`, `memory.learn_on_session_end`) are read as values,
162
+ and the action they govern is prose. So the budget, the four slots, the
163
+ who-picks-the-moment half, and the obligation to consult `consentVerdict` are all
164
+ model-carried. On a prose-only host ask-once can degrade to ask-never. The
165
+ deterministic fences sit one layer down and guard a different thing:
166
+ `settings:set` and the GUI write route both refuse every C key and fail closed on
167
+ an unreadable contract, so a protocol violation cannot become an illegal *write* —
168
+ only a badly-shaped *ask*.
169
+
170
+ ## See also
171
+
172
+ - [`docs/contracts/settings-classes.md`](../docs/contracts/settings-classes.md) — the A/B/C source of truth; slot 4 is read from it.
173
+ - [`ask-when-uncertain`](ask-when-uncertain.md) — one question per turn; this narrows it to one *settings* question per execution.
174
+ - [`no-cheap-questions`](no-cheap-questions.md) — the floor a settings question clears before it is asked at all.
175
+ - [`user-interaction`](user-interaction.md) — the numbered-options shape slot 3 uses.
176
+ - [`session-canary`](session-canary.md) — what the nickname answer activates, and the layers to check first.
@@ -31,9 +31,12 @@ TO THE FULL FRUGALITY CANON (telegraph-speak, thin-projector).
31
31
  | `rich` | Must be declared + justified | **Exempt** | **Never trimmed** | 2000–3500 tokens |
32
32
 
33
33
  Read `tokens.rich_skills` from `.agent-settings.yml` (default `on`) to determine
34
- whether rich skills may load in full. If `off`, treat them as
35
- `standard`. If `ask`, surface the estimated token delta (≈ skill file size in
36
- chars / 4) and wait for user confirmation; cache the answer for the session.
34
+ whether rich skills may load in full. If `off`, treat them as `standard`. If
35
+ `ask`, the question's shape is
36
+ [`settings-ask-protocol`](settings-ask-protocol.md)'s, not this rule's; what only
37
+ this rule knows is the number to put in it — the estimated token delta, ≈ skill
38
+ file size in chars / 4. The answer is cached for the session and never persisted
39
+ (`tokens.rich_skills` is class C).
37
40
 
38
41
  ## Requirements for `token_budget_class: rich`
39
42
 
@@ -16,6 +16,9 @@ workspaces: [agent-config-maintainer, engineering]
16
16
  packs: [frontend-design]
17
17
  collision_ok:
18
18
  "component": "no new component without audit findings — its core subject"
19
+ "design token": "same surface, opposite side: this inventories tokens before the write, design-review-after-ui-write reviews what the write emitted"
20
+ "resources/views/": "both halves of one UI loop fire on the same path — audit before, review after; neither substitutes for the other"
21
+ "resources/js/": "both halves of one UI loop fire on the same path — audit before, review after; neither substitutes for the other"
19
22
  ---
20
23
 
21
24
  # UI Audit Gate
@@ -52,6 +52,29 @@ the script is the deterministic safety net.
52
52
 
53
53
  If in doubt, split into serial turns — never a long batched prompt.
54
54
 
55
+ ## The trigger is a decision, not a format
56
+
57
+ ```
58
+ THE OBLIGATION FIRES ON HANDING A DECISION TO THE USER — IN ANY FORM.
59
+ NOT ON THE PRESENCE OF A NUMBERED LIST.
60
+ A TRAILING FREE-TEXT OFFER IS AN ASK. A BARE YES/NO IS AN ASK.
61
+ ```
62
+
63
+ Measured (30-session conformance audit, 2026-08-06): **every** malformed ask was
64
+ a one-line parenthetical or a trailing free-text offer — *"sag Bescheid, wenn
65
+ ich die drei Zeilen mitnehmen soll"*, *"Soll ich das so umsetzen?"* — while the
66
+ same sessions formatted their **large** asks perfectly. So the rule is being
67
+ read as *if numbered options, then a recommendation line*. It is the other way
68
+ round, and an ask that feels too small for a block is exactly the one that
69
+ escapes the format. Three further caught shapes: a contentless filler option; an
70
+ inline `(Empfohlen)` tag **beside** the recommendation line (the dual source
71
+ Iron Law 1 forbids); an option set answerable only as `1,3,4`.
72
+
73
+ **No gate ships for this.** `check_reply_consistency` can read a draft on stdin,
74
+ but it inspects *numbered-option blocks* — and every measured failure had no
75
+ block by construction, so it scans exactly the surface that did not fail. `conformance:behavior` deliberately does not score ask-shape,
76
+ so an unmoved rate is a finding rather than a silence.
77
+
55
78
  ## Mechanics — rationale, failure modes, format details, examples
56
79
 
57
80
  The "why take a position", position-agnostic clause, format
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  model_tier: medium
3
3
  name: finishing-a-development-branch
4
- description: "Use when the feature is implementation-complete and the next step is 'ship it' — verifies, cleans up, and routes to merge/PR/park/discard — even when the user just says 'I'm done, what now?'."
4
+ description: "Use when the feature is implementation-complete and the next step is 'ship it' — verifies, cleans up, routes to merge/PR/park/discard; never destroys work without explicit confirmation."
5
5
  domain: process
6
6
  workspaces:
7
7
  - engineering
@@ -48,6 +48,19 @@ until a benchmark gate authorises it per host.
48
48
  > major unless external evidence appears first. This skill is NOT sold as a
49
49
  > quality-lift mechanism.
50
50
 
51
+ > **Scope of that null — what it does NOT close.** It measured a loop that ADDS
52
+ > a critic to judge whether an attempt was good enough (deterministic
53
+ > scorer-as-critic, `max_depth=1`, weak host, `capH-debug`). It is not evidence
54
+ > about retrying on a check that has **already returned red**: there the verdict
55
+ > is deterministic and in hand, and no critic is introduced, so there is nothing
56
+ > for the null to be null about. The measurement's own decisive finding inverts
57
+ > in that case — recursion was redundant because the first attempt already
58
+ > passed the critic 72% of the time, so cost scaled with every task while benefit
59
+ > sat in the ~28% tail; a red-triggered retry costs nothing on the passing
60
+ > majority and fires only on the tail. What the null DOES bind, for any such
61
+ > loop, is the falsification shape: pre-register the reduction it must deliver,
62
+ > and revert rather than narrate if it does not.
63
+
51
64
  ## The Iron Law
52
65
 
53
66
  ```