@open-agent-toolkit/cli 0.3.1 → 0.3.2

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 (74) hide show
  1. package/assets/agents/oat-reviewer.md +7 -2
  2. package/assets/bundle-metadata.json +1 -1
  3. package/assets/config/dispatch-matrix-recommendation.json +63 -43
  4. package/assets/docs/cli-utilities/configuration.md +20 -8
  5. package/assets/docs/cli-utilities/workflow-gates.md +1 -1
  6. package/assets/docs/contributing/index.md +1 -0
  7. package/assets/docs/contributing/updating-model-guidance.md +106 -0
  8. package/assets/docs/contributing/verifying-cursor-pins.md +30 -18
  9. package/assets/docs/provider-sync/providers.md +5 -2
  10. package/assets/docs/reference/cli-reference.md +1 -1
  11. package/assets/docs/reference/oat-directory-structure.md +1 -1
  12. package/assets/docs/workflows/projects/artifacts.md +1 -1
  13. package/assets/docs/workflows/projects/dispatch-ceiling.md +67 -50
  14. package/assets/docs/workflows/projects/evidence-layers.md +6 -2
  15. package/assets/docs/workflows/projects/implementation-execution.md +9 -4
  16. package/assets/docs/workflows/projects/lifecycle.md +8 -6
  17. package/assets/docs/workflows/projects/programmatic-execution.md +4 -3
  18. package/assets/public-package-versions.json +4 -4
  19. package/assets/skills/oat-dispatch-subagents/SKILL.md +1 -1
  20. package/assets/skills/oat-dispatch-subagents/references/provider-claude.md +20 -7
  21. package/assets/skills/oat-project-autonomous/references/gate-inventory.md +4 -4
  22. package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +4 -4
  23. package/assets/skills/oat-project-implement/SKILL.md +1 -1
  24. package/assets/skills/oat-project-implement/references/completion-and-closeout.md +2 -0
  25. package/assets/skills/oat-project-implement/references/dispatch-and-dry-run.md +82 -25
  26. package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +4 -4
  27. package/assets/skills/oat-project-implement/references/phase-execution.md +16 -8
  28. package/assets/skills/oat-project-import-plan/SKILL.md +7 -4
  29. package/assets/skills/oat-project-lite/SKILL.md +5 -3
  30. package/assets/skills/oat-project-lite/references/docs/autonomy-contract.md +4 -4
  31. package/assets/skills/oat-project-plan/SKILL.md +7 -4
  32. package/assets/skills/oat-project-plan-writing/SKILL.md +28 -16
  33. package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +4 -4
  34. package/assets/skills/oat-project-quick-start/SKILL.md +7 -4
  35. package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +4 -4
  36. package/assets/skills/oat-project-review-provide/SKILL.md +7 -4
  37. package/assets/skills/subagent-orchestration/SKILL.md +1 -1
  38. package/assets/skills/subagent-orchestration/references/evidence-and-refresh.md +30 -29
  39. package/assets/skills/subagent-orchestration/references/provider-claude.md +41 -36
  40. package/assets/skills/subagent-orchestration/references/provider-codex.md +30 -35
  41. package/assets/skills/subagent-orchestration/references/provider-cursor.md +46 -38
  42. package/assets/templates/plan.md +5 -5
  43. package/dist/commands/project/dispatch/record.d.ts.map +1 -1
  44. package/dist/commands/project/dispatch/record.js +27 -5
  45. package/dist/commands/project/dispatch-ceiling/index.d.ts.map +1 -1
  46. package/dist/commands/project/dispatch-ceiling/index.js +112 -35
  47. package/dist/config/dispatch-matrix.d.ts.map +1 -1
  48. package/dist/config/dispatch-matrix.js +13 -0
  49. package/dist/providers/ceiling/registry.d.ts +7 -2
  50. package/dist/providers/ceiling/registry.d.ts.map +1 -1
  51. package/dist/providers/ceiling/registry.js +35 -11
  52. package/dist/providers/claude/codec/materialize.d.ts +33 -0
  53. package/dist/providers/claude/codec/materialize.d.ts.map +1 -0
  54. package/dist/providers/claude/codec/materialize.js +149 -0
  55. package/dist/providers/claude/codec/sync-extension.d.ts +24 -0
  56. package/dist/providers/claude/codec/sync-extension.d.ts.map +1 -0
  57. package/dist/providers/claude/codec/sync-extension.js +312 -0
  58. package/dist/providers/claude/dispatch-envelope.d.ts +34 -0
  59. package/dist/providers/claude/dispatch-envelope.d.ts.map +1 -0
  60. package/dist/providers/claude/dispatch-envelope.js +233 -0
  61. package/dist/providers/claude/targets.d.ts +48 -0
  62. package/dist/providers/claude/targets.d.ts.map +1 -0
  63. package/dist/providers/claude/targets.js +228 -0
  64. package/dist/providers/codex/codec/shared.d.ts +6 -0
  65. package/dist/providers/codex/codec/shared.d.ts.map +1 -1
  66. package/dist/providers/codex/codec/shared.js +8 -0
  67. package/dist/providers/cursor/codec/catalog.d.ts.map +1 -1
  68. package/dist/providers/cursor/codec/catalog.js +47 -45
  69. package/dist/providers/identity/claude-runtime-observation.fixtures.d.ts +35 -0
  70. package/dist/providers/identity/claude-runtime-observation.fixtures.d.ts.map +1 -1
  71. package/dist/providers/identity/claude-runtime-observation.fixtures.js +225 -12
  72. package/dist/providers/shared/registry.d.ts.map +1 -1
  73. package/dist/providers/shared/registry.js +5 -2
  74. package/package.json +2 -2
@@ -1,11 +1,10 @@
1
1
  ---
2
- guidance_version: 2026-07-25
3
- last_verified: 2026-07-25
4
- review_after: 2026-09-04
2
+ guidance_version: 2026-09-23
3
+ last_verified: 2026-09-23
4
+ review_after: 2026-12-22
5
5
  catalog_basis:
6
- live `cursor-agent models` catalog and CursorBench 3.2, with Opus 5
7
- and Opus 4.8 pin selectors probe-verified against Cursor 3.12.30 via
8
- subagentStart lifecycle hooks
6
+ Cursor desktop 3.20.14 resolved all five Opus 5.5 effort selectors in native
7
+ subagent hooks; GPT-6 Sol/Luna were absent from the observed Cursor catalog
9
8
  ---
10
9
 
11
10
  # Cursor Model Selection
@@ -45,25 +44,40 @@ does not by itself prove lower user-observed elapsed time.
45
44
 
46
45
  ## Dated Task-Class Matrix
47
46
 
48
- Use exact aliases from the live catalog. The examples below come from two
49
- observations, not one. Most were present in a 2026-07-21 catalog snapshot. The
50
- `claude-opus-5` and `claude-opus-4-8` routes postdate it — Opus 5 released
51
- 2026-07-24 — and were confirmed against the live catalog and probe-verified on
52
- 2026-07-25, as recorded under Verified Opus 5 Cursor Routes below. The
53
- remainder of the catalog has not been re-snapshotted since 2026-07-21, so treat
54
- non-Opus entries as the older and weaker observation.
55
-
56
- | Task class | Default | Economy | Escalation | Floor notes |
57
- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
58
- | `mechanical-recon` | `composer-2.5` | `composer-2.5` | `gpt-5.6-luna-high` | Use `composer-2.5-fast` or Luna fast only for latency, not capability. |
59
- | `intelligent-recon` | `cursor-grok-4.5-medium` or `gpt-5.6-sol-medium` | `gpt-5.6-terra-high` | `gpt-5.6-sol-high` | Grok medium is a primary route; Sol medium is the conservative silent-miss alternative; Terra high is the cost-saving route. |
60
- | `default-implementation` | `gpt-5.6-sol-medium` | `composer-2.5` for bounded, testable changes | `claude-opus-5-thinking-medium` | Sol is the code-first incumbent; Opus 5 medium is the substantive route for interpretation-heavy work; `cursor-grok-4.5-medium` remains a primary alternative. |
61
- | `hard-reasoning` | `claude-opus-5-thinking-high` | `cursor-grok-4.5-high` for architecture, ambiguous debugging, and incident diagnosis | `claude-opus-5-thinking-xhigh`, then `gpt-5.6-sol-xhigh` for code-first work | Opus 5 high is the starting point. Escalate to xhigh only for a reasoning-depth bottleneck. Do not infer cross-provider effort equivalence. |
62
- | `consequential` | The task's own reasoning-depth route, plus independent cross-family review: typically `gpt-5.6-sol-high` authoring with `claude-opus-5-thinking-high` review | No routine economy route | Raise the pair to xhigh for a reasoning-depth bottleneck; Sol max plus Opus 5 max only after a workload-specific sweep | Consequence adds independent cross-family review and root authorization, not automatic top effort. Select effort from reasoning depth exactly as the non-consequential row would, then add independence on top. For cyber-sensitive review, do not rely on Fable or Grok alone. |
63
-
64
- ## Verified Opus 5 Cursor Routes
65
-
66
- Opus 5 is a qualified Cursor route. Five effort rungs plus an Opus 4.8 rung were
47
+ Use currently approved exact aliases from the Cursor catalogue. On 2026-09-23,
48
+ Cursor desktop 3.20.14 resolved all five `claude-opus-5-5[effort=...]`
49
+ selectors to corresponding flat IDs in native hooks. See the
50
+ probe record at `packages/cli/src/providers/cursor/codec/__fixtures__/README.md`.
51
+ GPT-6 Sol/Luna were absent from the observed Cursor catalogue, so their Codex
52
+ availability does not authorize Cursor routes.
53
+
54
+ | Task class | Default | Economy | Escalation | Floor notes |
55
+ | ------------------------ | ------------------------------------------------------------------- | -------------------------------------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
56
+ | `mechanical-recon` | `composer-2.5` | Same with mechanical verification | `gpt-5.6-luna-high` | Fast aliases select service tier, not capability. |
57
+ | `intelligent-recon` | `cursor-grok-4.5-medium` or `gpt-5.6-sol-medium` | `gpt-5.6-terra-high` | `gpt-5.6-sol-high` | Verify silent-miss-prone conclusions. |
58
+ | `default-implementation` | `gpt-5.6-sol-medium` | `composer-2.5` for bounded, testable changes | `gpt-5.6-sol-high` | `cursor-grok-4.5-medium` remains an available judgment-heavy alternative. |
59
+ | `hard-reasoning` | `gpt-5.6-sol-high` | `cursor-grok-4.5-high` with corroborating evidence | `gpt-5.6-sol-xhigh` | Opus 5.5 high/xhigh are verified cross-family alternatives; qualify task performance separately. |
60
+ | `consequential` | An eligible high-effort author with independent cross-family review | No routine economy route | Sol xhigh for a depth bottleneck; max only after evaluation | If independent review cannot be met among approved Cursor mappings, use a separately qualified provider or stop. |
61
+
62
+ ## Current Opus 5.5 Pin Evidence
63
+
64
+ Cursor desktop 3.20.14 resolved `claude-opus-5-5[effort=low|medium|high|xhigh|max]`
65
+ to `claude-opus-5-5-low|medium|high|xhigh|max`, respectively, on 2026-09-23.
66
+ Both the `subagentStart.subagent_model` and the subagent Shell `preToolUse.model`
67
+ agreed for every rung. The Sonnet 5 high positive control resolved to
68
+ `claude-sonnet-5-thinking-high`. An unknown family fell back to
69
+ `cursor-grok-4.6-high-fast`; an unknown effort on Opus 5.5 fell back to
70
+ `claude-opus-5-5-medium`. The provenance summary at `packages/cli/src/providers/cursor/codec/__fixtures__/README.md`
71
+ links the adjacent redacted summary and native-event JSONL records containing
72
+ the exact observations. Recheck live availability before launch.
73
+
74
+ ## Historical Opus Cursor Probe Evidence (Retired)
75
+
76
+ The following observations document Cursor 3.12.30 behavior on 2026-07-25.
77
+ They no longer qualify those generations for current recommendations or the
78
+ active approved mapping catalogue. A new family needs its own live probe.
79
+
80
+ Five Opus 5 effort rungs plus an Opus 4.8 rung were
67
81
  probe-verified on 2026-07-25 against Cursor 3.12.30, using `subagentStart`
68
82
  lifecycle hooks to read the resolved model that Cursor itself reports:
69
83
 
@@ -80,21 +94,15 @@ Every rung resolves to the thinking variant. This is a verified fact, not an
80
94
  inference: the catalog carries distinct non-thinking IDs at low, medium, and
81
95
  high, and none were selected.
82
96
 
83
- Routing follows the accepted conclusions rather than the effort ladder alone.
84
- Opus 5 medium is the normal substantive route, high is the hard-reasoning
85
- starting point, xhigh is selective for a reasoning-depth bottleneck or an
86
- evaluated long-horizon benefit, and max requires a workload-specific sweep or an
87
- explicit exception. Sol remains the code-first, trajectory-efficient engineering
88
- route; Opus is generally stronger for interpretation-heavy work. Exact
89
- cross-provider substitutions remain provisional.
90
-
91
- Opus 4.8 xhigh is catalogued so the cyber-sensitive route is dispatchable, but it
92
- is deliberately excluded from the bundled recommendation. Select it explicitly
93
- when the cyber-sensitive refusal profile is required.
97
+ That historical result did not validate an Opus 5.5 selector; the 2026-09-23
98
+ probe above independently qualifies its five selectors. Even where the
99
+ requested effort has the same spelling across generations, preserve the old
100
+ probe only as evidence of past behavior and use the current approved catalogue
101
+ for dispatch.
94
102
 
95
103
  ### Unresolvable selectors fall back to a default, silently
96
104
 
97
- Probing showed that Cursor does not reject a malformed pin. It substitutes a
105
+ The historical probe showed that Cursor did not reject a malformed pin. It substitutes a
98
106
  default for whichever component it cannot resolve, with no error or warning:
99
107
 
100
108
  - An unknown family falls back to the default model. `claude-opus-9[effort=high]`
@@ -102,7 +110,7 @@ default for whichever component it cannot resolve, with no error or warning:
102
110
  - An unknown effort falls back to the family's default rung.
103
111
  `claude-opus-5[effort=ultra]` resolved to `claude-opus-5-thinking-high`.
104
112
 
105
- The default rung is family-specific, not a fixed value. In the live catalog
113
+ The default rung is family-specific, not a fixed value. In that catalog snapshot
106
114
  exactly one rung per family carries an unqualified display label, and that marks
107
115
  the default: `claude-opus-5-high` shows as `Opus 5 1M` while
108
116
  `claude-opus-5-medium` shows as `Opus 5 1M Medium`. The default is not always
@@ -55,13 +55,13 @@ Default is `[]` (fully sequential, no worktrees). Only declare parallelism when
55
55
 
56
56
  _Optional override surface. Use only for explicit user-authored constraints or preferences. Omit this section when runtime selection should choose the lowest confident tier._
57
57
 
58
- Blank or `auto` means there is no explicit constraint for that provider. Do not generate rows by default; a missing phase row uses runtime selection.
58
+ Blank or `auto` means there is no explicit phase constraint. Do not generate rows by default; a missing phase row uses runtime selection.
59
59
 
60
- | Phase | Claude model | Codex effort | Rationale |
61
- | ----- | -------------------------------- | ------------------------------ | ----------------------------- |
62
- | pNN | haiku\|sonnet\|opus\|fable\|auto | low\|medium\|high\|xhigh\|auto | why this constraint is needed |
60
+ | Phase | Named ceiling | Rationale |
61
+ | ----- | --------------------------------------- | ----------------------------- |
62
+ | pNN | economy\|balanced\|high\|frontier\|auto | why this constraint is needed |
63
63
 
64
- Codex effort values are preferred controls. `oat-project-implement` caps them when a capped managed dispatch policy exists, selects them directly under managed `Uncapped`, and maps selected efforts to pinned implementer variants when available. Codex provider default effort is informational only for explicit inherit/default behavior or base/unpinned fallback paths.
64
+ The named ceiling is a maximum candidate tier, not an exact provider, model family, or effort preference. `oat-project-implement` chooses one exact phase-implementer target from the complete configured ladder at runtime.
65
65
 
66
66
  ---
67
67
 
@@ -1 +1 @@
1
- {"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/dispatch/record.ts"],"names":[],"mappings":"AAcA,OAAO,EAKL,KAAK,qBAAqB,EAC3B,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAOL,KAAK,wBAAwB,EAE7B,KAAK,4BAA4B,EAElC,MAAM,yCAAyC,CAAC;AAWjD;;;;;GAKG;AACH,MAAM,WAAW,0BAA0B;IACzC,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC;AAoCD;;;;;;;;;GASG;AAEH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,KAAK,GAAE;IACL,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjB,GACL,MAAM,CAcR;AAaD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,qBAAqB,CAAC;IAC9B,KAAK,EAAE,wBAAwB,CAAC;IAChC,uEAAuE;IACvE,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED;;;;;GAKG;AACH,MAAM,WAAW,6BAA6B;IAC5C,UAAU,EAAE;QACV,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;KAC5B,CAAC;IACF,QAAQ,EAAE;QACR,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;KAC5B,GAAG,IAAI,CAAC;IACT,KAAK,EAAE,UAAU,GAAG,aAAa,GAAG,gBAAgB,GAAG,IAAI,CAAC;IAC5D;;;OAGG;IACH,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC;;;;OAIG;IACH,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,UAAU,GAAG,cAAc,CAAC;CACrC;AAED,MAAM,MAAM,2BAA2B,GAAG;IACxC,MAAM,EAAE,WAAW,GAAG,gBAAgB,CAAC;IACvC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,4BAA4B,CAAC;IACrC,eAAe,EAAE,6BAA6B,CAAC;CAChD,CAAC;AAsEF,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,CAgF5E;AAgKD;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CAAC,KAAK,EAAE;IACjD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,0BAA0B,CAAC;CAC3C,GAAG,OAAO,CAAC,2BAA2B,CAAC,CA6HvC"}
1
+ {"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/dispatch/record.ts"],"names":[],"mappings":"AAkBA,OAAO,EAKL,KAAK,qBAAqB,EAC3B,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAOL,KAAK,wBAAwB,EAE7B,KAAK,4BAA4B,EAElC,MAAM,yCAAyC,CAAC;AAWjD;;;;;GAKG;AACH,MAAM,WAAW,0BAA0B;IACzC,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC;AAoCD;;;;;;;;;GASG;AAEH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,KAAK,GAAE;IACL,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjB,GACL,MAAM,CAcR;AAaD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,qBAAqB,CAAC;IAC9B,KAAK,EAAE,wBAAwB,CAAC;IAChC,uEAAuE;IACvE,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED;;;;;GAKG;AACH,MAAM,WAAW,6BAA6B;IAC5C,UAAU,EAAE;QACV,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;KAC5B,CAAC;IACF,QAAQ,EAAE;QACR,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;KAC5B,GAAG,IAAI,CAAC;IACT,KAAK,EAAE,UAAU,GAAG,aAAa,GAAG,gBAAgB,GAAG,IAAI,CAAC;IAC5D;;;OAGG;IACH,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC;;;;OAIG;IACH,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,UAAU,GAAG,cAAc,CAAC;CACrC;AAED,MAAM,MAAM,2BAA2B,GAAG;IACxC,MAAM,EAAE,WAAW,GAAG,gBAAgB,CAAC;IACvC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,4BAA4B,CAAC;IACrC,eAAe,EAAE,6BAA6B,CAAC;CAChD,CAAC;AAsEF,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,CA0G5E;AAgKD;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CAAC,KAAK,EAAE;IACjD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,0BAA0B,CAAC;CAC3C,GAAG,OAAO,CAAC,2BAA2B,CAAC,CA6HvC"}
@@ -1,6 +1,7 @@
1
1
  import { readFile, readdir } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
3
  import { publishContainedJsonRevision, redactedFsError, withContainedWriterLock, } from '../../../fs/io.js';
4
+ import { acceptClaudeLaunchEnvelope, buildClaudeDispatchRecord, } from '../../../providers/claude/dispatch-envelope.js';
4
5
  import { assertJournalIdentityHasNoAbsolutePath, redactAbsolutePaths, } from '../../../providers/identity/absolute-paths.js';
5
6
  import { CLAUDE_OBSERVATION_SOURCE } from '../../../providers/identity/claude-runtime-observation.js';
6
7
  import { CODEX_OBSERVATION_SOURCE } from '../../../providers/identity/codex-runtime-observation.js';
@@ -127,12 +128,34 @@ export function parseDispatchRecordInput(value) {
127
128
  throw new Error('Dispatch record input must be a JSON object.');
128
129
  }
129
130
  const keys = Object.keys(value).sort();
130
- if (keys.length !== 2 || keys[0] !== 'event' || keys[1] !== 'record') {
131
- throw new Error('Dispatch record input accepts only record and event.');
131
+ const isGenericInput = keys.length === 2 && keys[0] === 'event' && keys[1] === 'record';
132
+ const isManagedClaudeInput = keys.length === 3 &&
133
+ keys[0] === 'claudeLaunch' &&
134
+ keys[1] === 'event' &&
135
+ keys[2] === 'recordBase';
136
+ if (!isGenericInput && !isManagedClaudeInput) {
137
+ throw new Error('Dispatch record input accepts record and event, or claudeLaunch, event, and recordBase.');
132
138
  }
133
139
  if (!isRecord(value.event)) {
134
140
  throw new Error('Dispatch record event must be a JSON object.');
135
141
  }
142
+ const record = isManagedClaudeInput
143
+ ? buildClaudeDispatchRecord({
144
+ envelope: acceptClaudeLaunchEnvelope({
145
+ resolution: isRecord(value.claudeLaunch)
146
+ ? value.claudeLaunch.resolution
147
+ : undefined,
148
+ definition: isRecord(value.claudeLaunch)
149
+ ? String(value.claudeLaunch.definition ?? '')
150
+ : '',
151
+ launch: isRecord(value.claudeLaunch)
152
+ ? value.claudeLaunch.payload
153
+ : undefined,
154
+ }),
155
+ recordBase: value.recordBase,
156
+ })
157
+ : parseGenericDispatchRecord(value.record);
158
+ const boundedInput = { record, event: value.event };
136
159
  // Raw provider metadata is the one input a caller may legitimately supply
137
160
  // unmodified, so it is projected through the owning parser's allowlist and
138
161
  // asserted as the projection. Everything else is asserted exactly as given.
@@ -143,15 +166,14 @@ export function parseDispatchRecordInput(value) {
143
166
  ? value.event.metadata
144
167
  : null;
145
168
  assertNoSensitiveDispatchContent(rawMetadata === null
146
- ? value
169
+ ? boundedInput
147
170
  : {
148
- ...value,
171
+ ...boundedInput,
149
172
  event: {
150
173
  ...value.event,
151
174
  metadata: { ...rawMetadata, entries: null },
152
175
  },
153
176
  });
154
- const record = parseGenericDispatchRecord(value.record);
155
177
  if (rawMetadata !== null) {
156
178
  if ('observation' in value.event) {
157
179
  throw new Error('A runtime observation event carries either observation or metadata, not both.');
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/dispatch-ceiling/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAkB9B,OAAO,EAUL,KAAK,uBAAuB,EAY7B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAEL,KAAK,cAAc,EAEpB,MAAM,iBAAiB,CAAC;AA6BzB,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAiC5C,UAAU,2BAA2B;IACnC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,sBAAsB,EAAE,CACtB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7B,oBAAoB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC7E,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;CAC/B;AAkyFD,wBAAgB,mCAAmC,CACjD,SAAS,GAAE,OAAO,CAAC,2BAA2B,CAAM,GACnD,OAAO,CA0GT"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/dispatch-ceiling/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAkB9B,OAAO,EAUL,KAAK,uBAAuB,EAY7B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAEL,KAAK,cAAc,EAEpB,MAAM,iBAAiB,CAAC;AAoCzB,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAiC5C,UAAU,2BAA2B;IACnC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,sBAAsB,EAAE,CACtB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7B,oBAAoB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC7E,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;CAC/B;AAm4FD,wBAAgB,mCAAmC,CACjD,SAAS,GAAE,OAAO,CAAC,2BAA2B,CAAM,GACnD,OAAO,CA0GT"}
@@ -12,7 +12,9 @@ import { getOwnKey, setOwnKey } from '../../../config/own-keys.js';
12
12
  import { resolveEffectiveConfig, } from '../../../config/resolve.js';
13
13
  import { resolveProjectRoot } from '../../../fs/paths.js';
14
14
  import TOML from '@iarna/toml';
15
- import { getCeilingAdapter, isDirectDispatchRoleName, CLAUDE_TIER_ORDER, } from '../../../providers/ceiling/registry.js';
15
+ import { getCeilingAdapter, isDirectDispatchRoleName, } from '../../../providers/ceiling/registry.js';
16
+ import { claudeTargetRank, CLAUDE_EFFORT_ORDER, validateClaudeDispatchCapability, validateClaudeDispatchTarget, } from '../../../providers/claude/targets.js';
17
+ import { SUPPORTED_CODEX_ROLE_TARGETS } from '../../../providers/codex/codec/shared.js';
16
18
  import { buildDispatchReport, formatDispatchReport, } from '../../../providers/identity/dispatch-report.js';
17
19
  import { classifyModelFamily, } from '../../../providers/identity/family.js';
18
20
  import { formatDispatchStamp, } from '../../../providers/identity/stamp.js';
@@ -21,6 +23,11 @@ import YAML from 'yaml';
21
23
  const CODEX_VALUES = [
22
24
  ...VALID_CODEX_DISPATCH_CEILINGS,
23
25
  ];
26
+ // Catalogue order is low to high within each model; the scalar ceiling
27
+ // remains separately capped by CODEX_VALUES.
28
+ const CODEX_CANDIDATE_EFFORTS = [
29
+ ...new Set(SUPPORTED_CODEX_ROLE_TARGETS.map((target) => target.effort)),
30
+ ];
24
31
  const CLAUDE_VALUES = [
25
32
  ...VALID_CLAUDE_DISPATCH_CEILINGS,
26
33
  ];
@@ -124,6 +131,9 @@ function validManagedPolicyList() {
124
131
  return managedDispatchPolicyValueList(', ');
125
132
  }
126
133
  function validProviderValueList(provider) {
134
+ if (provider === 'codex') {
135
+ return CODEX_VALUES.join(', ');
136
+ }
127
137
  return providerValueOrder(provider)?.join(', ') ?? 'none';
128
138
  }
129
139
  function compiledPolicyValueForProvider(provider, compiled) {
@@ -259,6 +269,39 @@ function routeTargetFromObject(provider, target, routeIndex, routeLength) {
259
269
  routeLength,
260
270
  };
261
271
  }
272
+ function resolveClaudeTargetCapability(target, env) {
273
+ if (!target ||
274
+ target.harness !== 'claude' ||
275
+ !target.model ||
276
+ !target.effort) {
277
+ return target;
278
+ }
279
+ const validation = validateClaudeDispatchCapability({
280
+ model: target.model,
281
+ effort: target.effort,
282
+ ...(target.capabilityEvidence
283
+ ? { capabilityEvidence: target.capabilityEvidence }
284
+ : {}),
285
+ }, env);
286
+ if (!validation.valid || !validation.capabilityEvidence) {
287
+ throw new Error(validation.reason ??
288
+ 'Claude effort target has no established model capability.');
289
+ }
290
+ return { ...target, capabilityEvidence: validation.capabilityEvidence };
291
+ }
292
+ function resolveClaudePolicyCapabilities(policy, env) {
293
+ if (!policy)
294
+ return policy;
295
+ return {
296
+ ...policy,
297
+ target: resolveClaudeTargetCapability(policy.target, env) ?? null,
298
+ ...(policy.ceilingTarget !== undefined
299
+ ? {
300
+ ceilingTarget: resolveClaudeTargetCapability(policy.ceilingTarget, env) ?? null,
301
+ }
302
+ : {}),
303
+ };
304
+ }
262
305
  function resolveRouteMatrixCell(provider, route, escalationLevel, cellSource) {
263
306
  const routeIndex = Math.min(escalationLevel, route.length - 1);
264
307
  const entry = route[routeIndex];
@@ -319,6 +362,8 @@ function resolveProviderCellFromValue(provider, providerValue, tier, cellSource,
319
362
  };
320
363
  }
321
364
  if (isWorkflowDispatchCandidateLadder(cell)) {
365
+ if (provider === 'claude')
366
+ assertCandidateOrder(provider, tier, cell);
322
367
  const ceiling = cell.candidates.at(-1);
323
368
  if (ceiling === undefined) {
324
369
  return null;
@@ -417,7 +462,7 @@ function candidatePrimaryTarget(provider, tier, candidate) {
417
462
  if (targetAdapter.selectionAxis === 'model-effort' &&
418
463
  (!target.model ||
419
464
  !target.effort ||
420
- !CODEX_VALUES.includes(target.effort))) {
465
+ !CODEX_CANDIDATE_EFFORTS.includes(target.effort))) {
421
466
  throw new Error(`Malformed ${provider} candidate ordering in ${tier}: Codex candidates require a model and supported effort.`);
422
467
  }
423
468
  if ((targetAdapter.selectionAxis === 'model' ||
@@ -425,6 +470,15 @@ function candidatePrimaryTarget(provider, tier, candidate) {
425
470
  !target.model) {
426
471
  throw new Error(`Malformed ${provider} candidate ordering in ${tier}: model-argument candidates require a model.`);
427
472
  }
473
+ if (target.harness === 'claude' && target.model) {
474
+ const validation = validateClaudeDispatchTarget({
475
+ model: target.model,
476
+ ...(target.effort ? { effort: target.effort } : {}),
477
+ });
478
+ if (!validation.valid) {
479
+ throw new Error(`Malformed ${provider} candidate ordering in ${tier}: ${validation.reason}`);
480
+ }
481
+ }
428
482
  return target;
429
483
  }
430
484
  function candidateTargetKey(target) {
@@ -450,17 +504,18 @@ function assertCandidateOrder(provider, tier, ladder) {
450
504
  }
451
505
  seen.add(key);
452
506
  if (target.harness === 'claude' && target.model) {
453
- const rank = CLAUDE_TIER_ORDER.indexOf(target.model);
454
- if (rank < 0) {
455
- throw new Error(`Malformed ${provider} candidate ordering in ${tier}: unsupported Claude model ${JSON.stringify(target.model)}.`);
456
- }
507
+ const [modelRank, effortRank] = claudeTargetRank({
508
+ model: target.model,
509
+ ...(target.effort ? { effort: target.effort } : {}),
510
+ });
511
+ const rank = modelRank * CLAUDE_EFFORT_ORDER.length + effortRank;
457
512
  if (previousClaudeRank !== null && rank < previousClaudeRank) {
458
513
  throw new Error(`Malformed ${provider} candidate ordering in ${tier}: Claude candidates must be nondecreasing.`);
459
514
  }
460
515
  previousClaudeRank = rank;
461
516
  }
462
517
  if (target.harness === 'codex' && target.model && target.effort) {
463
- const rank = CODEX_VALUES.indexOf(target.effort);
518
+ const rank = CODEX_CANDIDATE_EFFORTS.indexOf(target.effort);
464
519
  const previousRank = codexRanksByModel.get(target.model);
465
520
  if (previousRank !== undefined && rank < previousRank) {
466
521
  throw new Error(`Malformed ${provider} candidate ordering in ${tier}: Codex efforts for ${target.model} must be nondecreasing.`);
@@ -478,16 +533,26 @@ function assertTierCeilingsNondecreasing(provider, previous, current, tier) {
478
533
  if (current.harness === 'claude' &&
479
534
  previous.model &&
480
535
  current.model &&
481
- CLAUDE_TIER_ORDER.indexOf(current.model) <
482
- CLAUDE_TIER_ORDER.indexOf(previous.model)) {
536
+ (() => {
537
+ const [previousModel, previousEffort] = claudeTargetRank({
538
+ model: previous.model,
539
+ ...(previous.effort ? { effort: previous.effort } : {}),
540
+ });
541
+ const [currentModel, currentEffort] = claudeTargetRank({
542
+ model: current.model,
543
+ ...(current.effort ? { effort: current.effort } : {}),
544
+ });
545
+ return (currentModel < previousModel ||
546
+ (currentModel === previousModel && currentEffort < previousEffort));
547
+ })()) {
483
548
  throw new Error(`Malformed ${provider} candidate ordering in ${tier}: named tier ceilings must be nondecreasing.`);
484
549
  }
485
550
  if (current.harness === 'codex' &&
486
551
  previous.model === current.model &&
487
552
  previous.effort &&
488
553
  current.effort &&
489
- CODEX_VALUES.indexOf(current.effort) <
490
- CODEX_VALUES.indexOf(previous.effort)) {
554
+ CODEX_CANDIDATE_EFFORTS.indexOf(current.effort) <
555
+ CODEX_CANDIDATE_EFFORTS.indexOf(previous.effort)) {
491
556
  throw new Error(`Malformed ${provider} candidate ordering in ${tier}: named tier ceilings must be nondecreasing.`);
492
557
  }
493
558
  }
@@ -495,10 +560,11 @@ function requestedCandidateMatches(provider, requested, target) {
495
560
  if (target.harness !== provider || target.model !== requested.model) {
496
561
  return false;
497
562
  }
498
- return provider !== 'codex' || target.effort === requested.effort;
563
+ return ((provider !== 'codex' && provider !== 'claude') ||
564
+ target.effort === requested.effort);
499
565
  }
500
566
  function formatRequestedCandidate(provider, requested) {
501
- return provider === 'codex'
567
+ return provider === 'codex' || requested.effort !== undefined
502
568
  ? `${requested.model}/${requested.effort}`
503
569
  : requested.model;
504
570
  }
@@ -867,7 +933,7 @@ function normalizeRole(value) {
867
933
  }
868
934
  function providerValueOrder(provider) {
869
935
  if (provider === 'codex') {
870
- return CODEX_VALUES;
936
+ return CODEX_CANDIDATE_EFFORTS;
871
937
  }
872
938
  if (provider === 'claude') {
873
939
  return CLAUDE_VALUES;
@@ -887,7 +953,7 @@ function normalizePreferredValue(provider, value) {
887
953
  return null;
888
954
  }
889
955
  if (!isValidProviderValue(provider, normalized)) {
890
- const validValues = order.join(', ');
956
+ const validValues = (provider === 'codex' ? CODEX_VALUES : order).join(', ');
891
957
  throw new Error(`Invalid preferred dispatch value "${normalized}" for ${provider}. Valid values: ${validValues}.`);
892
958
  }
893
959
  return normalized;
@@ -927,17 +993,23 @@ function normalizeRequestedCandidate(provider, role, options) {
927
993
  if (!effort) {
928
994
  throw new Error('--candidate-effort is required for an exact Codex candidate.');
929
995
  }
930
- if (!CODEX_VALUES.includes(effort)) {
931
- throw new Error(`Invalid Codex candidate effort "${effort}". Valid values: ${CODEX_VALUES.join(', ')}.`);
996
+ if (!CODEX_CANDIDATE_EFFORTS.includes(effort)) {
997
+ throw new Error(`Invalid Codex candidate effort "${effort}". Valid values: ${CODEX_CANDIDATE_EFFORTS.join(', ')}.`);
932
998
  }
933
999
  return { model, effort };
934
1000
  }
935
- if (effort) {
936
- throw new Error(`--candidate-effort is only valid for Codex; ${provider} candidates use --candidate-model only.`);
1001
+ if (provider === 'claude') {
1002
+ const validation = validateClaudeDispatchTarget({
1003
+ model,
1004
+ ...(effort ? { effort } : {}),
1005
+ });
1006
+ if (!validation.valid) {
1007
+ throw new Error(validation.reason);
1008
+ }
1009
+ return effort ? { model, effort } : { model };
937
1010
  }
938
- if (provider === 'claude' &&
939
- !CLAUDE_VALUES.includes(model)) {
940
- throw new Error(`Invalid Claude candidate model "${model}". Valid values: ${CLAUDE_VALUES.join(', ')}.`);
1011
+ if (effort) {
1012
+ throw new Error(`--candidate-effort is only valid for Codex or Claude; ${provider} candidates use --candidate-model only.`);
941
1013
  }
942
1014
  return { model };
943
1015
  }
@@ -965,12 +1037,12 @@ function normalizeClassification(provider, role, options) {
965
1037
  throw new Error(`Invalid task class "${taskClassValue}". Valid values: ${TASK_CLASSES.join(', ')}.`);
966
1038
  }
967
1039
  const taskEffort = options.taskEffort?.trim() ?? '';
968
- if (hasTaskEffort && provider !== 'codex') {
969
- throw new Error(`--task-effort is only valid for Codex; received ${provider}.`);
1040
+ if (hasTaskEffort && provider !== 'codex' && provider !== 'claude') {
1041
+ throw new Error(`--task-effort is only valid for Codex or Claude; received ${provider}.`);
970
1042
  }
971
- if (hasTaskEffort &&
972
- !CODEX_VALUES.includes(taskEffort)) {
973
- throw new Error(`Invalid Codex task effort "${taskEffort}". Valid values: ${CODEX_VALUES.join(', ')}.`);
1043
+ const validTaskEfforts = provider === 'claude' ? CLAUDE_EFFORT_ORDER : CODEX_CANDIDATE_EFFORTS;
1044
+ if (hasTaskEffort && !validTaskEfforts.includes(taskEffort)) {
1045
+ throw new Error(`Invalid ${provider === 'claude' ? 'Claude' : 'Codex'} task effort "${taskEffort}". Valid values: ${validTaskEfforts.join(', ')}.`);
974
1046
  }
975
1047
  return {
976
1048
  taskClass: hasTaskClass ? taskClassValue : null,
@@ -1153,7 +1225,7 @@ function codexEffortAxis(selection, dispatchArgs) {
1153
1225
  * the enforcement mode, mechanism, dispatch args, and verify-on-upgrade flag.
1154
1226
  * Mode is computed here at call time — it is never read from persisted state.
1155
1227
  */
1156
- function buildProviderResolution(provider, policy, role, orchestratorTier, preferredValue) {
1228
+ function buildProviderResolution(provider, policy, role, orchestratorTier, preferredValue, env) {
1157
1229
  const adapter = getCeilingAdapter(provider);
1158
1230
  if (policy === null) {
1159
1231
  return {
@@ -1193,6 +1265,7 @@ function buildProviderResolution(provider, policy, role, orchestratorTier, prefe
1193
1265
  ? adapter.compileToDispatchArgs(dispatchValue, role, {
1194
1266
  orchestratorTier,
1195
1267
  target: selection.target,
1268
+ env,
1196
1269
  })
1197
1270
  : null;
1198
1271
  let mode;
@@ -1208,12 +1281,16 @@ function buildProviderResolution(provider, policy, role, orchestratorTier, prefe
1208
1281
  return {
1209
1282
  value: policy.value,
1210
1283
  mode,
1211
- mechanism: adapter.mechanism,
1284
+ mechanism: hasVariantDispatchArgs(dispatchArgs)
1285
+ ? 'pinned-variant'
1286
+ : adapter.mechanism,
1212
1287
  dispatchArgs,
1213
1288
  modelAxis: modelAxis(provider, selection, dispatchArgs),
1214
1289
  effortAxis: provider === 'codex'
1215
1290
  ? codexEffortAxis(selection, dispatchArgs)
1216
- : 'not-applicable',
1291
+ : provider === 'claude' && selection.target?.effort
1292
+ ? `selected:${selection.target.effort}`
1293
+ : 'not-applicable',
1217
1294
  verifyOnDispatch: dispatchValue && !isCrossHarness
1218
1295
  ? adapter.verifyOnDispatch(dispatchValue, {
1219
1296
  orchestratorTier,
@@ -1385,11 +1462,11 @@ async function resolveDispatchCeiling(context, dependencies, options) {
1385
1462
  const escalationLevel = normalizeEscalationLevel(options.escalationLevel);
1386
1463
  const policyResolution = readResolvedConfigCeiling(provider, resolvedConfig) ??
1387
1464
  (await resolveProjectStateCeiling(provider, projectPath, dependencies));
1388
- const resolvedValue = await resolveCeilingValue(provider, resolvedConfig, projectPath, dependencies, escalationLevel, role, preferredValue, requestedCandidate, ceilingTier);
1465
+ const resolvedValue = resolveClaudePolicyCapabilities(await resolveCeilingValue(provider, resolvedConfig, projectPath, dependencies, escalationLevel, role, preferredValue, requestedCandidate, ceilingTier), dependencies.processEnv);
1389
1466
  for (const warning of resolvedValue?.warnings ?? []) {
1390
1467
  context.logger.warn(warning);
1391
1468
  }
1392
- const providerResolution = buildProviderResolution(provider, resolvedValue, role, orchestratorTier, preferredValue);
1469
+ const providerResolution = buildProviderResolution(provider, resolvedValue, role, orchestratorTier, preferredValue, dependencies.processEnv);
1393
1470
  const providers = {
1394
1471
  [provider]: providerResolution,
1395
1472
  };
@@ -1714,7 +1791,7 @@ function writeHumanResolution(context, resolution) {
1714
1791
  }
1715
1792
  }
1716
1793
  else {
1717
- context.logger.info('Effort axis: not-applicable');
1794
+ context.logger.info(`Effort axis: ${providerResolution?.effortAxis ?? 'not-applicable'}`);
1718
1795
  if (providerResolution?.selection.selectionMode === 'inherit-default') {
1719
1796
  context.logger.info('Note: OAT will not select a Claude model; Task dispatch inherits host/provider behavior.');
1720
1797
  }
@@ -1910,9 +1987,9 @@ export function createProjectDispatchCeilingCommand(overrides = {}) {
1910
1987
  .option('--preferred <value>', 'Legacy preferred implementer/fix value before applying the resolved policy')
1911
1988
  .addOption(new Option('--ceiling-tier <tier>', 'Invocation-only named maximum tier; never persists configuration or project state').choices([...VALID_DISPATCH_MATRIX_TIERS]))
1912
1989
  .option('--candidate-model <model>', 'Exact configured implementer candidate model beneath the named ceiling')
1913
- .option('--candidate-effort <effort>', 'Exact configured Codex candidate effort paired with --candidate-model')
1990
+ .option('--candidate-effort <effort>', 'Exact configured Codex or Claude candidate effort paired with --candidate-model')
1914
1991
  .option('--task-class <class>', `Provider-neutral task classification provenance: ${TASK_CLASSES.join(', ')}`)
1915
- .option('--task-effort <effort>', 'Codex-only task effort classification provenance; does not select a candidate')
1992
+ .option('--task-effort <effort>', 'Codex or Claude task effort classification provenance; does not select a candidate')
1916
1993
  .option('--escalation-level <level>', 'Ordered route entry to select; 0 is the floor and higher values advance through escalation targets')
1917
1994
  .option('--project-path <path>', 'Read project-state policy from an explicit project path')
1918
1995
  .option('--preflight', 'Treat unresolved non-interactive resolution as an implementation block')
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch-matrix.d.ts","sourceRoot":"","sources":["../../src/config/dispatch-matrix.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dispatch-matrix.d.ts","sourceRoot":"","sources":["../../src/config/dispatch-matrix.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { validateClaudeDispatchTarget } from '../providers/claude/targets.js';
1
2
  export const VALID_DISPATCH_MATRIX_TIERS = ['economy', 'balanced', 'high', 'frontier'];
2
3
  const VALID_CODEX_PROVIDER_SCALARS = new Set([
3
4
  'low',
@@ -205,6 +206,18 @@ export function isCodexMaterializedRouteTarget(provider, target) {
205
206
  return (target.harness ?? provider) === 'codex';
206
207
  }
207
208
  export function validateDispatchRouteTarget(provider, target) {
209
+ if ((target.harness ?? provider) === 'claude') {
210
+ if (!target.model) {
211
+ return {
212
+ valid: false,
213
+ reason: 'Claude dispatch targets must provide a model.',
214
+ };
215
+ }
216
+ return validateClaudeDispatchTarget({
217
+ model: target.model,
218
+ ...(target.effort ? { effort: target.effort } : {}),
219
+ });
220
+ }
208
221
  if (!isCodexMaterializedRouteTarget(provider, target)) {
209
222
  return { valid: true };
210
223
  }
@@ -1,3 +1,4 @@
1
+ import { type ClaudeCapabilityEvidence } from '../claude/targets.js';
1
2
  /**
2
3
  * Provider ceiling adapter registry.
3
4
  *
@@ -9,8 +10,9 @@
9
10
  * to produce concrete dispatch args — skills never re-implement this logic.
10
11
  *
11
12
  * Codex enforces via sync-time materialized role variants selected from matrix
12
- * model+effort targets. Claude enforces via the per-call Task `model` argument
13
- * (no variant files). Every other provider is advisory by default.
13
+ * model+effort targets. Claude effort routes use materialized model-and-effort
14
+ * variants, while legacy model-only routes keep the per-call Task `model`
15
+ * argument. Every other provider is advisory by default.
14
16
  */
15
17
  export type EnforcementMechanism = 'pinned-variant' | 'model-arg' | 'none';
16
18
  export type ProviderSelectionAxis = 'model' | 'model-effort' | 'tier' | 'none';
@@ -18,9 +20,12 @@ export type CeilingRole = 'implementer' | 'reviewer';
18
20
  export interface CeilingCompileContext {
19
21
  /** The orchestrator's own tier, used to detect above-orchestrator upgrades. */
20
22
  orchestratorTier?: string;
23
+ /** Provider environment used by the resolver's capability derivation. */
24
+ env?: NodeJS.ProcessEnv;
21
25
  target?: {
22
26
  model?: string;
23
27
  effort?: string;
28
+ capabilityEvidence?: ClaudeCapabilityEvidence;
24
29
  } | null;
25
30
  }
26
31
  export type CeilingDispatchArgs = {
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/providers/ceiling/registry.ts"],"names":[],"mappings":"AASA;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,GAAG,WAAW,GAAG,MAAM,CAAC;AAC3E,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,cAAc,GAAG,MAAM,GAAG,MAAM,CAAC;AAE/E,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,UAAU,CAAC;AAErD,MAAM,WAAW,qBAAqB;IACpC,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE;QACP,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,IAAI,CAAC;CACV;AAED,MAAM,MAAM,mBAAmB,GAC3B;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GACnB;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GACjB,IAAI,CAAC;AAKT,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE/D;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,oBAAoB,CAAC;IAChC,aAAa,EAAE,qBAAqB,CAAC;IACrC;;;OAGG;IACH,qBAAqB,CACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,qBAAqB,GACzB,mBAAmB,CAAC;IACvB;;;;OAIG;IACH,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,qBAAqB,GAAG,OAAO,CAAC;CACtE;AAMD,wEAAwE;AACxE,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAK9C,CAAC;AA6HF;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,sBAAsB,CAM1E"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/providers/ceiling/registry.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,KAAK,wBAAwB,EAE9B,MAAM,2BAA2B,CAAC;AAQnC;;;;;;;;;;;;;;GAcG;AAEH,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,GAAG,WAAW,GAAG,MAAM,CAAC;AAC3E,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,cAAc,GAAG,MAAM,GAAG,MAAM,CAAC;AAE/E,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,UAAU,CAAC;AAErD,MAAM,WAAW,qBAAqB;IACpC,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,yEAAyE;IACzE,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,MAAM,CAAC,EAAE;QACP,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,kBAAkB,CAAC,EAAE,wBAAwB,CAAC;KAC/C,GAAG,IAAI,CAAC;CACV;AAED,MAAM,MAAM,mBAAmB,GAC3B;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GACnB;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GACjB,IAAI,CAAC;AAKT,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE/D;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,oBAAoB,CAAC;IAChC,aAAa,EAAE,qBAAqB,CAAC;IACrC;;;OAGG;IACH,qBAAqB,CACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,qBAAqB,GACzB,mBAAmB,CAAC;IACvB;;;;OAIG;IACH,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,qBAAqB,GAAG,OAAO,CAAC;CACtE;AAMD,wEAAwE;AACxE,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAA4B,CAAC;AAkK5E;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,sBAAsB,CAM1E"}