@open-agent-toolkit/cli 0.1.54 → 0.1.59

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 (45) hide show
  1. package/assets/agents/oat-phase-implementer.md +195 -238
  2. package/assets/docs/cli-utilities/configuration.md +7 -6
  3. package/assets/docs/contributing/index.md +1 -0
  4. package/assets/docs/contributing/smoke-testing.md +284 -0
  5. package/assets/docs/provider-sync/providers.md +11 -11
  6. package/assets/docs/provider-sync/scope-and-surface.md +2 -2
  7. package/assets/docs/workflows/projects/dispatch-ceiling.md +29 -26
  8. package/assets/docs/workflows/projects/evidence-layers.md +123 -0
  9. package/assets/docs/workflows/projects/implementation-execution.md +160 -406
  10. package/assets/docs/workflows/projects/index.md +8 -0
  11. package/assets/docs/workflows/projects/orchestration-model.md +190 -0
  12. package/assets/docs/workflows/projects/programmatic-execution.md +137 -0
  13. package/assets/docs/workflows/projects/review-flavors.md +129 -0
  14. package/assets/docs/workflows/skills/repo-improve.md +14 -0
  15. package/assets/public-package-versions.json +4 -4
  16. package/assets/skills/oat-agent-instructions-analyze/references/docs/provider-reference.md +5 -4
  17. package/assets/skills/oat-agent-instructions-apply/references/docs/provider-reference.md +5 -4
  18. package/assets/skills/oat-dispatch-subagents/SKILL.md +6 -1
  19. package/assets/skills/oat-dispatch-subagents/references/record-schema.md +5 -0
  20. package/assets/skills/oat-project-dispatch-subagents/SKILL.md +37 -15
  21. package/assets/skills/oat-project-implement/SKILL.md +63 -1904
  22. package/assets/skills/oat-project-implement/references/completion-and-closeout.md +431 -0
  23. package/assets/skills/oat-project-implement/references/dispatch-and-dry-run.md +715 -0
  24. package/assets/skills/oat-project-implement/references/phase-execution.md +270 -0
  25. package/assets/skills/oat-project-implement/references/plan-and-resume.md +279 -0
  26. package/assets/skills/oat-project-import-plan/SKILL.md +16 -8
  27. package/assets/skills/oat-project-plan/SKILL.md +15 -7
  28. package/assets/skills/oat-project-plan-writing/SKILL.md +74 -40
  29. package/assets/skills/oat-project-quick-start/SKILL.md +16 -8
  30. package/assets/skills/oat-project-review-provide/SKILL.md +8 -5
  31. package/assets/skills/oat-repo-improve/SKILL.md +17 -2
  32. package/assets/skills/oat-repo-improve/references/audit-playbook.md +6 -0
  33. package/assets/skills/oat-worktree-bootstrap/SKILL.md +22 -12
  34. package/assets/skills/oat-worktree-bootstrap/references/worktree-conventions.md +8 -8
  35. package/assets/skills/oat-worktree-bootstrap-auto/SKILL.md +233 -44
  36. package/dist/commands/docs/index-generate/index.d.ts.map +1 -1
  37. package/dist/commands/docs/index-generate/index.js +10 -5
  38. package/dist/commands/doctor/index.d.ts.map +1 -1
  39. package/dist/commands/doctor/index.js +7 -4
  40. package/dist/commands/gate/index.d.ts +9 -1
  41. package/dist/commands/gate/index.d.ts.map +1 -1
  42. package/dist/commands/gate/index.js +62 -2
  43. package/dist/commands/project/dispatch-ceiling/index.js +2 -2
  44. package/package.json +4 -4
  45. package/assets/skills/oat-worktree-bootstrap-auto/scripts/bootstrap.sh +0 -236
@@ -0,0 +1,284 @@
1
+ ---
2
+ title: Smoke Testing
3
+ description: 'Runbook for the OAT live workflow smoke runner: preflight, scenarios, evidence, cleanup, and fixture maintenance.'
4
+ ---
5
+
6
+ # Smoke Testing
7
+
8
+ The smoke runner (`tools/smoke/`) drives the real OAT orchestration workflows end
9
+ to end against a self-contained fixture project. It provisions a disposable Git
10
+ worktree, hands that worktree to a live provider harness, collects durable
11
+ evidence of what actually happened, verifies the evidence against per-scenario
12
+ assertion profiles, and then removes everything it created.
13
+
14
+ Run it manually as release validation and after any change that could alter
15
+ orchestration behavior — dispatch, parallel phase topology, review gating, state
16
+ transitions, or the fixture contract itself. It is deliberately **not** part of
17
+ the default CI path: each run launches real provider processes and external
18
+ review gates, so it is operator-initiated rather than automatic.
19
+
20
+ This page describes the machinery and the process. It does not report the
21
+ outcome of any particular run.
22
+
23
+ ## Data flow
24
+
25
+ ```mermaid
26
+ flowchart TD
27
+ F["Fixture template\ntools/smoke/fixture/"] --> PRE["Preflight\ninstall + auth + fixture + local oat"]
28
+ PRE -->|blocked| STOP["Exit before provisioning"]
29
+ PRE -->|ready| PREP["Prepare / provision\ndisposable worktree + isolated config + manifest"]
30
+ PREP --> DRIVE["Drive\nper-harness protocol"]
31
+ DRIVE --> AUTO["Automated: runner launches provider"]
32
+ DRIVE --> OP["Operator: printed command + prompt"]
33
+ AUTO --> COLLECT["Collect\nevidence bundle + report"]
34
+ OP --> COLLECT
35
+ COLLECT --> CLEAN["Cleanup\nmanifest-scoped"]
36
+ COLLECT -.->|--keep| SKIP["Cleanup skipped"]
37
+ ```
38
+
39
+ Collection runs even when the drive stage fails, so a broken run still produces
40
+ an evidence bundle before cleanup reclaims its resources.
41
+
42
+ ## Prerequisites
43
+
44
+ Preflight (`tools/smoke/runner/preflight.mjs`) derives the required runtime set
45
+ from both the selected drive harness and its independent gate runtime. Every
46
+ distinct required runtime must be installed and authenticated before
47
+ provisioning. Preflight also runs `oat gate target list --json` and requires the
48
+ configured target to report available without launching a review.
49
+
50
+ | Harness | Runtime probe | Authentication probe |
51
+ | ------------ | ------------------------ | --------------------- |
52
+ | `codex` | `codex --version` | `codex login status` |
53
+ | `claude` | `claude --version` | `claude auth status` |
54
+ | `cursor-ide` | `cursor --version` | `cursor agent status` |
55
+ | `cursor-cli` | `cursor-agent --version` | `cursor-agent status` |
56
+
57
+ Additional readiness requirements before a run can start:
58
+
59
+ - **`CURSOR_API_KEY` presence.** Required when the harness is `cursor-cli` or
60
+ `cursor-ide`, or when the selected gate runtime is Cursor (this is the case
61
+ for the Codex harness, whose review gate is cross-runtime). Preflight checks
62
+ only for a non-empty value; the key is never printed, logged, or written into
63
+ config, manifests, prompts, or evidence.
64
+ - **Local build.** Preflight requires the CLI to resolve to the freshly built
65
+ local dist entrypoint (`packages/cli/dist/index.js`) through the committed
66
+ `tools/smoke/bin/oat` shim, with a version matching source. Build the CLI
67
+ first (for example, `pnpm build`) so the disposable worktree does not fall
68
+ through to a global `oat`.
69
+ - **Fixture integrity.** Preflight runs the fixture validators and checks the
70
+ required project artifacts, presets, and seed logs before provisioning.
71
+
72
+ If any required check fails, preflight raises `PreflightError` and no
73
+ provisioning is started.
74
+
75
+ ## Scenario selection
76
+
77
+ Select the scenario with `--scenario`. The manifest's applied scenario is the
78
+ authoritative selector for which assertion profile the evidence is checked
79
+ against.
80
+
81
+ - **`plan-review`** — proves the plan-review lifecycle: the substantive plan
82
+ (task IDs and parallel groups) is stable across resume, the plan gate review
83
+ is corroborated against gate-owned invocation evidence, and state advances
84
+ atomically from pre-review through reviewed to implementation-ready.
85
+ - **`implement`** — proves execution: one accepted, completed phase implementer
86
+ and one direct-root phase reviewer for each of `p01`, `p02`, and `p03`;
87
+ exactly five fixture markers and five bounded task commits; exact
88
+ at-or-below-ceiling target selection; isolated flat parallel branches with
89
+ fan-in after all declared dependencies; phase-review row and artifact
90
+ binding; explicit runtime identity status; and exactly one final code gate
91
+ after `p03`.
92
+ - **`full`** — unions the plan-review and implement profiles. It runs exactly
93
+ two external gates: one plan-review gate before implementation and one final
94
+ code gate after `p03`.
95
+
96
+ ## Running
97
+
98
+ The runner entrypoint is `tools/smoke/runner/run-smoke.mjs`. `--harness` and
99
+ `--scenario` are always required. Drive mode defaults to `automated` and all
100
+ stages (`prepare`, `drive`, `collect`) run by default.
101
+
102
+ ### Automated full run
103
+
104
+ Automated drive supports `codex`, `claude`, and `cursor-cli`. The runner
105
+ launches the provider itself and runs all three stages:
106
+
107
+ ```bash
108
+ node tools/smoke/runner/run-smoke.mjs --harness codex --scenario full
109
+ ```
110
+
111
+ ### Operator prepare/collect split
112
+
113
+ Operator mode splits the lifecycle so a noninteractive command cannot drive by
114
+ accident. Passing `--drive-mode operator` without `--stage` defaults to
115
+ `prepare` only, so you run prepare and collect as separate commands:
116
+
117
+ ```bash
118
+ node tools/smoke/runner/run-smoke.mjs \
119
+ --harness claude --scenario full --drive-mode operator --stage prepare
120
+ # Run the printed command and paste the printed prompt in an interactive TTY.
121
+ node tools/smoke/runner/run-smoke.mjs \
122
+ --harness claude --scenario full --drive-mode operator --stage collect
123
+ ```
124
+
125
+ Prepare prints the disposable worktree path, the interactive provider command,
126
+ and the canned root prompt. Complete the driven session before running collect.
127
+
128
+ ### Manual Cursor IDE flow
129
+
130
+ `cursor-ide` is operator-driven by definition, so it always uses the
131
+ prepare/collect shape and never substitutes a headless CLI drive. Do not pass
132
+ `--drive-mode operator`; its canonical report root omits the `operator/`
133
+ segment.
134
+
135
+ ```bash
136
+ node tools/smoke/runner/run-smoke.mjs --harness cursor-ide --scenario full --stage prepare
137
+ ```
138
+
139
+ Then, following `tools/smoke/protocols/cursor-ide.md`:
140
+
141
+ 1. Open the printed disposable worktree in Cursor.
142
+ 2. Start a new Agent session in that worktree.
143
+ 3. Paste the canned root prompt printed by prepare and let the session finish.
144
+ 4. Run the matching collect stage:
145
+
146
+ ```bash
147
+ node tools/smoke/runner/run-smoke.mjs --harness cursor-ide --scenario full --stage collect
148
+ ```
149
+
150
+ For each required review gate, the canned prompt invokes `oat gate review`
151
+ exactly once with the harness's fixed `--target`. Listing targets with
152
+ `oat gate target list` is a valid probe; invoking a gate as a probe is not,
153
+ because an accepted gate launch is terminal even when it fails.
154
+
155
+ ### Dry run and keep
156
+
157
+ - `--dry-run` stubs the install and authentication probes and produces a drive
158
+ stub instead of launching a provider, letting you exercise the
159
+ provisioning and cleanup wiring. The fixture and local-CLI checks still run
160
+ for real.
161
+ - `--keep` short-circuits cleanup so the worktree, branches, and manifest remain
162
+ on disk for inspection.
163
+
164
+ ```bash
165
+ node tools/smoke/runner/run-smoke.mjs --harness cursor-cli --scenario plan-review --dry-run --keep
166
+ ```
167
+
168
+ ## Negative controls
169
+
170
+ Negative controls prove the runner refuses to do the wrong thing.
171
+
172
+ **Unavailable target.** Set `OAT_SMOKE_FORCE_UNAVAILABLE=<harness>` to force that
173
+ harness's runtime probe to report unavailable. Preflight then blocks before any
174
+ provisioning, and the control asserts that no manifests, branches, or worktrees
175
+ were created. Capture the failed runner output, then normalize it:
176
+
177
+ ```bash
178
+ OAT_SMOKE_FORCE_UNAVAILABLE=codex \
179
+ node tools/smoke/runner/run-smoke.mjs --harness codex --scenario plan-review \
180
+ > preflight-capture.txt 2>&1
181
+ node tools/smoke/evidence/negative.mjs \
182
+ --harness codex \
183
+ --preflight preflight-capture.txt \
184
+ --repository "$(pwd)" \
185
+ --runs-dir "$(pwd)/tools/smoke/.runs" \
186
+ --out tools/smoke/reports/negative-controls/codex
187
+ ```
188
+
189
+ **Post-acceptance failure.** Once a child launch is accepted and then fails, that
190
+ outcome is terminal: any launch after an accepted failure is a Critical
191
+ violation. Explicit pre-start rejections before the accepted launch remain
192
+ valid. This control is verified through the `post-acceptance-failure` profile
193
+ (see below).
194
+
195
+ ## Interpreting evidence reports
196
+
197
+ Reports are written outside the disposable worktree, under
198
+ `tools/smoke/reports/<harness>/<scenario>/` for automated runs and
199
+ `tools/smoke/reports/<harness>/operator/<scenario>/` for operator runs
200
+ (`cursor-ide` always uses the operator-free `tools/smoke/reports/cursor-ide/<scenario>/`
201
+ path).
202
+
203
+ The collect stage runs the collector and report generator automatically. To
204
+ regenerate or re-verify a report by hand:
205
+
206
+ ```bash
207
+ node tools/smoke/evidence/report.mjs --bundle <out>/bundle.json --out <out>
208
+ node tools/smoke/evidence/report.mjs --check <out>/report.json \
209
+ --expect-profile <plan-review|implement|full|unavailable-target|post-acceptance-failure>
210
+ ```
211
+
212
+ Reading the output:
213
+
214
+ - **`report.json` is authoritative.** It records the SHA-256 digest and sibling
215
+ path of the `bundle.json` it was generated from. The `report.md` table
216
+ (columns Assertion, Severity, Status, Description) is a derived, human-readable
217
+ view.
218
+ - **`--check` re-verification** rereads the bound bundle, validates its digest,
219
+ recomputes the scenario profile, and requires the caller's explicit expected
220
+ profile plus byte-equivalent results. It does not trust the report's stated
221
+ status, assertion IDs, severities, summary counts, or the bundle's own
222
+ scenario as the caller's intent.
223
+
224
+ The evidence is organized as three layers — launcher-owned production records,
225
+ independent durable corroboration from Git and the fixture, and the normalized
226
+ bundle and assertion report. See
227
+ [Evidence Layers](../workflows/projects/evidence-layers.md) for the model.
228
+
229
+ ## Cleanup and recovery
230
+
231
+ Cleanup (`tools/smoke/runner/cleanup.mjs`) is manifest-scoped: it only removes
232
+ resources the run journaled. It runs automatically when the run errored, when a
233
+ full `prepare` → `drive` → `collect` lifecycle completed, or when a
234
+ collection-only invocation ran. `--keep` short-circuits it entirely. An operator
235
+ `prepare` stage therefore intentionally leaves its worktree in place for you to
236
+ drive.
237
+
238
+ After an interrupted run you may find:
239
+
240
+ - `tools/smoke/.runs/smoke-<branch>/` containing the `provisioning-manifest.json`
241
+ and the disposable `worktree/`.
242
+ - The outer `smoke-*` branch and any journaled child branches created for
243
+ parallel phases.
244
+
245
+ Recovery validates the tracked smoke marker at each ownership baseline, refuses
246
+ divergent branch tips, mismatched shared Git directories, missing baseline
247
+ markers, and any run-descendant worktree or branch absent from the journal. A
248
+ journaled worktree that is already gone from disk is still recoverable; a
249
+ contradictory or unjournaled resource fails closed with a refusal rather than
250
+ guessing.
251
+
252
+ To finish a stalled run, re-run the matching `--stage collect` (collection-only
253
+ triggers cleanup) or start a fresh run; the runner reconciles journaled
254
+ resources on the next errored or collection-bearing invocation. If cleanup fails
255
+ closed on unjournaled state, resolve that state manually before retrying.
256
+
257
+ ## Updating the fixture as workflows change
258
+
259
+ When a workflow or skill contract changes shape, the fixture and its checks must
260
+ change with it, and a passing smoke run on the updated fixture is the acceptance
261
+ bar. Typical touch points:
262
+
263
+ - **Fixture plan** (`tools/smoke/fixture/project/plan.md`) — task IDs, the
264
+ parallel-groups declaration, each task's write target, and the expected commit
265
+ subject. Preflight enforces the task count, groups, and per-task integrity.
266
+ - **Lifecycle presets** (`tools/smoke/fixture/presets/`) — the `pre-review` and
267
+ `implementation-ready` frontmatter fingerprints that transition assertions
268
+ parse.
269
+ - **Protocols** (`tools/smoke/protocols/*.md`) — the canned prompts, fixed gate
270
+ counts, and expected per-harness topology.
271
+ - **Assertion profiles** (`tools/smoke/evidence/assertions.mjs`) — the expected
272
+ task IDs and the plan-review, implement, and full profiles.
273
+ - **Format contract tests** (`tools/smoke/fixture/fixture-format-contract.test.mjs`,
274
+ `fixture-integrity.test.mjs`, and `presets/apply-preset.test.mjs`) — run by
275
+ preflight and updated alongside any contract change.
276
+
277
+ Change these together, then run the affected scenario end to end. If the updated
278
+ fixture does not pass, the workflow change is not accepted.
279
+
280
+ ## Related
281
+
282
+ - [Contributing Code](code.md)
283
+ - [Implementation Execution](../workflows/projects/implementation-execution.md)
284
+ - [Dispatch Ceiling](../workflows/projects/dispatch-ceiling.md)
@@ -12,7 +12,7 @@ description: 'Provider-specific path mappings for Claude, Cursor, Copilot, Gemin
12
12
  - Project: `.agents/skills` -> `.claude/skills`, `.agents/agents` -> `.claude/agents`, `.agents/rules` -> `.claude/rules`
13
13
  - User: `~/.agents/skills` -> `~/.claude/skills`, `~/.agents/agents` -> `~/.claude/agents`
14
14
  - Rule files stay `.md` and are rendered with Claude-compatible frontmatter when needed
15
- - Managed task workers use the exact configured candidate returned as `providers.claude.dispatchArgs.model`; OAT passes that value as the actual Task `model`
15
+ - Managed phase implementers and optional nested workers use the exact configured candidate returned as `providers.claude.dispatchArgs.model`; OAT passes that value as the actual Agent `model`
16
16
 
17
17
  === "Cursor"
18
18
 
@@ -61,10 +61,10 @@ description: 'Provider-specific path mappings for Claude, Cursor, Copilot, Gemin
61
61
  - Codex `max` is a first-class dispatch effort. It is present only for the Sol family in the committed supported catalogue, for both implementer and reviewer roles.
62
62
  - Codex multi-agent dispatch uses config-defined roles (`[agents.<name>]`) and `agent_type`
63
63
  - Codex subagent workflows require `[features] multi_agent = true` in active Codex config layers
64
- - Managed Codex roles require `agents.max_depth >= 2` for the native topology: root (depth 0) → phase coordinator (depth 1) task worker (depth 2). Sync and direct materialization merge that floor without lowering a higher target value; project writes also preserve a higher inherited user value.
64
+ - Default managed Codex execution requires root (depth 0) → phase implementer (depth 1). `agents.max_depth >= 2` enables optional nested phase-agent work; sync and direct materialization still merge that capability floor without lowering a higher target value.
65
65
  - Project sync or materialization writes only the project's `.codex/config.toml`; explicit user-scope materialization writes only `~/.codex/config.toml`. Project scope may read the lower-precedence user depth, but never mutates user configuration.
66
- - When managed roles exist and effective depth is missing, invalid, or below `2`, `oat doctor` and managed implementation preflight explain the topology and recommend `oat sync --scope project` or `oat sync --scope user` for the affected scope. Direct materialization with the same scope is the single-role repair path.
67
- - `oat-phase-implementer` is dual-mode: Phase Scope makes it a phase coordinator, while Task Scope makes the exact materialized variant a one-task worker. The coordinator does not implement ordinary tasks itself.
66
+ - Missing depth and explicit depth `1` are sufficient for default phase execution. Invalid values or values below `1` block managed implementation preflight. `oat doctor` explains when depth `2` optional nesting is available.
67
+ - The phase implementer directly executes its planned tasks from one Phase Scope, preserves one bounded commit per task, and returns phase-wide verification. It does not dispatch the phase reviewer.
68
68
 
69
69
  ## Managed dispatch views
70
70
 
@@ -85,17 +85,17 @@ project `.codex` view. User-config candidates materialize under `~/.codex`.
85
85
  OAT does not auto-ignore project output or create its Git commit; the team owns
86
86
  that repository change.
87
87
 
88
- At implementation time, the phase coordinator passes the recorded named
89
- maximum through invocation-only `--ceiling-tier`, resolves one exact candidate
90
- per bounded task, and dispatches one task worker at a time. Codex first
91
- attempts the resolver-returned materialized role as the native `agent_type`.
92
- The launcher records the target, model axis, and effort axis from that resolved
93
- payload; worker self-report is not provenance and cannot replace those values.
88
+ At implementation time, the root passes the recorded named maximum through
89
+ invocation-only `--ceiling-tier`, resolves one exact candidate per phase, and
90
+ dispatches one phase implementer. Codex first attempts the resolver-returned
91
+ materialized role as the native `agent_type`. The launcher records the target,
92
+ model axis, and effort axis from that resolved payload; child self-report is not
93
+ provenance and cannot replace those values.
94
94
  Only an explicit pre-start native role-selection rejection permits a fresh
95
95
  pinned-child fallback. An accepted child, including one that later returns
96
96
  `BLOCKED` or lacks telemetry, is a task outcome rather than a fallback signal.
97
97
  Claude and Cursor bind the exact model arguments described above. A missing or
98
- unselectable managed target blocks rather than falling back to the coordinator
98
+ unselectable managed target blocks rather than falling back to the root target
99
99
  or a base role.
100
100
 
101
101
  ## Scope rules
@@ -48,8 +48,8 @@ Rules are currently project-scoped canonical content. Unlike skills and agents,
48
48
  - `oat init --scope project` (interactive) prompts for supported providers and persists explicit true/false values.
49
49
  - `oat sync --scope project` uses config-aware provider activation and can prompt to remediate detected mismatches.
50
50
  - Codex project-scope subagent sync writes `.codex/config.toml` and `.codex/agents/*.toml` at command layer after path-mapping sync. Every generated project Codex variant and registration is repository-owned, version-controlled provider output. OAT provides no automatic ignore mechanism for this project output; collaborators review and commit it like other project configuration.
51
- - Managed Codex roles require an effective `agents.max_depth` of at least `2` for `root (0) → phase coordinator (1) → task worker (2)`. Sync and direct materialization apply that floor without lowering a higher target value. A project write may read a higher lower-precedence user value and preserves it in the project configuration; it writes only project `.codex/config.toml`. User scope writes only `~/.codex/config.toml` and does not read or change project configuration.
52
- - If a managed role has missing, invalid, or insufficient effective depth, `oat doctor` and managed implementation preflight report the topology and give a scope-specific repair: `oat sync --scope project` for project scope or `oat sync --scope user` for user scope. For a single role, use `oat providers codex materialize` with the same explicit scope.
51
+ - Default Codex execution requires `root (0) → phase implementer (1)`. Sync and direct materialization continue to apply an `agents.max_depth` floor of `2` as optional nested-work capability without lowering a higher target value. A project write may read a higher lower-precedence user value and preserves it in project configuration; it writes only project `.codex/config.toml`. User scope writes only `~/.codex/config.toml` and does not read or change project configuration.
52
+ - Missing depth or depth `1` does not block default phase execution. Invalid values or explicit values below `1` fail managed implementation preflight. `oat doctor` reports whether optional depth-two nesting is available and gives a scope-specific repair when the configured value is unusable.
53
53
  - Codex aggregate config drift is reported via sync/status extension metadata (`aggregateConfigHash`); it is not persisted as a separate manifest schema entry.
54
54
  - Codex user-config materialization writes user-owned implementer and reviewer roles under the user provider directory, `~/.codex`; it does not write those roles into the repository.
55
55
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: Dispatch Policy
3
- description: 'How OAT combines owned provider candidate ladders, project and phase named maximum ceilings, exact task dispatch, and provider-specific enforcement.'
3
+ description: 'How OAT combines provider candidate ladders, project and phase named ceilings, exact phase-agent dispatch, and provider-specific enforcement.'
4
4
  ---
5
5
 
6
6
  # Dispatch Policy
@@ -12,15 +12,15 @@ constraints:
12
12
  or repo-local config. Each named tier contains one or more exact candidates.
13
13
  - A **named ceiling** is a project or phase maximum such as `balanced` or
14
14
  `high`. It is not an enduring model-family or effort preference.
15
- - A **task target** is one exact configured candidate selected at invocation
16
- time at or below the named maximum.
15
+ - A **phase target** is one exact configured candidate selected at invocation
16
+ time at or below the named maximum. Optional nested work resolves separately.
17
17
 
18
18
  The CLI command remains `oat project dispatch-ceiling resolve` for compatibility.
19
19
  Legacy `workflow.dispatchCeiling.*` and `oat_dispatch_ceiling` values remain
20
20
  readable, but new projects use ordered candidates plus `oat_dispatch_policy`.
21
21
 
22
22
  For raw config keys, see [Configuration](../../cli-utilities/configuration.md).
23
- For the coordinator and task-worker loop, see
23
+ For the root-owned phase-agent loop, see
24
24
  [Implementation Execution](implementation-execution.md).
25
25
 
26
26
  ## Named Policy Choices
@@ -36,8 +36,8 @@ For the coordinator and task-worker loop, see
36
36
 
37
37
  A named `High` ceiling therefore keeps configured Economy, Balanced, and High
38
38
  candidates eligible and available. It does not pin Sol, `opus`, one Cursor
39
- string, or one effort value. The task coordinator chooses the lowest exact
40
- candidate it judges sufficient for each bounded task.
39
+ string, or one effort value. The project root chooses one exact candidate it
40
+ judges sufficient for the phase.
41
41
 
42
42
  `Uncapped` is explicit managed state. It is not represented by omitted policy
43
43
  state. `Unresolved` is a planning or preflight deferral and cannot begin
@@ -179,7 +179,7 @@ The final candidate in a named tier defines that tier's reviewer ceiling. Lower
179
179
  reviewer selection requires a separate reviewed contract; a normal reviewer
180
180
  does not use task candidate flags.
181
181
 
182
- ## Exact Task Resolution
182
+ ## Exact Phase Resolution
183
183
 
184
184
  Planning and implementation preflight resolve the active policy first:
185
185
 
@@ -190,9 +190,9 @@ oat project dispatch-ceiling resolve \
190
190
  --json
191
191
  ```
192
192
 
193
- Before each managed capped implementation or fix task, the phase coordinator
194
- classifies the bounded task and requests one exact configured candidate. It
195
- passes the recorded project or narrower phase maximum through the
193
+ Before each managed capped phase or bounded fix continuation, the root requests
194
+ one exact configured candidate. It passes the recorded project or narrower
195
+ phase maximum through the
196
196
  invocation-only `--ceiling-tier` option:
197
197
 
198
198
  ```bash
@@ -237,23 +237,23 @@ Successful JSON reports:
237
237
 
238
238
  The resolver rejects a missing candidate, an above-ceiling candidate, an
239
239
  ambiguous route, malformed ordering, a reviewer candidate request, or controls
240
- that cannot compile exactly. The coordinator blocks instead of reusing its own
241
- target, a base role, or a provider default.
240
+ that cannot compile exactly. The root blocks instead of reusing its own target,
241
+ a base role, or a provider default.
242
242
 
243
243
  `--preferred` remains available for legacy scalar ceilings and managed
244
- `Uncapped` compatibility. It is not the exact managed task-worker selection
244
+ `Uncapped` compatibility. It is not the exact managed phase-agent selection
245
245
  path.
246
246
 
247
247
  ## Provider Enforcement
248
248
 
249
- | Provider | Exact task invocation | Failure behavior |
249
+ | Provider | Exact phase-agent or optional-child invocation | Failure behavior |
250
250
  | -------- | ---------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
251
251
  | Codex | Use `providers.codex.dispatchArgs.variant` as `agent_type`; otherwise launch a fresh child pinned to the returned model and effort | Block if neither exact route is usable |
252
252
  | Claude | Pass `providers.claude.dispatchArgs.model` as the actual Task `model` | Block if the model cannot be applied |
253
253
  | Cursor | Pass `providers.cursor.dispatchArgs.model` byte-for-byte as the actual invocation model; treat it as opaque | Block rather than normalize or substitute |
254
254
  | Other | Use a registered provider adapter when it can compile exact controls | Unsupported providers remain advisory |
255
255
 
256
- Materialized Codex roles exist before task dispatch after project/user sync.
256
+ Materialized Codex roles exist before phase dispatch after project/user sync.
257
257
  The supported catalogue is committed project output; custom Codex candidates
258
258
  materialize according to config ownership. Workflow correctness still keeps a
259
259
  fresh pinned-child fallback and does not require provider restart or hot reload.
@@ -290,20 +290,23 @@ and prompts, stdout and stderr, exit and duration data, and capture-environment
290
290
  details such as user-specific binary paths; it is not limited to the structured
291
291
  second-pass projection.
292
292
 
293
- ## Coordinator and Worker Layers
293
+ ## Phase and Optional-Worker Layers
294
294
 
295
- `oat-phase-implementer` has two explicit modes:
295
+ The phase implementer directly implements the phase tasks from one Phase Scope
296
+ and:
296
297
 
297
- 1. **Phase coordinator:** reads phase artifacts once, preserves dependency
298
- order, selects one exact candidate per task, waits for each worker, verifies
299
- its result and commit, then performs phase-wide integration review. It does
300
- not implement ordinary tasks itself.
301
- 2. **Task worker:** receives exactly one Task Scope with one task ID, file
302
- boundary, verification commands, commit convention, and exact dispatch
303
- payload. It implements and commits that task, then stops.
298
+ 1. reads phase artifacts once and preserves dependency order;
299
+ 2. directly implements each planned task;
300
+ 3. creates and verifies one bounded commit per task; and
301
+ 4. runs phase-wide verification before returning to the root.
304
302
 
305
- Workers run serially in the same worktree. Parallelism remains limited to
306
- plan-declared phase worktrees. See
303
+ Optional nested workers or recon agents resolve their own exact candidates only
304
+ when they provide a concrete benefit. They are not required for ordinary plan
305
+ tasks and do not own phase commits or review dispatch.
306
+
307
+ Tasks run serially in the same worktree. Parallelism remains limited to
308
+ plan-declared phase worktrees unless optional work has explicitly isolated
309
+ write authority. See
307
310
  [Implementation Execution](implementation-execution.md) for the full loop.
308
311
 
309
312
  ## Dispatch Report V1 and Producer Provenance
@@ -0,0 +1,123 @@
1
+ ---
2
+ title: Evidence Layers
3
+ description: 'The three-layer dispatch evidence model — policy resolution, launcher-owned configured invocation, and optional runtime-observed identity — used across dispatch records and smoke verification.'
4
+ ---
5
+
6
+ # Evidence Layers
7
+
8
+ OAT dispatch evidence is layered so that trust flows from what OAT can prove
9
+ toward what it can only observe. The launcher always knows which policy it
10
+ resolved and which exact route it configured and launched, so that evidence is
11
+ authoritative. A child's self-report of its own model is corroboration, not
12
+ ground truth — it may be missing, delayed, or untrusted without ever
13
+ invalidating the configured-invocation record.
14
+
15
+ The model has **three layers**. The first two are what OAT decided and did; the
16
+ third is what a runtime happened to say about itself. Assertions target the
17
+ first two layers. The third is recorded as `reported` or `not-reported` and
18
+ never gates a conclusion on its own.
19
+
20
+ ## Layer map
21
+
22
+ ```mermaid
23
+ flowchart TD
24
+ L1["Layer 1 — Policy resolution\nnamed ceiling · candidates · capped/uncapped mode"]
25
+ L2["Layer 2 — Launcher-owned configured invocation\nroute · target/model/effort axes · selection reason ·\ncandidates considered · launch acceptance"]
26
+ L3["Layer 3 — Runtime-observed identity (optional)\nproducer + model, only under trusted provenance"]
27
+
28
+ L1 --> L2 --> L3
29
+
30
+ A["Assertions"] -->|assert on| L1
31
+ A -->|assert on| L2
32
+ A -.->|record only| L3
33
+
34
+ L3 --> R["reported\n(both present + trusted provenance)"]
35
+ L3 --> NR["not-reported\n(anything else normalizes here)"]
36
+ ```
37
+
38
+ Assertions bind to Layers 1 and 2. Layer 3 is recorded as `reported` or
39
+ `not-reported`; its absence never invalidates Layer 2.
40
+
41
+ ## Layer 1 — Policy resolution
42
+
43
+ Layer 1 is the output of the dispatch-ceiling / policy resolver: the named
44
+ ceiling in effect, the eligible candidates under that ceiling, and whether the
45
+ policy is capped (a named maximum such as `balanced` or `high`), uncapped
46
+ (explicit managed state), or inherit/default. It answers _what was allowed_
47
+ before any single task chose a target.
48
+
49
+ This layer is a maximum and a candidate set, not a selection. A named `high`
50
+ ceiling keeps lower configured tiers eligible; it does not pin one family or
51
+ effort. See [Dispatch Policy](dispatch-ceiling.md) for named policy choices,
52
+ candidate ladders, and the resolver contract.
53
+
54
+ ## Layer 2 — Launcher-owned configured invocation
55
+
56
+ Layer 2 is the dispatch record the launcher writes when it selects and launches
57
+ a route. It is the **authoritative evidence of what was configured and
58
+ launched**, and it records:
59
+
60
+ - the selected route and the exact target, model axis, and effort axis;
61
+ - the `selection.reason`, drawn from the stable shared values `native-catalog`,
62
+ `native-catalog-unsatisfying`, `pre-start-rejection`, `inherit`, and
63
+ `gate-target` (adapters may add a more specific diagnostic but never replace
64
+ or rename these);
65
+ - the ordered `candidates_considered` before launch (never sorted);
66
+ - launch acceptance status (`accepted` or `pre-start-rejected`) and mechanism.
67
+
68
+ Because the launcher constructs the invocation payload itself, this layer does
69
+ not depend on any child cooperation. A launch is judged consistent only when its
70
+ candidate tier, selected model/effort axes, ceiling model/effort axes, policy,
71
+ and exact target all agree. The `atOrBelowCeiling` boolean the launcher provides
72
+ is retained as source evidence but is **not trusted** by assertions — they
73
+ recompute eligibility from the configured candidates and named ceiling instead.
74
+ This layer maps to Dispatch Report V1 and its provenance record; see the
75
+ [Dispatch Report V1 / producer provenance](dispatch-ceiling.md#dispatch-report-v1-and-producer-provenance)
76
+ section.
77
+
78
+ ## Layer 3 — Runtime-observed identity (optional corroboration)
79
+
80
+ Layer 3 is the only layer that reflects what a runtime said about itself, and it
81
+ is optional corroboration. It is normalized to `reported` **only** when both the
82
+ `producer` and `model` are present _and_ provenance is one of
83
+ `runtime-observed`, `provider-output`, or `gate-corroborated`. Anything else —
84
+ missing producer, missing model, or a non-trusted provenance value — normalizes
85
+ to `not-reported`.
86
+
87
+ Requested controls, configured defaults, role-name parsing, and reviewer
88
+ self-identification do not become observed runtime identity. Crucially, a
89
+ missing or `not-reported` runtime identity **never invalidates** the
90
+ launcher-owned configured-invocation evidence in Layer 2. Selected model and
91
+ effort axes stay exact even when runtime producer identity is not reported.
92
+
93
+ ## How the smoke runner consumes these layers
94
+
95
+ The smoke runner's evidence pipeline reads all three layers and asserts only on
96
+ the trustworthy ones. Launcher-owned records (`dispatch/<scope>-<attempt>.json`),
97
+ orchestration state-transition records, and gate JSON are written before
98
+ collection. The collector then flows the evidence through three stages:
99
+
100
+ 1. **Bundle** — collect the immutable dispatch, orchestration, and gate records
101
+ into a normalized evidence bundle, preserving structured candidates and
102
+ recomputing eligible candidates through the named ceiling. Runtime identity
103
+ is normalized here to `reported` / `not-reported`.
104
+ 2. **Assertion profiles** — apply the profiles that assert on Layers 1 and 2
105
+ (policy resolution and configured invocation), while recording Layer 3 as
106
+ corroboration only.
107
+ 3. **Report** — emit the evidence report from launcher-owned records and gate
108
+ artifacts, carrying `reported` / `not-reported` runtime status without
109
+ letting a missing Layer 3 fail a Layer 2 assertion.
110
+
111
+ For how to run this end to end and when to refresh the fixture, see
112
+ [Smoke testing](../../contributing/smoke-testing.md).
113
+
114
+ ## Related
115
+
116
+ - [Dispatch Policy](dispatch-ceiling.md) — Dispatch Report V1 and the
117
+ producer-provenance record that back Layers 1 and 2.
118
+ - [Orchestration Model](orchestration-model.md) — the dispatch topology that
119
+ produces these records.
120
+ - [Review Flavors](review-flavors.md) — how the four review flavors are recorded
121
+ through the same launcher-owned evidence.
122
+ - [Smoke testing](../../contributing/smoke-testing.md) — operating the evidence
123
+ pipeline against real providers.