@event4u/agent-config 12.1.0 → 14.0.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.
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +164 -186
- package/README.md +1 -1
- package/dist/agent-src/commands/cost/report.md +23 -0
- package/dist/agent-src/commands/evals/roadmap.json +8 -0
- package/dist/agent-src/commands/fix/ci.md +39 -1
- package/dist/agent-src/commands/pr/create.md +65 -4
- package/dist/agent-src/commands/roadmap/next.md +28 -5
- package/dist/agent-src/commands/work.md +16 -0
- package/dist/agent-src/contexts/contracts/command-suggestion-flow.md +47 -0
- package/dist/agent-src/contexts/execution/contract-decision-sheet.md +94 -0
- package/dist/agent-src/contexts/execution/plan-confidence-gate.md +30 -0
- package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +21 -8
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +55 -8
- package/dist/agent-src/contexts/execution/subagent-response-contract.md +42 -0
- package/dist/agent-src/contexts/execution/subagent-routing.md +148 -33
- package/dist/agent-src/contexts/execution/subagent-spawn-contract.md +29 -0
- package/dist/agent-src/contexts/subagent-configuration.md +69 -7
- package/dist/agent-src/rules/autonomous-execution.md +1 -1
- package/dist/agent-src/rules/command-suggestion-policy.md +33 -0
- package/dist/agent-src/rules/design-fidelity.md +1 -1
- package/dist/agent-src/rules/design-review-after-ui-write.md +36 -14
- package/dist/agent-src/rules/evaluator-independence.md +27 -5
- package/dist/agent-src/rules/git-history-discipline.md +5 -1
- package/dist/agent-src/rules/missing-skill-recovery.md +89 -0
- package/dist/agent-src/rules/ui-audit-gate.md +34 -12
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +33 -0
- package/dist/agent-src/scripts/gate_execute.ts +395 -0
- package/dist/agent-src/scripts/resume_probe.ts +422 -0
- package/dist/agent-src/scripts/roadmap_gates.ts +138 -4
- package/dist/agent-src/scripts/update_roadmap_progress.ts +70 -4
- package/dist/agent-src/skills/ai-council/SKILL.md +61 -0
- package/dist/agent-src/skills/authz-review/SKILL.md +4 -0
- package/dist/agent-src/skills/design-system-capture/SKILL.md +4 -0
- package/dist/agent-src/skills/design-system-capture/references/snapshot-preference-order.md +77 -0
- package/dist/agent-src/skills/experiment-loop/SKILL.md +116 -0
- package/dist/agent-src/skills/experiment-loop/evals/output-schema.yml +27 -0
- package/dist/agent-src/skills/experiment-loop/evals/triggers.json +17 -0
- package/dist/agent-src/skills/experiment-loop/references/pivot-ladder.md +54 -0
- package/dist/agent-src/skills/experiment-loop/references/protocol.md +61 -0
- package/dist/agent-src/skills/experiment-loop/references/register-format.md +66 -0
- package/dist/agent-src/skills/merge-conflicts/SKILL.md +4 -0
- package/dist/agent-src/skills/prompt-optimizer/SKILL.md +17 -1
- package/dist/agent-src/skills/roadmap-management/SKILL.md +2 -2
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +5 -5
- package/dist/agent-src/skills/subagent-orchestration/schemas/team-review-status.json +8 -3
- package/dist/agent-src/skills/systematic-debugging/SKILL.md +4 -0
- package/dist/agent-src/skills/threat-modeling/SKILL.md +3 -0
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +43 -3
- package/dist/cli/registry.js +1 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli-delegate/{chunk-K34QTSD5.js → chunk-7PZ4FSZB.js} +368 -191
- package/dist/cli-delegate/{chunk-55WZN5VF.js → chunk-EVTY7ISR.js} +2 -2
- package/dist/cli-delegate/{chunk-O52B4F5S.js → chunk-F3YUF7SA.js} +1 -1
- package/dist/cli-delegate/{chunk-LKZ5DOYW.js → chunk-XURJ4AQC.js} +11 -3
- package/dist/cli-delegate/cmd_conformance.js +224 -104
- package/dist/cli-delegate/cmd_doctor.js +2 -2
- package/dist/cli-delegate/cmd_export.js +2 -2
- package/dist/cli-delegate/cmd_handoff.js +1 -1
- package/dist/cli-delegate/cmd_prune.js +2 -2
- package/dist/cli-delegate/cmd_settings_migrate.js +2 -2
- package/dist/cli-delegate/cmd_settings_set.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +2 -2
- package/dist/cli-delegate/cmd_uninstall.js +2 -2
- package/dist/cli-delegate/cmd_validate.js +2 -2
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +73 -30
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +7 -5
- package/dist/discovery/trust-report.md +3 -3
- package/dist/discovery/workspaces.json +6 -4
- package/dist/hooks/dispatch.js +2653 -1365
- package/dist/install/install.mjs +12 -4
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +2679 -887
- package/dist/router.json +1 -1
- package/dist/scripts/condense.js +1 -1
- package/dist/scripts/condense.js.map +1 -1
- package/dist/server/schemas/settings.js +2 -2
- package/dist/server/schemas/settings.js.map +1 -1
- package/dist/ui/assets/{index-B0aMJnuz.js → index-C1pBRm1f.js} +2 -2
- package/dist/ui/assets/index-C1pBRm1f.js.map +1 -0
- package/dist/ui/index.html +1 -1
- package/docs/guidelines/design-fidelity-mechanics.md +21 -0
- package/docs/guidelines/design-handover-extraction.md +87 -0
- package/docs/guidelines/prompt-templates.md +24 -1
- package/package.json +1 -1
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +33 -0
- package/src/agent-src/scripts/gate_execute.ts +395 -0
- package/src/agent-src/scripts/resume_probe.ts +422 -0
- package/src/agent-src/scripts/roadmap_gates.ts +138 -4
- package/src/agent-src/scripts/update_roadmap_progress.ts +70 -4
- package/src/config/ci-local-parity.yml +13 -0
- package/src/config/evaluator-budgets.json +9 -8
- package/src/config/gate-coverage.yml +140 -12
- package/src/config/gate-violation-baselines.json +9 -3
- package/src/config/hook-token-budget.json +8 -1
- package/src/config/rule-activation-census.json +41 -0
- package/src/config/rule-stub-ceilings.json +52 -0
- package/src/scripts/_dispatch.bash +4 -0
- package/src/scripts/_lib/bench_ab_complexity.ts +439 -0
- package/src/scripts/_lib/bench_ab_safety_tier.ts +142 -0
- package/src/scripts/_lib/bench_ab_scoring_v2.ts +28 -3
- package/src/scripts/_lib/bench_ab_search_adherence.ts +423 -0
- package/src/scripts/_lib/bench_ab_size_claim.ts +206 -0
- package/src/scripts/_lib/bench_ab_workspace.ts +111 -0
- package/src/scripts/_lib/evaluator_contract.ts +159 -0
- package/src/scripts/_lib/gh_transient.ts +80 -0
- package/src/scripts/_lib/release_material.ts +16 -5
- package/src/scripts/_lib/review_independence.ts +111 -0
- package/src/scripts/_lib/session_register.ts +14 -0
- package/src/scripts/_lib/skill_catalogue.ts +278 -5
- package/src/scripts/_lib/skill_catalogue_series.ts +411 -0
- package/src/scripts/_lib/tier_budget_routing.ts +31 -331
- package/src/scripts/_lib/turn_end_refusals.ts +482 -0
- package/src/scripts/ai_council/_py_json.ts +96 -0
- package/src/scripts/ai_council/cli_call_budget.ts +357 -0
- package/src/scripts/ai_council/clients.ts +101 -164
- package/src/scripts/ai_council/config.ts +25 -11
- package/src/scripts/ai_council/probe_store.ts +196 -0
- package/src/scripts/ai_council/qualification.ts +425 -0
- package/src/scripts/ai_council/qualification_wiring.ts +243 -0
- package/src/scripts/ai_council/quorum_wiring.ts +211 -0
- package/src/scripts/ai_team/team_dispatch.ts +40 -6
- package/src/scripts/bench_ab_v2_complexity.ts +252 -0
- package/src/scripts/bench_ab_v2_run.ts +3 -42
- package/src/scripts/bench_ab_v2_safety.ts +296 -0
- package/src/scripts/bench_ab_v2_search.ts +343 -0
- package/src/scripts/bench_ab_v2_stats.ts +191 -0
- package/src/scripts/build_archive_index.ts +383 -0
- package/src/scripts/capture_skill_catalogue.ts +369 -4
- package/src/scripts/check_evaluator_schema.ts +249 -0
- package/src/scripts/check_pr_ci_current.ts +409 -0
- package/src/scripts/check_review_schema.ts +195 -0
- package/src/scripts/check_rule_activation_census.ts +451 -0
- package/src/scripts/check_rule_stub_ceiling.ts +1128 -0
- package/src/scripts/check_source_size_budget.ts +428 -0
- package/src/scripts/check_suppression_hygiene.ts +5 -1
- package/src/scripts/condense.ts +1 -1
- package/src/scripts/cost/backfill_rates.mjs +298 -0
- package/src/scripts/cost/budget.mjs +12 -32
- package/src/scripts/cost_summary.ts +25 -0
- package/src/scripts/council_cli.ts +141 -191
- package/src/scripts/dispatch_r2_reviewer.ts +8 -1
- package/src/scripts/external_sources_denylist.json +1 -0
- package/src/scripts/hook_manifest.yaml +99 -6
- package/src/scripts/hooks/concern_registry.ts +6 -0
- package/src/scripts/hooks/dispatch_hook.ts +43 -1
- package/src/scripts/hooks/interruption_ledger_hook.ts +256 -0
- package/src/scripts/hooks/ship_diff_volume_hook.ts +180 -0
- package/src/scripts/hooks/skill_route_hook.ts +226 -0
- package/src/scripts/hooks/turn_end_gate_hook.ts +119 -26
- package/src/scripts/hooks/ui_route_nudge_hook.ts +6 -3
- package/src/scripts/hooks_doctor.ts +112 -0
- package/src/scripts/interruption_report.ts +443 -0
- package/src/scripts/lint_design_antipattern_parity.ts +40 -6
- package/src/scripts/lint_evidence_artifacts.ts +359 -0
- package/src/scripts/lint_harvest_provenance.ts +35 -1
- package/src/scripts/lint_roadmap_blockers.ts +65 -0
- package/src/scripts/lint_roadmap_complexity.ts +7 -1
- package/src/scripts/lint_rule_skill_pack_reach.ts +43 -0
- package/src/scripts/lint_skill_router_head.ts +21 -0
- package/src/scripts/mcp_server/consumer_tool_catalog.json +26 -3
- package/src/scripts/mcp_server/tool_catalog_source.ts +6 -24
- package/src/scripts/mcp_server/tools.ts +87 -0
- package/src/scripts/release.ts +43 -58
- package/src/scripts/routing_doctor.ts +50 -13
- package/src/scripts/rule_activation_census.ts +292 -0
- package/src/scripts/schemas/command.schema.json +1 -1
- package/src/scripts/schemas/evaluator-output.schema.json +60 -0
- package/src/scripts/schemas/review-findings.schema.json +31 -0
- package/src/scripts/schemas/skill.schema.json +18 -1
- package/src/scripts/self_review_gate.ts +6 -0
- package/src/scripts/session_register_hook.ts +30 -1
- package/src/scripts/sync_pr_branch.ts +271 -0
- package/src/scripts/test_council_qualification.ts +213 -0
- package/src/scripts/trigger_coverage.ts +224 -3
- package/src/server/schemas/settings.ts +2 -2
- package/dist/ui/assets/index-B0aMJnuz.js.map +0 -1
- package/src/config/budget-routing.json +0 -7
|
@@ -8,8 +8,10 @@ provider's model or billing rule.
|
|
|
8
8
|
|
|
9
9
|
## Inputs
|
|
10
10
|
|
|
11
|
-
- The sub-task's declared `model_tier` (`lite | medium | high |
|
|
12
|
-
per [`model-recommendations`](../model-recommendations.md)).
|
|
11
|
+
- The sub-task's declared `model_tier` (`lite | medium | high | frontier |
|
|
12
|
+
inherit`, per [`model-recommendations`](../model-recommendations.md)).
|
|
13
|
+
`frontier` (ADR-232) is declarable and opt-in; it is never the resolution of
|
|
14
|
+
`inherit` — see the top-band invariant below.
|
|
13
15
|
- `subagents.downshift`, `subagents.quota_arbitrage`, `subagents.model_map`
|
|
14
16
|
(see [`auto-orchestration-activation`](auto-orchestration-activation.md)).
|
|
15
17
|
- The host-capability manifest's `separate_quota_pool`
|
|
@@ -27,43 +29,154 @@ THE SAME MINUS THE QUOTA WIN.
|
|
|
27
29
|
1. **Downshift off** (`downshift: false`) → every sub-task runs on the session
|
|
28
30
|
tier. No routing change.
|
|
29
31
|
2. **Downshift on** → a sub-task runs on its declared tier; an `inherit` task
|
|
30
|
-
runs on the session tier
|
|
31
|
-
`model_map`; an empty entry means "use
|
|
32
|
-
baked-in provider model name.
|
|
32
|
+
runs on the session tier, **bounded by the top-band invariant below**. The
|
|
33
|
+
tier resolves to a model alias via `model_map`; an empty entry means "use
|
|
34
|
+
the tier's runtime default" — never a baked-in provider model name.
|
|
33
35
|
3. **Quota arbitrage** → prefer the **separate** quota pool for the sub-task
|
|
34
36
|
**only when** `subagents.quota_arbitrage == true` **and**
|
|
35
37
|
`manifest.separate_quota_pool == true`. Otherwise the shared pool is used and
|
|
36
38
|
the tier/model choice is unchanged. This is the only place the
|
|
37
39
|
"Sonnet-has-its-own-allowance" idea lives, and it lives as a runtime-detected
|
|
38
40
|
flag, never as portable prose.
|
|
39
|
-
4. **Budget routing
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
`
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
41
|
+
4. **Budget routing — ARCHIVED 2026-08-16, there is no fourth step.** This
|
|
42
|
+
position used to describe a budget relation applied after the tier resolves
|
|
43
|
+
per 1–3: cheapest classifier-adequate tier WITH available budget, an atomic
|
|
44
|
+
pre-dispatch reserve, a cool-down on quota errors. None of it exists any
|
|
45
|
+
more. A converged AI-council verdict (anthropic + openai, 2 of 2) archived
|
|
46
|
+
`pickTier` and the permit lifecycle, because the `routing_switch` they
|
|
47
|
+
required lost its only source when `subagents.budget_routing` was deliberately
|
|
48
|
+
deleted by always-on orchestration — so wiring meant inventing a replacement
|
|
49
|
+
for a removed category — and because `session_tier` sits non-null in 0 of 327
|
|
50
|
+
records, leaving the saving unmeasurable in principle. Migration record and
|
|
51
|
+
the union revisit-if:
|
|
52
|
+
[`budget-routing` contract](../../../../docs/contracts/budget-routing.md).
|
|
53
|
+
**Tier resolution therefore ends at step 3.** What survives of the module is
|
|
54
|
+
`TIER_ORDER` and `readCooldowns`, read by `routing:doctor` as a diagnostic —
|
|
55
|
+
monitoring, not routing, and note that nothing writes the cool-down file any
|
|
56
|
+
more, which is why the doctor reports that state as *unavailable, no
|
|
57
|
+
producer* rather than as a measured "not cooling".
|
|
58
|
+
|
|
59
|
+
### The top-band invariant (binding)
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
UNDER A TOP-BAND SESSION, `inherit` RESOLVES TO AT MOST `high`.
|
|
63
|
+
A SLICE THAT GENUINELY NEEDS THE SESSION'S OWN BAND DECLARES IT.
|
|
64
|
+
ONE TOP-BAND CONTEXT PER TASK — THE ORCHESTRATOR'S. NEVER A SECOND BY DEFAULT.
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Read as one line: an undeclared slice under a top-band session runs at most
|
|
68
|
+
`high`, never the session's own band.
|
|
69
|
+
|
|
70
|
+
`inherit` means *model-agnostic*, not *whatever the session happens to cost*.
|
|
71
|
+
Left unbounded it is the one declaration that silently buys the most expensive
|
|
72
|
+
band available, for exactly the slices whose authors judged the model choice
|
|
73
|
+
not to matter — the weakest possible reason to spend the most.
|
|
74
|
+
|
|
75
|
+
**The clamp is `high`, not the top mapped tier, and the distinction is not
|
|
76
|
+
cosmetic.** ADR-232 added `frontier` to the tier→model map, so the top *mapped*
|
|
77
|
+
rung is now `frontier`; clamping there would clamp nothing. The bound is the
|
|
78
|
+
top **generally-recommended** band, which is what
|
|
79
|
+
[`model-recommendations`](../model-recommendations.md) already states from the
|
|
80
|
+
other side — its `frontier` row reads *"Never the resolution of `inherit`"*.
|
|
81
|
+
This clause is that same rule written where the resolution actually happens.
|
|
82
|
+
|
|
83
|
+
Consequences, stated so the cost stays visible rather than removed:
|
|
84
|
+
|
|
85
|
+
- A slice that needs `frontier` **declares `model_tier: frontier`** — a value
|
|
86
|
+
§ Inputs above lists as declarable, precisely so this escape hatch is legal
|
|
87
|
+
rather than instructed-but-forbidden. The declaration is the whole point:
|
|
88
|
+
the spend becomes an authored decision with a name on it instead of a
|
|
89
|
+
default nobody chose.
|
|
90
|
+
- The clamp changes only the **undeclared** case. Every explicit
|
|
91
|
+
`model_tier:` is honoured verbatim, upward included.
|
|
92
|
+
- A session running *below* `high` is untouched — `inherit` still resolves to
|
|
93
|
+
the session tier. "At most" is a ceiling, never a floor, and this clause
|
|
94
|
+
never promotes a slice.
|
|
95
|
+
- A **declared `frontier` implementer** keeps its band, and its judge is
|
|
96
|
+
governed by [`subagent-configuration`](../subagent-configuration.md)
|
|
97
|
+
§ The judge cap — which handles that case explicitly rather than leaving
|
|
98
|
+
the reviewer weaker than the author.
|
|
99
|
+
|
|
100
|
+
**Honest scope.** This is a policy clause in a context file, so it binds the
|
|
101
|
+
agent that reads it and nothing else; no gate re-derives an `inherit`
|
|
102
|
+
resolution at dispatch time. `enforced_by: none`, deliberately — the same
|
|
103
|
+
boundary the safety-floor rules state for their own obligations.
|
|
104
|
+
|
|
105
|
+
### The non-escalation floor (binding)
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
A SLICE WHOSE DISPATCH OVERHEAD EXCEEDS THE SAVING FROM DOWNSHIFTING
|
|
109
|
+
STAYS IN-SESSION. SPLITTING WORK WHOSE OVERHEAD EATS ITS OWN SAVING
|
|
110
|
+
IS THE ANTI-GOAL, NOT THE MECHANISM WORKING.
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Every dispatch pays a fixed cost the in-session path does not: the slice's
|
|
114
|
+
prompt is re-sent to a fresh context, the return is read back, and the
|
|
115
|
+
orchestrator verifies it. Below some slice size that overhead exceeds
|
|
116
|
+
whatever the cheaper tier saved, and the delegation is a net loss dressed as
|
|
117
|
+
an optimisation.
|
|
118
|
+
|
|
119
|
+
**The floor is a rule, not a number — and the reason is measured, not
|
|
120
|
+
assumed.** The step that authored this clause expected the same-band spawn
|
|
121
|
+
distribution to supply the number. It cannot, and the corpus says so
|
|
122
|
+
precisely. Over the full 327-record `orchestration` corpus (2026-07 plus
|
|
123
|
+
2026-08):
|
|
124
|
+
|
|
125
|
+
| Field the saving model needs | Non-null records |
|
|
126
|
+
|---|---:|
|
|
127
|
+
| `dispatch_tokens` | 40 |
|
|
128
|
+
| `tier_chosen` | 1 |
|
|
129
|
+
| `session_tier` | **0** |
|
|
130
|
+
|
|
131
|
+
The three must co-occur on one dispatch to model a reduction, so the usable
|
|
132
|
+
intersection is **zero**. This is not a small sample — it is an empty one, and
|
|
133
|
+
`orchestration_savings_report.ts` already prints exactly that conclusion
|
|
134
|
+
(`MODELED cost reduction: n/a (needs dispatch_tokens + session_tier +
|
|
135
|
+
tier_chosen on a dispatch)`). `token_delta` does not rescue it: the hook
|
|
136
|
+
writes it as a constant `0` with provenance `estimated`, deliberately, because
|
|
137
|
+
no in-session counterfactual exists on disk to difference against.
|
|
138
|
+
|
|
139
|
+
So the floor binds as a judgement with a named direction rather than a
|
|
140
|
+
threshold:
|
|
141
|
+
|
|
142
|
+
- **Default to in-session** when the slice is small enough that stating it
|
|
143
|
+
costs about as much as doing it — a single-file edit, one grep, one
|
|
144
|
+
question with a known answer.
|
|
145
|
+
- **Delegate** when the slice carries its own reading (a file set to sweep, an
|
|
146
|
+
independent verification, a search whose output you do not want in context)
|
|
147
|
+
— there the returned conclusion is the saving, and it is not in tokens.
|
|
148
|
+
- **Never delegate to hit a target.** A dispatch count is not an outcome.
|
|
149
|
+
|
|
150
|
+
*Revisit-if:* a single dispatch record carries `dispatch_tokens`,
|
|
151
|
+
`session_tier` and `tier_chosen` together. At that point the floor is
|
|
152
|
+
computable and this clause should be replaced by the number, not amended
|
|
153
|
+
toward it. Filling `session_tier` is the blocking gap — it exists in the
|
|
154
|
+
schema and on the manual `orchestration_record` CLI path (`--session-tier`),
|
|
155
|
+
and the hook that produced all 327 records never sets it.
|
|
59
156
|
|
|
60
157
|
**Cache trade-off (road-to-cache-economy Phase 4).** A tier downshift changes
|
|
61
|
-
the sub-task's model, and the prompt cache is keyed by `(model, prefix)
|
|
62
|
-
a downshifted leg forfeits its model-scoped cache reads AND
|
|
63
|
-
shared prefix into two caches (downshifted legs vs.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
158
|
+
the sub-task's model, and the prompt cache is keyed by `(model, prefix)`. The
|
|
159
|
+
concern was that a downshifted leg forfeits its model-scoped cache reads AND
|
|
160
|
+
splits a cohort's shared prefix into two caches (downshifted legs vs.
|
|
161
|
+
session-tier legs).
|
|
162
|
+
|
|
163
|
+
**Measured 2026-08-16 —
|
|
164
|
+
[`downshift-vs-cache.md`](../../../../agents/evidence/analysis/downshift-vs-cache.md),
|
|
165
|
+
611 subagent legs / 16,612 calls.** The first half does not hold: a subagent
|
|
166
|
+
leg's **first call realizes 2.8 % cache read**, so it starts cold and does not
|
|
167
|
+
inherit the session's cache — a downshift forfeits a cache the leg never had.
|
|
168
|
+
The cache is not lost, it is created on the other model and then read for the
|
|
169
|
+
rest of the leg (median 18 calls per leg, ~96.9 % read share). The second half
|
|
170
|
+
is **not measured** — nothing sizes cohort prefix sharing — but it is bounded
|
|
171
|
+
above: prefix splitting is a write-side cost, and writes are **3.1 %** of
|
|
172
|
+
subagent billable input against a 96.9 % read surface. Even attributing every
|
|
173
|
+
write to splitting, the two sit about an order of magnitude apart, in favour of
|
|
174
|
+
the downshift, so the direction does not depend on the unmeasured fraction.
|
|
175
|
+
|
|
176
|
+
This resolves the direction; it does not license downshifting as a target. The
|
|
177
|
+
cold start is paid per leg regardless of tier, which is precisely what the
|
|
178
|
+
non-escalation floor above bounds. Analogous downgrade/cache coupling on the
|
|
179
|
+
council side: see
|
|
67
180
|
[`docs/contracts/ai-council-config.md`](../../../../docs/contracts/ai-council-config.md)
|
|
68
181
|
§ `model_downgrade` for the analogous downgrade/cache coupling this suite
|
|
69
182
|
already ships on the council side.
|
|
@@ -80,8 +193,10 @@ rule, or context asserts "model X is free".
|
|
|
80
193
|
[`src/scripts/_lib/subagent_routing.ts`](../../../../src/scripts/_lib/subagent_routing.ts)
|
|
81
194
|
(`resolveSubagentRouting`), covered by
|
|
82
195
|
[`tests/scripts/_lib_subagent_routing.test.ts`](../../../../tests/scripts/_lib_subagent_routing.test.ts).
|
|
83
|
-
|
|
84
|
-
|
|
196
|
+
Tier vocabulary + cool-down state:
|
|
197
|
+
[`src/scripts/_lib/tier_budget_routing.ts`](../../../../src/scripts/_lib/tier_budget_routing.ts)
|
|
198
|
+
(`TIER_ORDER`, `readCooldowns` — the budget decision layer that used to live
|
|
199
|
+
there is archived, see step 4), covered by
|
|
85
200
|
[`tests/scripts/tier_budget_routing.test.ts`](../../../../tests/scripts/tier_budget_routing.test.ts);
|
|
86
201
|
live state: `agent-config routing:doctor` (orchestration section).
|
|
87
202
|
|
|
@@ -170,6 +170,35 @@ contingency.
|
|
|
170
170
|
subagent's output is never auto-persisted into memory — promotion is
|
|
171
171
|
always the human-gated flow (ADR-098 floor). Auto-surface, never
|
|
172
172
|
auto-write.
|
|
173
|
+
- **(f) Return shape — text-only final message, disk copy written first.** Two
|
|
174
|
+
clauses, and they ride **here**, at spawn, rather than in a reusable agent
|
|
175
|
+
definition: a delivery duty stated in an agent definition measured 0/2 against
|
|
176
|
+
1/1 for the identical duty carried in the dispatch prompt (practitioner
|
|
177
|
+
report, n small), which is the same verbatim-at-spawn discipline as (a)–(e).
|
|
178
|
+
- **The final message is a single text-only envelope — never end on a tool
|
|
179
|
+
call.** Measured on host 2.1.229 with a matched control dispatched in the
|
|
180
|
+
same turn: the arm told to emit its report and then make one final
|
|
181
|
+
`echo done` call returned **`(no output)`** to its parent after 3 tool uses
|
|
182
|
+
and 18,242 tokens, while the control ending on assistant text returned the
|
|
183
|
+
complete report. The work was paid for in full and discarded in full
|
|
184
|
+
([`subagent-lifecycle-phase0-return-channel.md`](../../../../agents/evidence/investigations/subagent-lifecycle-phase0-return-channel.md)
|
|
185
|
+
§ F1).
|
|
186
|
+
- **Write the envelope to the runtime artifact dir before emitting it.** Disk
|
|
187
|
+
is the durable channel, the message the fast one — same envelope, so the
|
|
188
|
+
orchestrator still ingests exactly one shape
|
|
189
|
+
([response contract § Durable copy](subagent-response-contract.md#durable-copy--the-envelope-on-disk-before-the-message)).
|
|
190
|
+
|
|
191
|
+
**No carve-out for verifier dispatches.** An async verifier — a subagent that
|
|
192
|
+
screenshots, grades, and reports back — rides this identical return channel,
|
|
193
|
+
and one that grades and never delivers is two operator symptoms in a single
|
|
194
|
+
run: work that looks endless from the orchestrator's side, and work that
|
|
195
|
+
finished without returning. Rule (f) binds it like any other worker.
|
|
196
|
+
|
|
197
|
+
**Honest scope.** Nothing enforces (f). It is prompt-carried text, so a worker
|
|
198
|
+
that ignores it fails exactly as before — the clause buys a stated duty and a
|
|
199
|
+
known-good path to look in, not a guarantee. The deterministic half needs a
|
|
200
|
+
`subagent_stop` concern that reads the disk copy, which is planned and not
|
|
201
|
+
shipped.
|
|
173
202
|
|
|
174
203
|
## Hand-off worked examples — step N output feeds step N+1
|
|
175
204
|
|
|
@@ -15,21 +15,83 @@ Loaded by the `subagent-orchestration` skill and the `/do-and-judge`,
|
|
|
15
15
|
## Model tier ladder
|
|
16
16
|
|
|
17
17
|
The "one tier up" fallback walks this ladder. Session model is the
|
|
18
|
-
starting point; judge picks the tier above.
|
|
18
|
+
starting point; judge picks the tier above. The ladder is written in
|
|
19
|
+
**bands**, not vendor models — the package keeps exactly one tier→model
|
|
20
|
+
mapping and it lives in
|
|
21
|
+
[`model-recommendations`](model-recommendations.md) (ADR-035 § 3). A
|
|
22
|
+
second per-vendor ladder here would be the two-clocks drift ADR-232 was
|
|
23
|
+
careful not to create.
|
|
19
24
|
|
|
20
25
|
```
|
|
21
|
-
|
|
26
|
+
lite → medium → high
|
|
22
27
|
```
|
|
23
28
|
|
|
24
|
-
If the session runs
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
If the session runs at **`high`**, judge stays at `high`. If the session
|
|
30
|
+
runs at **`medium`**, judge defaults to `high`. If the session runs at
|
|
31
|
+
**`lite`**, judge defaults to `medium`.
|
|
32
|
+
|
|
33
|
+
### The judge cap (binding)
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
THE ONE-TIER-UP ESCALATION STOPS AT `high` — IT NEVER CLIMBS INTO `frontier`.
|
|
37
|
+
A JUDGE IS NEVER BELOW ITS OWN IMPLEMENTER: A DECLARED `frontier`
|
|
38
|
+
IMPLEMENTER KEEPS A `frontier` JUDGE.
|
|
39
|
+
A SATURATED LADDER ESCALATES CROSS-VENDOR VIA THE COUNCIL —
|
|
40
|
+
NEVER INTO A SECOND SAME-VENDOR TOP-BAND AGENT.
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Two clauses that are easy to collapse into one and must not be. The cap
|
|
44
|
+
binds the **escalation**, not the floor:
|
|
45
|
+
|
|
46
|
+
| Implementer band | Judge band | Why |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| `lite` | `medium` | one tier up |
|
|
49
|
+
| `medium` | `high` | one tier up |
|
|
50
|
+
| `high` | `high` | escalation capped — never climbs into `frontier` |
|
|
51
|
+
| `frontier` | **`frontier`** | the floor wins: a judge is never below its author |
|
|
52
|
+
|
|
53
|
+
`frontier` (ADR-232) sits above `high` in the vocabulary, so a naive
|
|
54
|
+
"one tier up" would resolve a `high` implementer's judge to `frontier`
|
|
55
|
+
and buy the most expensive band available for every verification pass.
|
|
56
|
+
The cap forecloses that — `frontier` is opt-in by declaration only.
|
|
57
|
+
|
|
58
|
+
**But the cap must not invert the ladder it protects.** Reading it as a
|
|
59
|
+
flat ceiling would give a declared `frontier` implementer a `high`
|
|
60
|
+
judge, i.e. a reviewer strictly *weaker* than the author — worse than
|
|
61
|
+
the same-band case the one-tier-up rule exists to avoid, and a direct
|
|
62
|
+
contradiction of "never downshifts its judge below what the verify
|
|
63
|
+
contract requires" below. So `frontier` reaches the judge only where
|
|
64
|
+
the implementer already declared it, never by escalation from `high`.
|
|
65
|
+
|
|
66
|
+
**What to do when the ladder saturates.** At `high` and at `frontier`
|
|
67
|
+
the judge is same-band — the reviewer is no stronger than the author,
|
|
68
|
+
which is the condition the one-tier-up rule existed to avoid. The
|
|
69
|
+
answer is *different vendor*, not *bigger model*:
|
|
70
|
+
|
|
71
|
+
- Route the saturation case through
|
|
72
|
+
[`ai-council`](../skills/ai-council/SKILL.md), which polls models
|
|
73
|
+
outside the host session (Anthropic + OpenAI) and is therefore
|
|
74
|
+
genuinely independent of the implementer's framing.
|
|
75
|
+
- This is the escalation **instead of** a second top-band context, not
|
|
76
|
+
in addition to one. Two same-vendor top-band agents on one task cost
|
|
77
|
+
twice and correlate their blind spots; a second vendor costs less and
|
|
78
|
+
disagrees for real reasons.
|
|
79
|
+
- Cost boundary unchanged: the council is a network call and is
|
|
80
|
+
therefore never automatic. It is what the saturation case escalates
|
|
81
|
+
*to* when a second opinion is wanted, not a step every `high` task
|
|
82
|
+
takes ([`ai-council`](../skills/ai-council/SKILL.md) § Do NOT use).
|
|
83
|
+
|
|
84
|
+
**Honest scope.** This is policy prose in a context file — it binds the
|
|
85
|
+
agent that reads it and no gate re-derives a judge tier at dispatch
|
|
86
|
+
time. `enforced_by: none`, stated rather than implied.
|
|
27
87
|
|
|
28
88
|
**Downshift never touches the judge.** When cost-aware routing runs an
|
|
29
89
|
implementer on a downshifted tier (per the category → tier defaults in
|
|
30
90
|
[`model-recommendations § Subagent Category → Tier Defaults`](model-recommendations.md)),
|
|
31
|
-
the judge still resolves one tier above the IMPLEMENTER's resolved tier
|
|
32
|
-
|
|
91
|
+
the judge still resolves one tier above the IMPLEMENTER's resolved tier,
|
|
92
|
+
**with the escalation capped at `high` per the judge cap above** — so a
|
|
93
|
+
`lite` implementer gets at least a `medium` judge, and no *downshifted*
|
|
94
|
+
implementer escalates its judge into `frontier`. Downshifting an
|
|
33
95
|
implementer never downshifts its judge below what the verify contract
|
|
34
96
|
requires, and a judge is never `lite`.
|
|
35
97
|
|
|
@@ -67,7 +67,7 @@ ALLOWLIST > 20 ENTRIES IN ONE SESSION = THE LINTER IS WRONG.
|
|
|
67
67
|
STOP. PROPOSE LINTER REDESIGN OR REMOVAL. DO NOT EXPAND THE ALLOWLIST FURTHER.
|
|
68
68
|
```
|
|
69
69
|
|
|
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 the
|
|
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 pre-tool surface). 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).
|
|
71
71
|
|
|
72
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).
|
|
73
73
|
Trigger-set above activates this routing on demand, independent of the discipline profile (ADR-110).
|
|
@@ -32,6 +32,39 @@ A suggestion block emits options. It does **not** start a command flow.
|
|
|
32
32
|
The "run as-is" option is **always present**, **always last**, never
|
|
33
33
|
removed.
|
|
34
34
|
|
|
35
|
+
### The single HIGH-tier carve-out — a duplicate confirmation, never a skipped one
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
HIGH TIER REMOVES A SECOND CONFIRMATION. IT NEVER REMOVES THE FIRST.
|
|
39
|
+
A COMMAND THAT WOULD BEGIN ACTING ON ARRIVAL IS NEVER HIGH TIER.
|
|
40
|
+
TWO CANDIDATES ABOVE THE FLOOR IS MEDIUM. A SUBSTRING HIT IS MEDIUM.
|
|
41
|
+
NO DETERMINISTIC UNIQUE SIGNAL → THE BLOCK, ALWAYS.
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Added by road-to-user-out-of-the-loop Phase 1. It is narrow on purpose, and the
|
|
45
|
+
narrowness is the argument: the law above exists so the user is never carried
|
|
46
|
+
somewhere they did not choose, and a routed command whose **own** contract
|
|
47
|
+
screen is the next thing they see has not carried them anywhere — it has
|
|
48
|
+
replaced one options block with one basis line and left the real decision
|
|
49
|
+
exactly where it was.
|
|
50
|
+
|
|
51
|
+
All three conditions in
|
|
52
|
+
[`command-suggestion-flow § Tier matrix`](../contexts/contracts/command-suggestion-flow.md)
|
|
53
|
+
must hold: a deterministic unique signal, no second candidate above the floor,
|
|
54
|
+
and a routed command that shows its own confirmation. Condition 3 is the
|
|
55
|
+
load-bearing one — without it this clause would authorise auto-execution, which
|
|
56
|
+
is the thing the Iron Law forbids and this carve-out does not touch.
|
|
57
|
+
|
|
58
|
+
Everything else on this page is unchanged. MEDIUM and LOW still emit the block
|
|
59
|
+
with "run as-is" always present and always last; the subordination list below
|
|
60
|
+
still makes suggestion junior to every rule on it; and a Hard-Floor action stays
|
|
61
|
+
gated by [`non-destructive-by-default`](non-destructive-by-default.md) however
|
|
62
|
+
it was reached.
|
|
63
|
+
|
|
64
|
+
**Honest status:** the kill criterion (>5 % mis-routes over 50 auto-routes
|
|
65
|
+
reverts to block-always) has **no instrument yet**. The rate is unmeasured, not
|
|
66
|
+
low. A mis-route is a reportable defect until it can be counted.
|
|
67
|
+
|
|
35
68
|
## Subordination — when to stay silent
|
|
36
69
|
|
|
37
70
|
The suggestion rule is **junior** to:
|
|
@@ -171,7 +171,7 @@ introduced. The row that would have caught it is
|
|
|
171
171
|
and it exists only because a review asked for it after the trigger had already
|
|
172
172
|
shipped. Write that row first next time; it is the cheap half.
|
|
173
173
|
|
|
174
|
-
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.
|
|
174
|
+
Body migrated to [`guideline:design-fidelity-mechanics`](../docs/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.
|
|
175
175
|
Trigger-set above activates this routing on demand, independent of the discipline profile (ADR-110).
|
|
176
176
|
|
|
177
177
|
## See also
|
|
@@ -14,8 +14,13 @@ triggers:
|
|
|
14
14
|
- file_pattern: "*.tsx"
|
|
15
15
|
- file_pattern: "*.jsx"
|
|
16
16
|
- file_pattern: "*.blade.php"
|
|
17
|
-
|
|
18
|
-
-
|
|
17
|
+
# `keyword: "component"` and `keyword: "design token"` removed 2026-08-17 as an
|
|
18
|
+
# AUTHORING decision — road-to-mixed-trigger-activation-cost Phase 2, amendment
|
|
19
|
+
# option (b), narrowed to the two path-dominant per-edit rules. This is the
|
|
20
|
+
# escape the mixed-triggers guard's own comment names: with no non-path trigger
|
|
21
|
+
# left the emitter restores `paths:`, so the rule loads on UI file contact
|
|
22
|
+
# instead of in every session. The obligation is unchanged — it binds when a UI
|
|
23
|
+
# file is touched, which is the only place a UI edit can happen.
|
|
19
24
|
routes_to:
|
|
20
25
|
- "skill:design-review"
|
|
21
26
|
- "skill:accessibility-auditor"
|
|
@@ -24,8 +29,12 @@ packs: [frontend-design]
|
|
|
24
29
|
enforced_by:
|
|
25
30
|
- "none"
|
|
26
31
|
collision_ok:
|
|
27
|
-
"component"
|
|
28
|
-
|
|
32
|
+
# The "component" and "design token" entries were removed with their triggers
|
|
33
|
+
# (2026-08-17): a collision note for a trigger that no longer exists is an
|
|
34
|
+
# own-orphan, and `minimal-safe-diff` § Own-orphan cleanup requires the diff that
|
|
35
|
+
# stopped referencing them to remove them too. The path-keyed notes below are
|
|
36
|
+
# unchanged, and they still carry the real point: both halves of the UI loop fire
|
|
37
|
+
# on the same paths.
|
|
29
38
|
"resources/views/": "both halves of one UI loop fire on the same path — audit before, review after; neither substitutes for the other"
|
|
30
39
|
"resources/js/": "both halves of one UI loop fire on the same path — audit before, review after; neither substitutes for the other"
|
|
31
40
|
"components/": "both halves of one UI loop fire on the same path — audit before, review after; neither substitutes for the other"
|
|
@@ -109,16 +118,29 @@ design consultation latched this session.
|
|
|
109
118
|
|
|
110
119
|
It runs **parallel** to this rule rather than consuming it. Nothing in the tree
|
|
111
120
|
reads this frontmatter at session time; the concern decides what counts as a UI
|
|
112
|
-
surface from `src/scripts/_lib/ui_surface.ts
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
121
|
+
surface from `src/scripts/_lib/ui_surface.ts`. A test — not a code path — keeps
|
|
122
|
+
the two from drifting: `ui_rule_triggers.test.ts` asserts every `file_pattern`
|
|
123
|
+
declared here is accepted by that predicate.
|
|
124
|
+
|
|
125
|
+
**This rule carries no `keyword:` trigger any more (2026-08-17).** It used to,
|
|
126
|
+
and the observation those keywords had no runtime consumer is what made removing
|
|
127
|
+
them cheap: no host activation surface reads a keyword — Cursor and Windsurf
|
|
128
|
+
activate on `globs` plus the description, Claude on `paths:`. What the keywords
|
|
129
|
+
did do was expensive, and only on Claude: one non-path trigger makes the emitter
|
|
130
|
+
write **no** `paths:` at all, which is why this rule's pre-inventory-and-review
|
|
131
|
+
obligation stood in every session from 12.1.0 until the removal. It is
|
|
132
|
+
path-scoped again — see `road-to-mixed-trigger-activation-cost` Phase 2.
|
|
133
|
+
|
|
134
|
+
Warn-only, capped at two nudges per session, default-OFF, and bound only in the
|
|
135
|
+
three `platforms:` rows that carry a `pre_tool_use` key — augment, claude,
|
|
136
|
+
cowork (**clarified 2026-08-17**: "hosts carrying a slot" read as a host
|
|
137
|
+
property and is a manifest one; three further hosts alias a native pre-tool
|
|
138
|
+
event with no binding, and only claude honours a deny — see
|
|
139
|
+
[`hook-architecture-v1 § Which hosts carry pre_tool_use`](../docs/contracts/hook-architecture-v1.md)).
|
|
140
|
+
The verdict is unchanged either way: a nudge that can be ignored is not
|
|
141
|
+
enforcement, so `enforced_by:` stays `none` — it moves the day a mechanism can
|
|
142
|
+
refuse, not the day a reminder appears. `agent-config hooks:status` answers
|
|
143
|
+
whether the concern is bound on the host you are actually on.
|
|
122
144
|
|
|
123
145
|
What that leaves, and it is the useful part: the write side now has a named
|
|
124
146
|
obligation and a route to the skill that discharges it, where before it had
|
|
@@ -95,13 +95,35 @@ Three limits, stated because they were measured. The pre-loaded-verdict list is
|
|
|
95
95
|
a **phrase list**, so a paraphrase evades it — it catches recurrences of known
|
|
96
96
|
steering wording, not steering as such. The turn boundary is the
|
|
97
97
|
authorization ledger's `detected_at` stamp, because the envelope carries no turn
|
|
98
|
-
id; with no ledger yet, the counter falls back to session scope. And the
|
|
99
|
-
|
|
100
|
-
claude, cowork
|
|
101
|
-
|
|
102
|
-
frequency join in `check_enforcement_coverage.ts` reports exactly that set, and
|
|
98
|
+
id; with no ledger yet, the counter falls back to session scope. And the guard
|
|
99
|
+
does not deny everywhere it exists: `pre_tool_use` is **bound** on three hosts —
|
|
100
|
+
augment, claude, cowork — and only `claude` honours the deny. Everywhere else,
|
|
101
|
+
augment and cowork included, items 1 and 4 join 2 and 3 as model-carried.
|
|
103
102
|
`agent-config hooks:status` answers it for the host you are on right now.
|
|
104
103
|
|
|
104
|
+
**Corrected 2026-08-17 — this paragraph was wrong on both sides of the line it
|
|
105
|
+
drew.** It said `pre_tool_use` "exists on three hosts" and that the guard has
|
|
106
|
+
"nowhere to bind" on the other five. Neither half survived a re-read of the
|
|
107
|
+
tree. **Downward:** the manifest's own `native_event_aliases` table already maps
|
|
108
|
+
`preToolUse` (cursor), `PreToolUse` (cline) and `BeforeTool` (gemini) onto
|
|
109
|
+
`pre_tool_use`, so there the guard is **unbound, not unbindable**; only windsurf
|
|
110
|
+
and copilot carry no pre-tool surface at all. **Upward, and worse:**
|
|
111
|
+
`host_semantics.ts` certifies **claude alone**, and the augment and cowork
|
|
112
|
+
trampolines discard dispatcher output and `exit 0` unconditionally — so on two
|
|
113
|
+
of the three "enforcing" hosts this guard runs and is then ignored. Nor may the
|
|
114
|
+
inverse be asserted downward: nothing records whether an unbound host's
|
|
115
|
+
pre-tool event can *deny*, and `severity: blocking` is a property of the concern
|
|
116
|
+
rather than of the host. The four states are tabulated once in
|
|
117
|
+
[`hook-architecture-v1 § Which hosts carry pre_tool_use`](../docs/contracts/hook-architecture-v1.md).
|
|
118
|
+
|
|
119
|
+
Stated at this length because this rule exists over a case where a process that
|
|
120
|
+
*looked* followed produced fabricated evidence. An unbacked reason for a real
|
|
121
|
+
gap and an unmeasured claim of enforcement are the same failure in a smaller
|
|
122
|
+
font, and this paragraph had shipped one of each. Note also what the frequency
|
|
123
|
+
join actually reports: `check_enforcement_coverage.ts` skips `fallback_only`
|
|
124
|
+
platforms, so its gap set is **four** — cursor, cline, windsurf, gemini — never
|
|
125
|
+
copilot, which is excluded by declaration rather than measured as a gap.
|
|
126
|
+
|
|
105
127
|
Items 2 and 3 — an honestly chosen scope, and recording the prompt with the
|
|
106
128
|
verdict — are **not** enforced by anything. A narrowed scope is not decidable
|
|
107
129
|
from the prompt alone, and no validator reads the artefacts a verdict lands in.
|
|
@@ -84,4 +84,8 @@ Trigger-set above activates this routing on demand, independent of the disciplin
|
|
|
84
84
|
- [`commit-policy`](commit-policy.md) — commits are the user's call; rewriting them is a stronger version of the same restriction.
|
|
85
85
|
- [`token-efficiency`](token-efficiency.md) — Iron Law on burning the user's tokens for cosmetic gain.
|
|
86
86
|
- [`skill:git-workflow`](../skills/git-workflow/SKILL.md) — Safe Squash-After-Push protocol and Divergent-State Recovery decision tree.
|
|
87
|
-
- `git … --no-verify` / `core.hooksPath` overrides — deterministically blocked by the `block-no-verify` PreToolUse guard (`src/scripts/hooks/block_no_verify.ts`, registered in `hook_manifest.yaml`) **on the
|
|
87
|
+
- `git … --no-verify` / `core.hooksPath` overrides — deterministically blocked by the `block-no-verify` PreToolUse guard (`src/scripts/hooks/block_no_verify.ts`, registered in `hook_manifest.yaml`) **on `claude`, the one host that both binds `pre_tool_use` and honours a deny**. It is *bound* on augment and cowork too, and ignored there. Everywhere else the Iron Laws above are model-carried and "deterministically blocked" is not a claim this rule can make. To check the host you are on rather than trusting this sentence, run `agent-config hooks:status`.
|
|
88
|
+
|
|
89
|
+
**Corrected 2026-08-17, in both directions, because this line was wrong on each side.** It read "the guard has nowhere to bind" on cursor, cline, windsurf, gemini and copilot — refuted for three of the five by the manifest's own `native_event_aliases` table, which already maps `preToolUse`, `PreToolUse` and `BeforeTool` onto `pre_tool_use`: there the guard is **unbound, not unbindable**, and only windsurf and copilot carry no pre-tool surface. And it certified augment, claude and cowork as the enforcing set — `host_semantics.ts` verifies **claude alone**, while the augment and cowork trampolines discard dispatcher output and `exit 0` unconditionally, so a guard bound there runs and is then ignored. Both halves are the same failure: a host-capability claim this tree never established. The four states are tabulated once in [`hook-architecture-v1 § Which hosts carry pre_tool_use`](../docs/contracts/hook-architecture-v1.md).
|
|
90
|
+
|
|
91
|
+
The frequency join in `check_enforcement_coverage.ts` reports this obligation uncovered on **four** platforms — cursor, cline, windsurf, gemini. It skips `fallback_only` platforms before computing, so copilot never appears in its output and must not be quoted as if it did; copilot is uncovered for the separate reason that it has no hook surface at all.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: "auto"
|
|
3
|
+
tier: "2a"
|
|
4
|
+
description: "A skill exists in the tree but not in the host's catalogue — ask for it by TASK via suggest_skill_for_task, never conclude it does not exist"
|
|
5
|
+
triggers:
|
|
6
|
+
- phrase: "skill not found"
|
|
7
|
+
- phrase: "no such skill"
|
|
8
|
+
- phrase: "skill does not exist"
|
|
9
|
+
- phrase: "kein passendes skill"
|
|
10
|
+
- phrase: "which skill"
|
|
11
|
+
- phrase: "welches skill"
|
|
12
|
+
applies_to_user_types:
|
|
13
|
+
- "developer"
|
|
14
|
+
- "maintainer"
|
|
15
|
+
self_contained: true
|
|
16
|
+
workspaces: [engineering]
|
|
17
|
+
packs: [meta]
|
|
18
|
+
# obligation: line 41
|
|
19
|
+
obligation_frequency: "per-turn"
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
# Missing-Skill Recovery
|
|
23
|
+
|
|
24
|
+
The catalogue a host shows you is not the catalogue that exists. Hosts truncate,
|
|
25
|
+
and at least one truncates hard: measured 2026-08-16 on a default install, the
|
|
26
|
+
host published its own budget event stating it had stripped every description
|
|
27
|
+
and dropped **402 entries** from the model-visible skills list
|
|
28
|
+
(`agents/evidence/analysis/scoped-projection-host-delivery.md`). Scoping the
|
|
29
|
+
projection moved that to 330 and stripped the descriptions anyway.
|
|
30
|
+
|
|
31
|
+
402 is the **host's own count against the host's own denominator**, which is not
|
|
32
|
+
this package's: the same install projects 297 skills, so the figure is a
|
|
33
|
+
magnitude, never a subtraction anyone can perform. What it establishes is that
|
|
34
|
+
most of the catalogue is not model-visible — which is all this rule needs.
|
|
35
|
+
|
|
36
|
+
So "I do not see a skill for this" is evidence about the **delivery**, never
|
|
37
|
+
about the tree.
|
|
38
|
+
|
|
39
|
+
## The Iron Law
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
A SKILL MISSING FROM THE HOST CATALOGUE IS NOT A SKILL THAT DOES NOT EXIST.
|
|
43
|
+
NEVER CONCLUDE "NO SKILL COVERS THIS" FROM THE LIST YOU WERE SHOWN.
|
|
44
|
+
ASK BY TASK — `suggest_skill_for_task` RANKS THE TREE, NOT THE CATALOGUE.
|
|
45
|
+
NEVER REBUILD A CAPABILITY BECAUSE ITS SKILL WAS NOT DELIVERED.
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## What to do
|
|
49
|
+
|
|
50
|
+
1. **Ask by task, not by name.** A name you cannot see is a name you cannot
|
|
51
|
+
type; a task description always works. The `suggest_skill_for_task` MCP tool
|
|
52
|
+
ranks `SKILL.md` frontmatter over the source tree and returns names, scores
|
|
53
|
+
and personas — no bodies, so a wrong rank costs one read.
|
|
54
|
+
2. **Open the winner and check it yourself.** The ranker is deterministic
|
|
55
|
+
keyword scoring, not judgement. A high score is a pointer, not a verdict.
|
|
56
|
+
3. **Say which source answered.** "The catalogue had no entry, the ranker
|
|
57
|
+
found `X`" is a different claim from "there is no skill for this", and a
|
|
58
|
+
reader cannot reconstruct which one you meant from silence.
|
|
59
|
+
4. **If nothing scores, say that** — and proceed without a skill rather than
|
|
60
|
+
inventing one. A ranked empty list and an unreachable catalogue are
|
|
61
|
+
different answers; the tool distinguishes them (`status: no_catalogue`) and
|
|
62
|
+
so should you.
|
|
63
|
+
|
|
64
|
+
## When NOT to fire
|
|
65
|
+
|
|
66
|
+
- The skill you need was delivered and is in front of you. This rule is for the
|
|
67
|
+
gap, not for routine skill selection.
|
|
68
|
+
- The task genuinely has no skill and you already checked by task. Checking
|
|
69
|
+
twice is the loop, not the discipline.
|
|
70
|
+
- A host that delivers its catalogue whole — the rule costs nothing there and
|
|
71
|
+
simply never has a gap to close.
|
|
72
|
+
|
|
73
|
+
## Honest enforcement — `enforced_by: none`
|
|
74
|
+
|
|
75
|
+
Nothing can observe an agent concluding "no skill exists". The `skill-route`
|
|
76
|
+
concern injects ranked pointers on `user_prompt_submit` when its floor is
|
|
77
|
+
cleared, which covers the prompts where the ranker is confident and by
|
|
78
|
+
construction covers no others: it is silent on ~86 % of prompts by design. This
|
|
79
|
+
rule is the model-carried half for the rest, and it is stated as such rather
|
|
80
|
+
than implied to be caught by the concern.
|
|
81
|
+
|
|
82
|
+
## See also
|
|
83
|
+
|
|
84
|
+
- [`code-intelligence`](../skills/code-intelligence/SKILL.md) — the same
|
|
85
|
+
shape for source code: query the index first, fall back, name the source.
|
|
86
|
+
- [`external-code-graph-interop`](external-code-graph-interop.md) — its rule-side
|
|
87
|
+
twin, and the model this rule's trigger set follows.
|
|
88
|
+
- `src/scripts/skill_tools/score_skill_relevance.ts` — the ranker itself, and
|
|
89
|
+
the one place its scoring is defined.
|