okstra 0.121.1 → 0.123.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/README.md +4 -2
- package/docs/architecture/storage-model.md +14 -0
- package/docs/architecture.md +38 -8
- package/docs/cli.md +45 -5
- package/docs/for-ai/README.md +2 -2
- package/docs/for-ai/skills/okstra-rollup.md +1 -1
- package/docs/for-ai/skills/{okstra-schedule.md → okstra-schedule-gen.md} +3 -3
- package/docs/project-structure-overview.md +4 -3
- package/docs/task-process/implementation-planning.md +33 -9
- package/docs/task-process/implementation.md +21 -2
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/claude-worker.md +1 -1
- package/runtime/bin/lib/okstra/usage.sh +3 -3
- package/runtime/prompts/launch.template.md +9 -6
- package/runtime/prompts/lead/adapters/claude-code.md +104 -0
- package/runtime/prompts/lead/adapters/codex.md +45 -0
- package/runtime/prompts/lead/adapters/external.md +46 -0
- package/runtime/prompts/lead/context-loader.md +5 -5
- package/runtime/prompts/lead/convergence.md +11 -28
- package/runtime/prompts/lead/okstra-lead-contract.md +44 -94
- package/runtime/prompts/lead/plan-body-verification.md +50 -5
- package/runtime/prompts/lead/report-writer.md +59 -54
- package/runtime/prompts/lead/team-contract.md +33 -106
- package/runtime/prompts/profiles/_common-contract.md +3 -3
- package/runtime/prompts/profiles/_implementation-deliverable.md +3 -1
- package/runtime/prompts/profiles/_implementation-executor.md +6 -1
- package/runtime/prompts/profiles/_implementation-verifier.md +2 -2
- package/runtime/prompts/profiles/final-verification.md +2 -0
- package/runtime/prompts/profiles/implementation-planning.md +14 -4
- package/runtime/prompts/profiles/requirements-discovery.md +1 -1
- package/runtime/prompts/wizard/prompts.ko.json +44 -0
- package/runtime/python/okstra_ctl/codex_dispatch.py +23 -1
- package/runtime/python/okstra_ctl/design_prep.py +1462 -0
- package/runtime/python/okstra_ctl/design_surfaces.py +243 -0
- package/runtime/python/okstra_ctl/final_report_schema.py +33 -1
- package/runtime/python/okstra_ctl/implementation_stage.py +35 -0
- package/runtime/python/okstra_ctl/incremental_carry.py +294 -21
- package/runtime/python/okstra_ctl/incremental_scope.py +51 -5
- package/runtime/python/okstra_ctl/lead_runtime.py +4 -0
- package/runtime/python/okstra_ctl/material.py +1 -1
- package/runtime/python/okstra_ctl/model_discovery.py +98 -0
- package/runtime/python/okstra_ctl/models.py +8 -3
- package/runtime/python/okstra_ctl/render.py +81 -194
- package/runtime/python/okstra_ctl/report_views.py +22 -7
- package/runtime/python/okstra_ctl/run.py +53 -5
- package/runtime/python/okstra_ctl/team_reconcile.py +3 -1
- package/runtime/python/okstra_ctl/user_response.py +67 -2
- package/runtime/python/okstra_ctl/wizard.py +283 -3
- package/runtime/python/okstra_token_usage/report.py +11 -0
- package/runtime/schemas/final-report-v1.0.schema.json +339 -0
- package/runtime/skills/okstra-inspect/SKILL.md +2 -2
- package/runtime/skills/okstra-rollup/SKILL.md +1 -1
- package/runtime/skills/{okstra-schedule → okstra-schedule-gen}/SKILL.md +62 -20
- package/runtime/skills/okstra-user-response/SKILL.md +8 -6
- package/runtime/templates/reports/final-report.template.md +71 -4
- package/runtime/templates/reports/i18n/en.json +32 -1
- package/runtime/templates/reports/i18n/ko.json +32 -1
- package/runtime/validators/validate-run.py +515 -5
- package/runtime/validators/validate-schedule.py +11 -7
- package/runtime/validators/validate_session_conformance.py +58 -33
- package/src/cli-registry.mjs +14 -0
- package/src/commands/inspect/design-prep.mjs +23 -0
- package/src/commands/inspect/stage-map.mjs +100 -0
- package/src/commands/lifecycle/install.mjs +3 -0
- package/src/commands/lifecycle/uninstall.mjs +8 -23
- package/src/lib/skill-catalog.mjs +10 -1
|
@@ -2,15 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
## File-author ownership (BLOCKING)
|
|
4
4
|
|
|
5
|
-
The final-report
|
|
5
|
+
The final-report data.json is authored by `Report writer worker` when that role is in the roster. The lead reviews both rendered artifacts but does not write them. Lead-authored fallback is legal only after a real `dispatch_worker` attempt records `error`, `timeout`, or `not-run` with a concrete reason. `release-handoff` remains the intentional single-lead exception.
|
|
6
|
+
|
|
7
|
+
The JSON SSOT path is `runs/<task-type>/reports/final-report-<task-type>-<seq>.data.json`. The user-facing markdown at `runs/<task-type>/reports/final-report-<task-type>-<seq>.md` is produced by `scripts/okstra-render-final-report.py` from the data.json so both files land on disk before the worker returns.
|
|
6
8
|
|
|
7
9
|
The data.json schema is `schemas/final-report-v1.0.schema.json`. The renderer + the run-validator both consume that schema, so a data.json that validates is guaranteed to render into a markdown that passes the contract checks.
|
|
8
10
|
|
|
9
11
|
Two `frontmatter` approval fields are always emitted with their unset default — never pre-fill them: `frontmatter.approved` is emitted as `false`, and `frontmatter.implementationOption` is emitted as an empty string `""`. The user later flips `approved` to `true` (via `--approve` or manual edit) and fills `implementationOption` with the chosen Option Candidate name (via `--implementation-option <name>` or manual edit) to authorise and scope the next `implementation` run.
|
|
10
12
|
|
|
11
|
-
If you are reading this contract **as the report-writer
|
|
13
|
+
If you are reading this contract **as the report-writer worker**, YOU are the one writing the data.json and invoking the renderer through the available execution interface. Do not return either artifact inline — the files on disk are the canonical record.
|
|
12
14
|
|
|
13
|
-
If you are reading this contract **as
|
|
15
|
+
If you are reading this contract **as the lead**, your job in Phase 6 is to prepare the report-writer prompt, dispatch the Report writer worker per the Phase 6 dispatch template in okstra-lead-contract.md, and review both files in Phase 7. Do not call `write_artifact` against either report path yourself when Report writer worker is in the roster.
|
|
14
16
|
|
|
15
17
|
## When to Use
|
|
16
18
|
|
|
@@ -20,21 +22,13 @@ If you are reading this contract **as Claude lead**, your job in Phase 6 is to (
|
|
|
20
22
|
|
|
21
23
|
## Phase 6 dispatch template (Report writer worker)
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
prompt: "<report-writer prompt: see this contract + Required reading clause + Available MCP Servers section>",
|
|
29
|
-
name: "report-writer",
|
|
30
|
-
subagent_type: "report-writer-worker",
|
|
31
|
-
run_in_background: true, # no team_name — implicit team; see team-contract Operating Rule 0
|
|
32
|
-
model: "<family token of Report writer worker's modelExecutionValue>", # opus/sonnet/haiku — NOT hardcoded; see below
|
|
33
|
-
mode: "auto"
|
|
34
|
-
)
|
|
35
|
-
```
|
|
25
|
+
1. Resolve the Report writer worker assignment and all required prompt/result/error paths from the manifests.
|
|
26
|
+
2. Persist the exact prompt history with the required anchor headers and audience-specific reading list.
|
|
27
|
+
3. Emit the Phase 6 checkpoint.
|
|
28
|
+
4. Call `dispatch_worker(report_writer_assignment, prompt)` through the selected adapter.
|
|
29
|
+
5. Call `await_workers([handle])` and verify both the data.json Result Path and worker-results audit path.
|
|
36
30
|
|
|
37
|
-
The
|
|
31
|
+
The assignment's `modelExecutionValue` feeds both adapter dispatch and the prompt header in item 7 below, so the execution model and recorded `**Model:**` header always agree. Missing or unsupported model resolution is a pre-dispatch contract failure; the common contract does not choose a runtime fallback.
|
|
38
32
|
|
|
39
33
|
The prompt MUST include, in this order at the top:
|
|
40
34
|
|
|
@@ -57,37 +51,35 @@ The prompt MUST include, in this order at the top:
|
|
|
57
51
|
has been resolved by the lead from project.json / global config
|
|
58
52
|
before the dispatch is constructed. The worker copies this verbatim
|
|
59
53
|
into `data.json.meta.reportLanguage`.
|
|
60
|
-
12. For implementation-planning runs: a literal block listing the
|
|
61
|
-
13. An explicit instruction: `You are the author of TWO files: (a) the final-report data.json at <Result Path>, (b) the worker-results audit file at <Worker Result Path>. After writing the data.json, invoke "okstra render-final-report <Result Path>"
|
|
54
|
+
12. For implementation-planning runs: a literal block listing the 10 required English section headings (`Option Candidates`, `Trade-off`, `Recommended Option`, `Stepwise Execution Order`, `Dependency`, `Validation Checklist`, `Rollback`, `User Approval Request`, `Plan Body Verification`, `Implementation Design Preparation`). The writer uses these exact substrings as section headings (Korean translation in parentheses is allowed), and the `Plan Body Verification` section carries its required `Gate result:` line.
|
|
55
|
+
13. An explicit instruction: `You are the author of TWO files: (a) the final-report data.json at <Result Path>, (b) the worker-results audit file at <Worker Result Path>. After writing the data.json, invoke "okstra render-final-report <Result Path>" through the available execution interface so the markdown sibling is rendered before you return. Do not return the report inline. The validator fails the run when (a)'s schema validation fails, when the rendered markdown is absent, or when (b) is missing.`
|
|
62
56
|
|
|
63
|
-
**Completion detection after dispatch (BLOCKING).**
|
|
57
|
+
**Completion detection after dispatch (BLOCKING).** A dispatch acknowledgement is NOT completion — detect completion via the SSOT protocol in [team-contract](./team-contract.md) "Worker-completion detection", with a one-entry pending set covering the data.json (Result Path) and the worker-results file (Worker Result Path). Do NOT end the turn with a prose "waiting for the report" statement.
|
|
64
58
|
|
|
65
59
|
### Resume-safe dispatch
|
|
66
60
|
|
|
67
|
-
A resumed lead
|
|
68
|
-
|
|
69
|
-
- Dispatch with `Agent(name: "report-writer", run_in_background: true)`; the worker's session is recoverable by `agentName: "report-writer"` in `okstra-token-usage.py`.
|
|
70
|
-
- Do NOT skip dispatch because of any team-related concern. Record `teamCreate` in team-state and proceed.
|
|
61
|
+
A resumed lead can always call `redispatch_worker` for a fresh Report writer worker. Resume/session mechanics are adapter-owned and are never a reason to bypass the role.
|
|
71
62
|
|
|
72
63
|
### Lead-authored fallback (only if dispatch failed)
|
|
73
64
|
|
|
74
65
|
Except for `release-handoff` (which is single-lead by design and never dispatches a Report writer worker — see "Release-handoff section contract" below), lead-authored fallback is permitted only if all of the following are true and recorded in team-state:
|
|
75
66
|
|
|
76
|
-
1. A Report writer worker dispatch was actually attempted
|
|
67
|
+
1. A Report writer worker dispatch was actually attempted through `dispatch_worker`.
|
|
77
68
|
2. The attempt recorded a terminal status of `error`, `timeout`, or `not-run` with a concrete reason (tool error message, timeout duration, or external blocker).
|
|
78
69
|
3. The reason is logged via `okstra error-log append-observed --error-type cli-failure ...` (or `tool-failure` if the failure was internal).
|
|
79
70
|
|
|
80
|
-
Speculative reasons such as "session resume constraint", "
|
|
81
|
-
|
|
82
|
-
For `tmux-pane` backend runs, do not use the Agent template. Create a one-job jobs file for the `report-writer` with `dispatchKind: "report-writer"` and the same field set as reverify jobs files ([convergence](./convergence.md) "Re-verification Agent Dispatch", tmux-pane branch — the single source for the jobs-file fields). Then call `okstra team dispatch --project-root <dir> --run-manifest <path> --jobs-file <jobs-file>` followed by `okstra team await --project-root <dir> --run-manifest <path>`. Completion requires both the report data.json and the report-writer worker-results audit file.
|
|
71
|
+
Speculative reasons such as "session resume constraint", "runtime state is unavailable", or "lead can do it faster" are NOT valid.
|
|
83
72
|
|
|
84
73
|
|
|
85
74
|
## Phase 6 → Phase 7 execution sequence (BLOCKING order)
|
|
86
75
|
|
|
87
|
-
|
|
76
|
+
Phase 6 first produces the final-report data.json at `runs/<task-type>/reports/final-report-<task-type>-<seq>.data.json` and its rendered markdown sibling. Token Usage cells are `null` at this point, and Section 3 does not yet include auto-spawned follow-ups.
|
|
88
77
|
|
|
89
|
-
|
|
90
|
-
|
|
78
|
+
For an implementation-planning run, the Report writer worker owns the Phase 6 design assessment snapshot: it writes `designPreparation` and every stage's `designSurfaceCoverage` into data.json from the detector output and consolidated plan. It does not create user inputs, consume a user answer as if it were part of that snapshot, or materialize `design-prep-requests/`; `schemas/final-report-v1.0.schema.json` and `validators/validate-run.py` `_validate_design_prep_contract` enforce the snapshot shape, detector coverage, and references.
|
|
79
|
+
|
|
80
|
+
The four Phase 7 steps below MUST execute in this exact order. Reordering them is the recurring root cause of reports shipping with `--` token cells, Section 3 missing follow-up entries, or Section 4 rows never spawning.
|
|
81
|
+
|
|
82
|
+
1. **Collect usage.** Call `collect_usage` through the selected adapter with substitution enabled by the existing `okstra token-usage` workflow. One invocation aggregates `leadUsage` / `workers[].usage` / `usageSummary` into team-state, populates `tokenUsage` and the execution-status usage fields in data.json, and re-invokes the renderer so the markdown carries real numbers.
|
|
91
83
|
|
|
92
84
|
```bash
|
|
93
85
|
okstra token-usage \
|
|
@@ -97,7 +89,9 @@ The four steps below MUST execute in this exact order. Reordering them is the re
|
|
|
97
89
|
```
|
|
98
90
|
|
|
99
91
|
The data.json paths populated: `tokenUsage.lead.{totalTokens,billableTokens,costUsd}`, the `worker` / `grand` rows, `tokenUsage.cli.costUsd`, and each `executionStatus[].{totalTokens,billableTokens,costUsd,durationMs,cliTotalTokens,cliCostUsd}` for rows whose role matches a team-state worker. The data.json MUST already exist (Phase 6 output).
|
|
100
|
-
|
|
92
|
+
|
|
93
|
+
For implementation-planning, this Phase 7 canonical render calls `materialize_design_prep_requests()` after token substitution and creates deterministic request files only for `provisional` / `blocked` items. Later answers are append-only user-input sidecars; request generation and user input never rewrite the assessment fields, so the source report remains immutable as the design-input snapshot after this render. `validators/validate-run.py` `_validate_design_prep_requests` enforces request existence, canonical path, content, and assessment fingerprint.
|
|
94
|
+
2. **Validate and render the report artifacts.** Always invoke the report-view renderer after the substituted data.json passes its schema/run checks; the renderer decides whether an html sibling is warranted:
|
|
101
95
|
|
|
102
96
|
```bash
|
|
103
97
|
okstra render-views \
|
|
@@ -109,8 +103,8 @@ The four steps below MUST execute in this exact order. Reordering them is the re
|
|
|
109
103
|
- implementation-planning 보고서에는 본문 끝에 **Plan Approval** 섹션(구현 옵션 `<select>` + 승인 체크박스)이 렌더된다 — §1 `Blocks: approval` 행이 미해소면 disabled. 승인을 체크하고 Export 하면 sidecar 본문에 `## APPROVAL` 블록이 실리고, implementation 시작 마법사의 approve-confirm 단계가 그것을 감지해 사용자 확인 후 기존 `--approve` / `--implementation-option` 경로로 적용한다.
|
|
110
104
|
- When the report has **no** `C-*` clarification rows and is **not** a Plan Approval widget target, the html carries no interactive forms (it would only duplicate the MD), so the renderer prints `html: skipped (...)` and writes nothing. This is the expected state for such runs — `validators/validate-report-views.py` treats "no C-* rows + no approval target + no html" as a pass, not a missing artifact.
|
|
111
105
|
|
|
112
|
-
|
|
113
|
-
|
|
106
|
+
This step runs after usage collection so token placeholders are substituted in any rendered html and before routing persistence so the html artifact, when generated, exists for the validator step that checks it.
|
|
107
|
+
3. **Complete routing and follow-up persistence.** Run the follow-up task spawner when Section 4 is non-empty. It turns the report's `## 4. Follow-up Tasks (후속 작업)` rows into `tasks/<task-group>/<new-task-id>/` stubs.
|
|
114
108
|
|
|
115
109
|
```bash
|
|
116
110
|
okstra spawn-followups \
|
|
@@ -126,15 +120,14 @@ The four steps below MUST execute in this exact order. Reordering them is the re
|
|
|
126
120
|
- Rows whose `origin` is `phase-continuation` are reported as `skipped (no new task dir)` and never spawn — they advance the same task-key via `/okstra-run` instead.
|
|
127
121
|
- An invalid `origin`, `suggestedTaskType`, missing `title`, missing `reason`, or missing `newTaskId` exits `1`. (Schema validation in Phase 6 catches most of these before the spawner runs.)
|
|
128
122
|
- **Canonical spawn rule (single source of truth):** the spawner runs when `task-type` ∈ {`implementation`, `final-verification`, `release-handoff`}, OR when `followUpTasks` is non-empty for any other task-type. For the listed task-types `followUpTasks` must be present (schema enforces the phase-continuation row for non-terminal task-types); an empty array is permitted only for `release-handoff`. Missing arrays are no-ops (exit `0`). All other references to this rule (including the Persistence Checklist) defer to this statement.
|
|
129
|
-
|
|
123
|
+
After the spawner, the report writer MUST append one row per newly spawned task-key with its entry command:
|
|
130
124
|
|
|
131
125
|
```
|
|
132
|
-
- Follow-up: `<task-group>/<new-task-id>` —
|
|
126
|
+
- Follow-up: `<task-group>/<new-task-id>` — in-session `/okstra-run task-key=<task-group>/<new-task-id> task-type=<suggested>` / standalone `scripts/okstra.sh --task-key <task-group>/<new-task-id> --task-type <suggested>`
|
|
133
127
|
```
|
|
134
128
|
|
|
135
|
-
The status file is written after
|
|
136
|
-
|
|
137
|
-
**Run-end teammate teardown follows this whole sequence.** Token-usage collection (step 1) reads the worker session jsonls, so the lead MUST NOT disband the team until every step above is done. Only then — after the combined pane/team disposition prompt and only when the user approves cleanup — does the lead dismiss the worker teammates via `SendMessage` shutdown_request per [okstra-lead-contract](./okstra-lead-contract.md) "Run-scoped pane & teammate lifecycle" → "Run-end teammate teardown" (split-pane runs only; silent-skip when split-pane is off; if the user keeps panes/teammates, leave them intact and surface the manual Teams/FleetView cleanup path).
|
|
129
|
+
The status file is written after routing and follow-up persistence completes.
|
|
130
|
+
4. **Execute the run-scoped cleanup gate.** Call `shutdown_workers` only after usage collection, all persistence work, and explicit user approval under [okstra-lead-contract](./okstra-lead-contract.md) "Run-scoped worker-resource lifecycle". If the user keeps resources, leave the selected adapter's resources intact and surface its manual cleanup guidance.
|
|
138
131
|
|
|
139
132
|
## Final Report Structure
|
|
140
133
|
|
|
@@ -142,13 +135,15 @@ The final report follows the structure encoded in `schemas/final-report-v1.0.sch
|
|
|
142
135
|
|
|
143
136
|
### Report Header
|
|
144
137
|
|
|
138
|
+
Milestone 1 keeps the final-report schema unchanged. Read the exact permitted values for `header.reportOwner` and `header.reportAuthor` from the task bundle's `instruction-set/final-report-schema.json` excerpt of `schemas/final-report-v1.0.schema.json`, then write those schema v1 compatibility values according to the actual authorship path. Do not derive either header field from the selected runtime's lead role. Runtime identity remains visible in the execution-status row and team-state audit fields.
|
|
139
|
+
|
|
145
140
|
```markdown
|
|
146
141
|
# <task-key> - Multi-Agent Cross Verification Final Report
|
|
147
142
|
- Date: <ISO 8601 timestamp>
|
|
148
143
|
- Task Key: <task-key>
|
|
149
144
|
- Task Type: <task-type>
|
|
150
|
-
- Report Owner:
|
|
151
|
-
- Report Author: `<
|
|
145
|
+
- Report Owner: `<exact schema header.reportOwner compatibility value>`
|
|
146
|
+
- Report Author: `<exact schema header.reportAuthor compatibility value for the actual authorship path>`
|
|
152
147
|
- Lead model: `<lead-model>`
|
|
153
148
|
- Preparation Method: Final report authored by Report writer worker (or lead-authored fallback — record the documented dispatch failure reason here when applicable)
|
|
154
149
|
```
|
|
@@ -158,22 +153,19 @@ The final report follows the structure encoded in `schemas/final-report-v1.0.sch
|
|
|
158
153
|
```markdown
|
|
159
154
|
| Agent | Role | Model | Status | 처리 토큰 | 환산 토큰 | 비용 (USD) | Duration | Summary of Key Findings |
|
|
160
155
|
|-------|------|-------|--------|-----------|-----------|------------|----------|------------------------|
|
|
161
|
-
|
|
|
162
|
-
|
|
|
163
|
-
| Codex | Codex worker | gpt-5.5 | completed | 2,274,011 (CLI: 5,261,833) | 586,223 | $8.79 (+ CLI $4.20) | 22m 06s | Key findings summary |
|
|
164
|
-
| Antigravity | Antigravity worker | auto | completed | 3,107,795 | 746,623 | $11.20 | 22m 06s | Key findings summary |
|
|
165
|
-
| Claude Code | Report writer | opus-4-6 | completed | 665,497 | 267,210 | $4.01 | 4m 20s | Report organization |
|
|
156
|
+
| <team-state.lead.agent> | <team-state.lead.role> | <model> | completed | <tokens> | <billable> | <cost> | <duration> | Final synthesis status |
|
|
157
|
+
| <team-state.workers[].agent> | <team-state.workers[].role> | <model> | <status> | <tokens> | <billable> | <cost> | <duration> | Key findings summary |
|
|
166
158
|
```
|
|
167
159
|
|
|
168
160
|
Table Generation Rules:
|
|
169
|
-
- The first row
|
|
170
|
-
-
|
|
161
|
+
- The first row derives its agent identifier and role from `team-state.lead.agent` / `team-state.lead.role` and its usage data from `leadUsage`; subsequent rows follow `recommendedWorkers` / `resultContract.requiredWorkerRoles` order.
|
|
162
|
+
- Every worker agent identifier and role derives from its persisted team-state entry; the common contract does not infer labels from provider names.
|
|
171
163
|
- **처리 토큰** = `usage.totalTokens` (input + output + cache_creation + cache_read; the raw volume processed).
|
|
172
164
|
- **환산 토큰** = `usage.billableEquivalentTokens` (cache reads weighted at 0.1×, cache_creation 1.25×, output 5×; useful as a single number for "how big was this session in cost terms").
|
|
173
165
|
- **비용 (USD)** = `usage.estimatedCostUsd`. For Codex/Antigravity workers that actually invoked the CLI, append `(+ CLI $X.XX)` from `usage.cliEstimatedCostUsd`.
|
|
174
166
|
- For Codex/Antigravity workers, append `(CLI: <cliTotalTokens>)` to the 처리 토큰 cell when `usage.cliTotalTokens` is set.
|
|
175
167
|
- Status values are retrieved from team-state; format duration as `Xm Ys` from `usage.durationMs`.
|
|
176
|
-
- Workers with status `not-run` or
|
|
168
|
+
- Workers with status `not-run` or unavailable usage evidence show `--` for tokens/cost/duration; quote the `note` underneath the table if useful.
|
|
177
169
|
|
|
178
170
|
### Token Usage Summary Section
|
|
179
171
|
|
|
@@ -206,12 +198,12 @@ Token Summary Generation Rules:
|
|
|
206
198
|
- **Grand total** (ko: `전체 합계`) row: `usageSummary.grandTotalTokens` / `usageSummary.grandBillableEquivalentTokens` / sum of `lead + claudeWorkers`.
|
|
207
199
|
- **Codex/Antigravity CLI add-on** (ko: `Codex/Antigravity CLI 추가 비용`) row: `usageSummary.estimatedCostUsd.cliWorkers`. If 0, still show the row so the reader sees that no CLI work was billed under those providers (or that CLI fallback occurred).
|
|
208
200
|
- Format tokens with comma separators (e.g., `32,500`); format USD with two decimals (e.g., `$1.43`).
|
|
209
|
-
- If `lead` or any `worker.usage`
|
|
201
|
+
- If `lead` or any `worker.usage` records unavailable evidence, show `--` for that row and append a one-line note (`reason: <note>`).
|
|
210
202
|
- If pricing for a model is unknown, the script omits `estimatedCostUsd` for that block — show `N/A` in that column and add a note like `pricing missing for model <model>`.
|
|
211
203
|
|
|
212
204
|
### Implementation-planning section heading contract (BLOCKING)
|
|
213
205
|
|
|
214
|
-
When the run's `task-type` is `implementation-planning`, the final report MUST contain section headings whose **lines include each of the
|
|
206
|
+
When the run's `task-type` is `implementation-planning`, the final report MUST contain section headings whose **lines include each of the 10 literal English substrings below**. The validator (`validators/validate-run.py`) does plain substring matching on the report text and validates the design-preparation data contract — missing headings was a real, repeatedly observed failure mode caused by translating the headings to Korean.
|
|
215
207
|
|
|
216
208
|
| # | Required substring | Recommended heading form |
|
|
217
209
|
|---|--------------------|--------------------------|
|
|
@@ -224,11 +216,24 @@ When the run's `task-type` is `implementation-planning`, the final report MUST c
|
|
|
224
216
|
| 7 | `Rollback` | `### Rollback Strategy (롤백 전략)` |
|
|
225
217
|
| 8 | `User Approval Request` | Satisfied by the top-of-report `## User Approval Request (사용자 승인 게이트)` block. Do NOT recreate a `### 5.5.8 User Approval Request` body stub — the validator now fails reports that contain one. |
|
|
226
218
|
| 9 | `Plan Body Verification` + `Gate result:` | `### Plan Body Verification (계획 본문 검증)` containing a `Gate result:` line — copy `templates/reports/final-report.template.md §5.5.9` verbatim. Validator checks both substrings. |
|
|
219
|
+
| 10 | `Implementation Design Preparation` | `### Implementation Design Preparation (구현 설계 준비)` — rendered from `implementationPlanning.designPreparation` by `templates/reports/final-report.template.md §5.5.10`. |
|
|
227
220
|
|
|
228
221
|
The Korean translation in parentheses is optional but the English keyword is mandatory. The body of each section is written in the Report Language per the writing rules below. For non-`implementation-planning` runs, omit this entire block — these headings are NOT validator-checked for other task-types.
|
|
229
222
|
|
|
230
223
|
The final-report template `templates/reports/final-report.template.md` Section 5.5 already encodes this contract — copy that block verbatim and fill in.
|
|
231
224
|
|
|
225
|
+
### Self-fix rewrite (plan-body self-fix 라운드)
|
|
226
|
+
|
|
227
|
+
lead 가 self-fix 라운드를 지시하면(대상 `P-*` 목록 + 각 결함 사유 전달), 지정된 planner-fixable 항목이 가리키는 **계획 섹션만** 교정한다 — 전체 draft 를 다시 쓰지 않는다:
|
|
228
|
+
|
|
229
|
+
- 경로 축약 → `<PROJECT_ROOT>` 기준 전체 상대경로로 교체(File Structure / Stepwise `files`).
|
|
230
|
+
- prose command → 작업 디렉터리·인자·task-type 이 포함된 실행 가능한 명령 시퀀스로 구체화.
|
|
231
|
+
- placeholder(`stage-<N>` 등) → 구체 파일명·재생성 계획으로 교체.
|
|
232
|
+
- requirement-coverage 매핑 오류 → 실재하는 option/stage/step 또는 XP 행으로 재매핑.
|
|
233
|
+
- missing/weak design-prep contract → kind-specific inline detail 또는 concrete `aiProposal` 을 가진 AI-prepared PREP item 으로 교정. 사용자·외부 권한 사실은 만들어내지 않고 `blocked` + request material 로 유지한다.
|
|
234
|
+
|
|
235
|
+
교정 후 해당 `planItems[].selfFixNote` 에 `self-fixed in round <N>: <무엇을 고쳤는지>` 를 남기고, `planBodyVerification.selfFixRoundApplied = true` 로 표시한다. `needs-user-input` 항목은 절대 교정 대상이 아니다 — 그대로 clarification 으로 승격된다.
|
|
236
|
+
|
|
232
237
|
### Final-verification verdict token contract (BLOCKING)
|
|
233
238
|
|
|
234
239
|
When the run's `task-type` is `final-verification`, the report's `## 7. Final Verdict` table MUST contain a `Verdict Token` row whose value is **exactly one of** the literal strings below. The `release-handoff` profile reads this row as its entry gate; any other value blocks the next phase.
|
|
@@ -247,13 +252,13 @@ The final-report template `templates/reports/final-report.template.md` Section 7
|
|
|
247
252
|
|
|
248
253
|
When the run's `task-type` is `release-handoff`, the final report MUST include Section `## 5.6 Release Handoff Deliverables` with all eight sub-sections (`5.6.1` Source Verification Report, `5.6.2` Feature Branch & Working-Tree State, `5.6.3` User Selections, `5.6.4` Executed Commands, `5.6.5` Commit List, `5.6.6` Merge Conflict Probe, `5.6.7` Pull Request Outcome, `5.6.8` Routing Recommendation). Every entry is dictated by the lead's recorded git/gh command log and the user's verbatim answers to the H1/H2/H3 menu prompts. H1 choices are `local checkout`, `push + PR`, or `skip`; release-handoff records existing implementation commits and MUST NOT create new commits. If the user picked `skip` (H1) or `cancel` (H3), keep 5.6.3 populated but leave 5.6.4–5.6.6 explicitly empty per the template's empty-state lines.
|
|
249
254
|
|
|
250
|
-
**Single-lead authorship (release-handoff only):** release-handoff has no worker roster
|
|
255
|
+
**Single-lead authorship (release-handoff only):** release-handoff has no worker roster. The lead authors the final-report file directly — there is no `Report writer worker` dispatch to perform in Phase 6, no resume-safe dispatch concern, and no mandatory worker-results file for a report-writer role. The rest of this contract's dispatch / resume / fallback machinery applies ONLY when `Report writer worker` is in the roster (i.e. every task-type other than `release-handoff`).
|
|
251
256
|
|
|
252
257
|
The final-report template `templates/reports/final-report.template.md` Section 5.6 already encodes this contract — copy that block verbatim and fill in. For non-`release-handoff` runs, omit Section 5.6 entirely.
|
|
253
258
|
|
|
254
259
|
### Mandatory worker-results file (BLOCKING)
|
|
255
260
|
|
|
256
|
-
You (the report-writer
|
|
261
|
+
You (the report-writer worker) MUST also write a worker-results audit file at the path the lead provides as `**Worker Result Path:**`, defaulting to:
|
|
257
262
|
|
|
258
263
|
```
|
|
259
264
|
runs/<task-type>/worker-results/report-writer-worker-<task-type>-<seq>.md
|
|
@@ -281,7 +286,7 @@ Every field MUST anchor its claim with at least one evidence reference — a `pa
|
|
|
281
286
|
|
|
282
287
|
**Reader-facing prose MUST NOT cite a bare brief/worker-internal ID that this report never surfaces** — `RC-*` (reporter confirmations, defined in the brief), `RF-*` / `F-*` (findings, defined in worker-results) have no anchor in the final report, so a reader hits an opaque token with nothing to click. Either expand it inline (`the confirmed version target 1.27.47→1.27.48`) or, for an audit trail, namespace it (`claude:F-005`). **Enforced:** `_validate_no_opaque_id_references` fails a bare `RC-*` / `RF-*` / non-namespaced `F-*` appearing in `verdictCard` / `finalVerdict` / `rationale` / `clarificationItems[].statement`. (The renderer anchors + links in-report IDs of any digit width, so a surfaced `RC-4`-style id does resolve.) Do NOT restate the Verdict Card or the §5.4 trade-off matrix verbatim — this section is the *why*, in connected prose, that those tables compress.
|
|
283
288
|
|
|
284
|
-
0. **Clarification Response Carried In** — render this `## 0.` heading ONLY when `{{CLARIFICATION_RESPONSE_RELATIVE_PATH}}` is non-empty. Walk every `C-*` row of the prior report's `## 1. Clarification Items` table, reconcile against new evidence, and record the outcome (`resolved` / `obsolete`) with citation before drafting the verdict. When no carry-in path was provided, OMIT the `## 0.` heading entirely — the validator fails an empty Section 0 stub.
|
|
289
|
+
0. **Clarification Response Carried In** — render this `## 0.` heading ONLY when `{{CLARIFICATION_RESPONSE_RELATIVE_PATH}}` is non-empty. Walk every `C-*` row of the prior report's `## 1. Clarification Items` table, reconcile against new evidence, and record the outcome (`resolved` / `obsolete`) with citation before drafting the verdict. When no carry-in path was provided, OMIT the `## 0.` heading entirely — the validator fails an empty Section 0 stub. The lead calls `okstra incremental-scope` exactly once, combining answered-clarification stage impacts (`--impacted`) and changed PREP IDs (`--prep-items`); selected-option, Stage Map, or recommended-approach changes pass both CSVs empty to force full mode. Record that single decision JSON verbatim into `implementationPlanning.incrementalDecision` (`mode`, `reverifyStages`, `carryStages`, `reason`); the renderer emits the `### 0.1 Incremental Re-Verification Scope` audit block from it, and the validator fails an `incremental`-mode run whose Section 0 omits that block. In `incremental` mode this run's `planItems` MUST carry every plan-item id from the re-verified stages forward with its updated verdict; if re-verification concludes a plan item should be REMOVED, that is a signal the answer's blast radius is not local — do not drop it here, tell the lead to abandon incremental and re-route to a FULL re-verification, because the carry merge only adds prior items and would resurrect the removed item's stale verdict. After authoring the current data.json, call `okstra incremental-carry`, passing the decision's `carryStages` CSV to `--carry-stages` and its `reverifyStages` CSV to `--reverify-stages`. A `CarryError` means the stage/PREP ownership contract is unsafe: discard the partial merged output and route the run through full re-verification; never publish a partially merged report.
|
|
285
290
|
1. **Cross Verification Results** — 4 categories (Full / Partial / Contested / Worker-Unique) when convergence is enabled, per `convergence`. Prepend the Round History sub-table (columns: `Round | inputQueueSize | resolvedCount | carriedForwardCount | dispatches | skippedWorkers`) plus a `round2SkippedReason: <value>` note, pulled verbatim from `convergence-<task-type>-<seq>.json`. Empty contested list renders as `- 합의 미달 항목 없음.`. Convergence-disabled runs use the legacy Consensus/Differences format and omit the round table.
|
|
286
291
|
2. **Final Verdict** — `Direction` ∈ `continue-investigation` / `begin-implementation` / `approve` / `reject` / `hold`. **Verdict Token** is `not-applicable` for every task-type except `final-verification` — see "Final-verification verdict token contract" below for that case.
|
|
287
292
|
3. **Evidence and Detailed Analysis** — primary evidence rows (file path, line, snippet); secondary evidence / alternate interpretations. If `reference-expectations.md` lists explicit expected values, record match/gap per row.
|
|
@@ -9,15 +9,15 @@
|
|
|
9
9
|
|
|
10
10
|
## Team Structure
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Okstra tasks use one lead plus the exact worker assignments selected in the prepared bundle. The lead runtime and the worker providers are independent axes.
|
|
13
13
|
|
|
14
14
|
### Role Definitions
|
|
15
15
|
|
|
16
16
|
**All analysis workers (Claude / Codex / Antigravity) share an identical core responsibility.** Specialization is additive — it lives in optional Section 6 of the worker output, NOT in differentiated core questions. This is intentional: cross-verification only converges if all three workers are answering the same questions against the same brief. Disjoint per-worker scopes produce union-of-perspectives, not triangulation.
|
|
17
17
|
|
|
18
|
-
| Role | Core responsibility | Specialization lens (Section 6 only) |
|
|
18
|
+
| Role | Core responsibility | Specialization lens (Section 6 only) | Assignment key | Notes |
|
|
19
19
|
|------|------|------|---------------|------|
|
|
20
|
-
|
|
|
20
|
+
| Lead | orchestration + convergence supervision + final-report review/approval | runtime-specific | -- | Does not author the final report when `Report writer worker` is rostered |
|
|
21
21
|
| Claude worker | Answer every brief question across feasibility, requirement interpretation, hidden assumptions, and alternatives — with file:line evidence | broad reasoning depth, hidden assumptions, execution-risk surfacing | claude-worker | `agents/workers/claude-worker.md` |
|
|
22
22
|
| Codex worker | Same core responsibility as Claude worker — identical questions, identical sections 1–5 | implementation realism, code-path implications, edge cases, technical trade-offs | codex-worker | generated from `agents/workers/_cli-wrapper-template.md` + `codex-worker.params.json` |
|
|
23
23
|
| Antigravity worker | Same core responsibility as Claude worker — identical questions, identical sections 1–5 | requirement interpretation, consistency, safety, alternative viewpoints | antigravity-worker | generated from `agents/workers/_cli-wrapper-template.md` + `antigravity-worker.params.json` |
|
|
@@ -31,9 +31,7 @@ okstra tasks are always operated using the `Claude lead` + required worker team
|
|
|
31
31
|
|
|
32
32
|
1. `resultContract.requiredWorkerRoles` in `task-manifest.json` (and the lead model metadata) is the canonical source. There is no role-level fallback — a missing assignment is a manifest defect, not a license to invent one.
|
|
33
33
|
2. If `modelExecutionValue` differs from `model`, use `modelExecutionValue` during execution.
|
|
34
|
-
3. **
|
|
35
|
-
4. **`modelExecutionValue` → Agent `model:` family token.** The Agent tool's `model` parameter accepts family tokens only — `fable` / `opus` / `sonnet` / `haiku` (an exact version such as `claude-opus-4-7` is NOT a valid value). Map by prefix: a `modelExecutionValue` of `fable*` / `claude-fable*` → `"fable"`, `opus*` / `claude-opus*` → `"opus"`, `sonnet*` / `claude-sonnet*` → `"sonnet"`, `haiku*` / `claude-haiku*` → `"haiku"`. This enforces the assignment at **family granularity** (fable vs opus vs sonnet vs haiku); the exact version within a family is still inherited from the lead session and cannot be pinned via this parameter.
|
|
36
|
-
5. **Codex / Antigravity wrappers are out of scope for the Agent `model:` rule.** `Codex worker` / `Antigravity worker` subagents are Claude wrappers that shell out to an external CLI; the role's `modelExecutionValue` is already applied via the CLI's own `--model <modelExecutionValue>` argument (see `agents/workers/_cli-wrapper-template.md`). The Agent `model:` parameter for these wrappers would only set the wrapper's own orchestration model, not the external CLI's model — leave it at `inherit` and do NOT map it from `modelExecutionValue`.
|
|
34
|
+
3. **Dispatch-time enforcement (BLOCKING).** The selected adapter receives each role's `modelExecutionValue` and must apply its documented native mapping. The adapter must fail before dispatch if it cannot apply the exact assignment; it must not inherit the lead model, change provider, or choose a nearby alias silently.
|
|
37
35
|
|
|
38
36
|
### Dynamic Worker Role Determination
|
|
39
37
|
|
|
@@ -48,10 +46,10 @@ Only workers selected from `recommendedWorkers` in `task-manifest.json` and `res
|
|
|
48
46
|
|
|
49
47
|
## Operating Rules
|
|
50
48
|
|
|
51
|
-
0. **
|
|
52
|
-
1.
|
|
49
|
+
0. **Adapter-owned dispatch (BLOCKING).** Every worker start, await, retry, and shutdown goes through the selected runtime adapter. Core state records the outcome but never guesses a host primitive.
|
|
50
|
+
1. The lead is responsible for orchestration, convergence supervision, and final-report review/approval. It never overrides worker analysis and never bypasses a rostered Report writer worker.
|
|
53
51
|
2. `Report writer worker` is NOT an analysis worker. It is excluded from Phase 4/5 (initial analysis) and Phase 5.5 (convergence re-verification). It is spawned only in Phase 6 and is the **author** of the final-report file at `runs/<task-type>/reports/final-report-<task-type>-<seq>.md`.
|
|
54
|
-
3. When `Report writer worker` is in the roster, Lead MUST dispatch it in Phase 6. The only legal lead-authored fallback is when a dispatch was attempted and recorded a terminal status of `error` / `timeout` / `not-run` with a concrete logged reason. Speculative reasons such as "session resume constraint" or "team is no longer alive" are NOT valid —
|
|
52
|
+
3. When `Report writer worker` is in the roster, Lead MUST dispatch it in Phase 6. The only legal lead-authored fallback is when a dispatch was attempted and recorded a terminal status of `error` / `timeout` / `not-run` with a concrete logged reason. Speculative reasons such as "session resume constraint" or "team is no longer alive" are NOT valid — `dispatch_worker` can start a fresh one-shot assignment through the selected adapter.
|
|
55
53
|
4. The assigned model for each role is maintained based on `resultContract.requiredWorkerRoles` in task-manifest.json and the lead model metadata.
|
|
56
54
|
5. Required roles must not be replaced by unnamed generic parallel workers.
|
|
57
55
|
6. Before dispatching any required worker, persist the exact worker prompt to the assigned current-run prompt history path under `runs/<task-type>/prompts/`.
|
|
@@ -101,8 +99,6 @@ Audience-scoped file enumeration (performance optimization — mandatory):
|
|
|
101
99
|
| Report writer worker (Phase 6) | task-brief, analysis-profile, analysis-material, reference-expectations, clarification-response (if carry-in), **plus** the instruction-set-local `final-report-template.md` (phase-stripped) and `final-report-schema.json` (per-task-type excerpt) — NOT the full `templates/reports/...` / `schemas/...` sources |
|
|
102
100
|
| Reverify dispatches | none — the lead provides only the items to reverify |
|
|
103
101
|
|
|
104
|
-
Asymmetry note: `claude-worker` runs in-process and the Agent SDK auto-loads its agent definition; lead's dispatch prompt body for claude-worker can therefore be shorter than for codex/antigravity. The Worker Preamble pointer is still emitted for all three so the contract source is identical regardless of dispatch path.
|
|
105
|
-
|
|
106
102
|
## Terminal Statuses
|
|
107
103
|
|
|
108
104
|
Terminal statuses that can be recorded for a worker:
|
|
@@ -114,58 +110,13 @@ Terminal statuses that can be recorded for a worker:
|
|
|
114
110
|
| `error` | Execution error, reason recorded; prompt history file must exist |
|
|
115
111
|
| `not-run` | Not executed, reason recorded |
|
|
116
112
|
|
|
117
|
-
## Worker-completion detection
|
|
118
|
-
|
|
119
|
-
**SSOT.** This section is the single source of truth for how Lead detects worker completion across all phases and all worker kinds (Claude teammate, Codex / Antigravity wrappers). Other documents (`prompts/lead/okstra-lead-contract.md`, `report-writer`, `convergence`) reference this section by name; they MUST NOT restate the algorithm.
|
|
120
|
-
|
|
121
|
-
Lead dispatches workers asynchronously: an `Agent` call with `run_in_background: true` returns `Spawned successfully` **immediately** — that ack is NOT a completion. Lead MUST NOT treat the spawn ack as completion, and MUST NOT end its turn with a prose "waiting for ..." statement (that path stalls the run — the Agent Teams idle-notification is experimental and can be dropped, leaving Lead parked until the user manually nudges it). Instead:
|
|
122
|
-
|
|
123
|
-
For `tmux-pane` backend runs, Lead MUST use exactly one background wait command instead of raw result-file polling:
|
|
124
|
-
|
|
125
|
-
```bash
|
|
126
|
-
okstra team await --project-root <dir> --run-manifest <path>
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
This command checks both result files and wrapper status sidecars. Raw result-file-only polling is forbidden for `tmux-pane` because pane creation and file presence alone are not terminal worker completion.
|
|
130
|
-
|
|
131
|
-
For the Claude Code `team` backend, use the self-scheduled polling protocol below.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
1. Record the dispatched workers' Result Paths as the **pending set** (resolved to absolute from each launch prompt's `**Result Path:**` anchor header against `**Project Root:**`; the same paths recorded in run-manifest / team-state).
|
|
136
|
-
2. Arm a SINGLE self-wakeup: one `Bash(run_in_background: true)` poll covering ALL dispatched workers (not one background task per worker):
|
|
137
|
-
|
|
138
|
-
```bash
|
|
139
|
-
deadline=$((SECONDS + <per-worker-deadline-seconds>))
|
|
140
|
-
until [ -f "<result_A>" ] && [ -f "<result_B>" ]; do
|
|
141
|
-
[ $SECONDS -ge $deadline ] && { echo "POLL_TIMEOUT"; exit 1; }
|
|
142
|
-
sleep 5
|
|
143
|
-
done
|
|
144
|
-
echo "ALL_WORKERS_DONE"
|
|
145
|
-
```
|
|
113
|
+
## Worker-completion detection
|
|
146
114
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
- the poll exited `POLL_TIMEOUT` for a worker past its deadline → record terminal status `timeout` for that worker, remove it from the pending set, then redispatch-once (per "Lead Redispatch Policy on Result-Missing" below) or proceed.
|
|
153
|
-
- any error / abort path → no zombie schedule exists, because the background task is self-terminating.
|
|
154
|
-
6. **Per-worker soft timeout.** Use 2× the task-type expected per-worker duration in the table below as `<per-worker-deadline-seconds>`. The background poll's `deadline` IS the lead-side worker soft-timeout safety net.
|
|
155
|
-
|
|
156
|
-
| Task type | Expected per-worker | Deadline (2×) |
|
|
157
|
-
|---|---|---|
|
|
158
|
-
| requirements-discovery | 10 min | 20 min |
|
|
159
|
-
| error-analysis | 15 min | 30 min |
|
|
160
|
-
| implementation-planning | 20 min | 40 min |
|
|
161
|
-
| implementation | 20 min | 40 min |
|
|
162
|
-
| final-verification | 10 min | 20 min |
|
|
163
|
-
|
|
164
|
-
Relationship to the Codex / Antigravity wrapper polling contract: that contract (in the errors-sidecar section below) governs how a *wrapper subagent* waits on its own external CLI via `BashOutput`. This section governs how *Lead* waits on the worker subagents themselves. The two compose — Lead's background poll watches the result files; each wrapper independently watches its CLI — and neither imposes a timeout on the other (see "No external timeout on wrapper subagents").
|
|
165
|
-
|
|
166
|
-
### Claude-worker heartbeat staleness (lead-side liveness check)
|
|
167
|
-
|
|
168
|
-
The claude-worker appends a `- PROGRESS: <stage> <ISO-UTC>` line to its audit sidecar (`runs/<task-type>/worker-results/claude-worker-audit-<task-type>-<seq>.md`) at least every 5 minutes (`agents/workers/claude-worker.md` "Heartbeat"). While the result file is still pending, if that sidecar is absent or its mtime is >5 minutes stale, treat the dispatch as `timeout` and redispatch once with a byte-identical prompt (one-retry budget shared with "Lead Redispatch Policy on Result-Missing" below); after a second silent hang, record terminal status `timeout` with the missing-sidecar reason in team-state. The heartbeat is an auxiliary liveness signal layered on top of the completion protocol above — the authoritative completion signal remains the result file — and a missing sidecar after the result file appears is itself a contract violation per the heartbeat rule.
|
|
115
|
+
1. Build the pending set from the manifest-assigned completion paths.
|
|
116
|
+
2. Call `await_workers(handles)` through the selected adapter.
|
|
117
|
+
3. On every wake/return, read terminal dispatch records and verify every required completion path.
|
|
118
|
+
4. A process exit, spawn acknowledgement, pane creation, or Result Path alone is insufficient when the backend contract requires additional status/audit artifacts.
|
|
119
|
+
5. Apply the single shared retry budget through `redispatch_worker`; after the second failure, record the terminal status and proceed with reduced confidence.
|
|
169
120
|
|
|
170
121
|
## Lead Redispatch Policy on Result-Missing
|
|
171
122
|
|
|
@@ -179,12 +130,12 @@ After each worker subagent returns (regardless of role), Lead MUST verify the ca
|
|
|
179
130
|
|
|
180
131
|
**One-retry policy:**
|
|
181
132
|
|
|
182
|
-
1. On the FIRST result-missing trigger for a given role within a single run, Lead MUST
|
|
133
|
+
1. On the FIRST result-missing trigger for a given role within a single run, Lead MUST call `redispatch_worker` with the byte-identical prompt — same `**Result Path:**`, same `**Prompt History Path:**`, same model assignment, and same adapter-native assignment identity. The redispatch counts as a second attempt against the existing role slot; do NOT create a new role-id, do NOT change the result file path, do NOT switch to a different model as a "workaround".
|
|
183
134
|
2. If the SECOND attempt also fails the same check, Lead records the role's terminal status as `error` with `--message "result-missing after 1 retry"` and proceeds to Phase 5.5 / Phase 6 with the remaining workers' results. Lead MUST NOT retry a third time — convergence and the report writer are designed to operate on reduced-confidence single-or-two-analyser mode when one role is absent (`prompts/lead/okstra-lead-contract.md` "If only one worker result is usable: reduced-confidence synthesis").
|
|
184
135
|
3. The retry counter is **per-run, per-role** and is NOT preserved across runs. A subsequent okstra run for the same task-key starts each role's counter fresh.
|
|
185
136
|
4. Convergence reverify rounds (Phase 5.5) inherit the same one-retry budget — a reverify dispatch that triggers result-missing may be re-dispatched once.
|
|
186
137
|
|
|
187
|
-
**Logging.** Lead records the first attempt's `cli-failure` (already emitted by the wrapper sub-agent) as-is. The retry, on success, is logged via the normal worker-completion path; on failure (second `*_RESULT_MISSING`), Lead records a single `contract-violation` entry with `--message "result-missing after 1 retry"` referencing both
|
|
138
|
+
**Logging.** Lead records the first attempt's `cli-failure` (already emitted by the wrapper sub-agent) as-is. The retry, on success, is logged via the normal worker-completion path; on failure (second `*_RESULT_MISSING`), Lead records a single `contract-violation` entry with `--message "result-missing after 1 retry"` referencing both adapter dispatch-attempt ids and prompt-history paths.
|
|
188
139
|
|
|
189
140
|
**Diagnostic sidecar (advisory).** Both codex/antigravity wrappers also write a heartbeat sidecar at `<prompt-path>.status.json` recording `started_ts`, `ended_ts`, `exit_code`, `duration_ms`, and the canonical `log_path` (see `scripts/okstra-wrapper-status.py` for the schema). Lead MAY read this sidecar when deciding whether the first attempt actually launched the CLI (stage=`exited`, `exit_code=0`, non-zero `duration_ms`) versus failed before reaching it (sidecar absent, or stage=`started` with no exit fields). The sidecar is best-effort — its absence is NOT by itself a reason to skip the retry; the canonical trigger remains the missing result file.
|
|
190
141
|
|
|
@@ -310,7 +261,7 @@ Schema:
|
|
|
310
261
|
```
|
|
311
262
|
|
|
312
263
|
Workers MUST omit `source` / `recordedAt` / `agent` / `agentRole` / `model` /
|
|
313
|
-
`taskKey`.
|
|
264
|
+
`taskKey`. The lead fills those in when dumping the sidecar to the
|
|
314
265
|
run-level errors log (`runs/<task-type>/logs/errors-<task-type>-<seq>.jsonl`)
|
|
315
266
|
via `okstra error-log append-from-worker`.
|
|
316
267
|
|
|
@@ -326,13 +277,13 @@ omits either header, the worker MUST return `<WORKER>_ERRORS_PATH_MISSING`
|
|
|
326
277
|
without proceeding.
|
|
327
278
|
|
|
328
279
|
- `cli-failure` events are recorded by the wrapper subagent itself (Codex / Antigravity), but **directly to the run-level error log** via `okstra error-log append-observed --error-type cli-failure ...` — NOT via the sidecar. The sidecar is an in-process tool-failure channel only.
|
|
329
|
-
- **Wrapper invocation arity.** Both `okstra-codex-exec.sh` and `okstra-antigravity-exec.sh` accept four required positional arguments plus an optional fifth `<role>`: `<project-root> <model> <prompt-path> <worktree-path> [<role>]`. The fourth (worktree) argument is **mandatory for implementation phase** and optional otherwise. For codex it becomes `--add-dir <worktree>` (sandbox write access); for antigravity it is appended to `--include-directories`. Omitting it during implementation causes the codex sandbox to reject every Edit/Write targeting the worktree with EPERM. Workers extract the path from the `**Worktree:**` / `EXECUTOR_WORKTREE_PATH` / `cwd for every mutating command:` line in the lead prompt. The optional fifth `<role>` is folded into both the caller (worker) pane title `<cli>-<role>-<pid>` and the sibling trace-pane title `<cli>-<role>-<pid>-tail` (e.g. `codex-executor-93421` ↔ `codex-executor-93421-tail`). `<pid>` is the wrapper's own PID and disambiguates concurrent dispatches of the same role. The
|
|
330
|
-
- **Background dispatch + polling contract (Codex / Antigravity wrappers).** Both wrapper subagents MUST
|
|
331
|
-
- Successful completion: return the wrapper's accumulated stdout from the
|
|
332
|
-
- Non-zero `exit_code
|
|
333
|
-
- Polling cap reached:
|
|
334
|
-
-
|
|
335
|
-
- **No external timeout on wrapper subagents.** The codex/antigravity wrapper subagent's polling loop (with optional mtime grace) is the SINGLE timeout authority for its dispatch. Lead MUST NOT impose a separate `
|
|
280
|
+
- **Wrapper invocation arity.** Both `okstra-codex-exec.sh` and `okstra-antigravity-exec.sh` accept four required positional arguments plus an optional fifth `<role>`: `<project-root> <model> <prompt-path> <worktree-path> [<role>]`. The fourth (worktree) argument is **mandatory for implementation phase** and optional otherwise. For codex it becomes `--add-dir <worktree>` (sandbox write access); for antigravity it is appended to `--include-directories`. Omitting it during implementation causes the codex sandbox to reject every Edit/Write targeting the worktree with EPERM. Workers extract the path from the `**Worktree:**` / `EXECUTOR_WORKTREE_PATH` / `cwd for every mutating command:` line in the lead prompt. The optional fifth `<role>` is folded into both the caller (worker) pane title `<cli>-<role>-<pid>` and the sibling trace-pane title `<cli>-<role>-<pid>-tail` (e.g. `codex-executor-93421` ↔ `codex-executor-93421-tail`). `<pid>` is the wrapper's own PID and disambiguates concurrent dispatches of the same role. The selected adapter maps the functional assignment identity to this value; when the value is absent, pass the literal `worker` (the wrapper also defaults to `worker` if the argument is omitted).
|
|
281
|
+
- **Background dispatch + polling contract (Codex / Antigravity wrappers).** Both wrapper subagents MUST start their CLI through the selected adapter's asynchronous execution mapping and await the same handle until it reports terminal completion, capped at 30 minutes (1800s) of wall-clock elapsed time. The adapter's await operation is the wait primitive; do not add a standalone sleep or build shorter-sleep loops to bypass a host constraint. This rule applies in **every phase**. Recording responsibilities:
|
|
282
|
+
- Successful completion: return the wrapper's accumulated stdout from the terminal await result. No log entry.
|
|
283
|
+
- Non-zero `exit_code`: record a `cli-failure` to the run-level error log with the real `exit_code` and observed `duration-ms`.
|
|
284
|
+
- Polling cap reached: perform a one-shot **mtime-grace check** on the wrapper's live log (`<prompt>.log`). If the log was written within the last 90 seconds and grace has not yet been applied, extend the cap from 1800s to 2100s and continue awaiting. Otherwise call the selected adapter's termination mapping, record `cli-failure` with `--exit-code 124 --duration-ms <observed_ms> --message "<wrapper> exceeded polling cap (grace=<applied|not-applied>, last_mtime_age=<n>s)"`, then return the language-specific `*_CLI_TIMEOUT` sentinel.
|
|
285
|
+
- The selected adapter owns runtime-session accounting for the full wrapper window; core retains only the observed start/end event boundaries.
|
|
286
|
+
- **No external timeout on wrapper subagents.** The codex/antigravity wrapper subagent's polling loop (with optional mtime grace) is the SINGLE timeout authority for its dispatch. Lead MUST NOT impose a separate `dispatch_worker` timeout, an outer `Bash` wall-clock deadline, or any other mechanism that terminates the subagent before its own polling cap is reached. Doing so reproduces the historical failure mode that motivated this rule: Lead aborts the subagent at e.g. 18 minutes, the subagent returns nothing, and Lead classifies the role as "no response" while the underlying CLI was actively working. The wrapper's polling cap (30min + optional 5min grace) is calibrated so that, combined with Lead's redispatch policy (see "Lead Redispatch Policy on Result-Missing"), a recoverable single-run failure costs at most ~70 minutes of wall-clock — predictable enough to plan around. If a specific run requires a tighter cap, lower it in the wrapper subagent's polling contract (single source of truth), NOT by layering Lead-side timeouts.
|
|
336
287
|
- `contract-violation` events (C) are recorded by Lead via `okstra error-log append-observed --error-type contract-violation ...` after inspecting worker outputs.
|
|
337
288
|
- Lead's responsibility regarding the sidecar is to dump it to the run-level error log via `okstra error-log append-from-worker` after each worker terminates; Lead does not write into the sidecar.
|
|
338
289
|
|
|
@@ -342,7 +293,7 @@ without proceeding.
|
|
|
342
293
|
2. Re-verification workers follow a constrained response format (verdict + brief explanation).
|
|
343
294
|
3. Workers cannot vote on their own findings (only verify other workers’ work).
|
|
344
295
|
4. The `report writer worker` does not participate in re-verification voting. It is responsible only for generating the final report.
|
|
345
|
-
5. Division of labor: the
|
|
296
|
+
5. Division of labor: the lead performs **finding-to-finding matching** (deciding which worker-A finding maps to which worker-B finding for cross-review) and mediates the round protocol; **workers cast the AGREE / DISAGREE / SUPPLEMENT votes** that determine consensus. The lead does NOT vote on substance and does NOT collapse worker disagreements by fiat — disagreements flow into the `contested` / `partial-consensus` classifications defined in `prompts/lead/convergence.md`.
|
|
346
297
|
6. Batch processing is performed with one spawn per worker per round (not one spawn per finding).
|
|
347
298
|
7. These rules do not apply if Convergence is disabled.
|
|
348
299
|
|
|
@@ -382,22 +333,7 @@ The header is followed by the standard worker output contract sections (Findings
|
|
|
382
333
|
|
|
383
334
|
## Usage Tracking
|
|
384
335
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
### How to Collect
|
|
388
|
-
|
|
389
|
-
At the **start of Phase 7** (persistence), run the helper via the okstra CLI with the path to this run's `team-state.json`. Substitute `<runDirectoryPath>` with a literal absolute path (no shell variables, no `$(...)`) so the `Bash(okstra:*)` permission match holds:
|
|
390
|
-
|
|
391
|
-
```bash
|
|
392
|
-
okstra token-usage /abs/path/to/run/state/team-state-<task-type>-<seq>.json --write --summary
|
|
393
|
-
```
|
|
394
|
-
|
|
395
|
-
`okstra token-usage` is a thin Node-side wrapper around the python helper installed at `~/.okstra/bin/okstra-token-usage.py`. Calling the python script directly with `python3 "$HOME/..."` is forbidden — the `$HOME` expansion breaks the literal-token permission match and forces a confirmation prompt every call.
|
|
396
|
-
|
|
397
|
-
The script reads:
|
|
398
|
-
- `~/.claude/projects/<encoded-cwd>/<sessionId>.jsonl` for the lead and every Claude-side worker (Claude worker, Report writer worker, plus the Claude wrappers around Codex/Antigravity workers). Sessions are discovered by the recorded team-state `teamName`, lead is identified by `lead.sessionId`, and other workers are identified by `agentName` (e.g. `claude-worker`, `codex-worker`, `antigravity-worker`, `report-writer`). **For this `agentName` match to work, Lead MUST set the Agent `name` arg to `<workerId>-worker` on every dispatch** (see [agents okstra-lead-contract.md Phase 4 — "Agent `name` on dispatch"](./okstra-lead-contract.md)); a worker dispatched without `name` carries no `agentName`, so the collector cannot attribute its session and records it `unavailable` (now surfaced as a `usageSummary.unattributedTeamSessions` entry rather than dropped silently).
|
|
399
|
-
- `~/.agent/sessions/Y/M/D/rollout-*.jsonl` for the underlying Codex CLI session (matched by `cwd` and timestamp window of the wrapper subagent). Last `event_msg.token_count.total_token_usage.total_tokens` is the session total.
|
|
400
|
-
- `~/.antigravity/tmp/<project>/chats/session-*.json` for the underlying Antigravity CLI session. Sum of per-message `tokens.total`.
|
|
336
|
+
At the start of Phase 7, call `collect_usage(source)` through the selected adapter. `source` is `team-state.leadAdapter.sessionAccounting` plus the dispatch backend's recorded event source. Never read another runtime's session store as a fallback. Persist the resulting `leadUsage`, worker usage, and `usageSummary` in team-state before report substitution and cleanup.
|
|
401
337
|
|
|
402
338
|
### Resulting team-state shape
|
|
403
339
|
|
|
@@ -411,8 +347,8 @@ The script reads:
|
|
|
411
347
|
"cacheReadTokens": 9842949,
|
|
412
348
|
"toolUses": 47,
|
|
413
349
|
"durationMs": 7253000,
|
|
414
|
-
"source": "
|
|
415
|
-
"sessionId": "<
|
|
350
|
+
"source": "<adapter-accounting-source>",
|
|
351
|
+
"sessionId": "<adapter-session-id>",
|
|
416
352
|
"collectedAt": "<utc>"
|
|
417
353
|
},
|
|
418
354
|
"workers": [
|
|
@@ -420,11 +356,8 @@ The script reads:
|
|
|
420
356
|
"workerId": "codex",
|
|
421
357
|
"usage": {
|
|
422
358
|
"totalTokens": 2274011,
|
|
423
|
-
"source": "
|
|
424
|
-
"sessionId": "<
|
|
425
|
-
"cliSessionPaths": ["/Users/.../.agent/sessions/.../rollout-*.jsonl"],
|
|
426
|
-
"cliTotalTokens": 5261833,
|
|
427
|
-
"cliModel": "gpt-5.5"
|
|
359
|
+
"source": "<dispatch-event-source>",
|
|
360
|
+
"sessionId": "<worker-session-id>"
|
|
428
361
|
}
|
|
429
362
|
}
|
|
430
363
|
],
|
|
@@ -440,20 +373,14 @@ The script reads:
|
|
|
440
373
|
|
|
441
374
|
### Notes
|
|
442
375
|
|
|
443
|
-
-
|
|
444
|
-
-
|
|
445
|
-
-
|
|
446
|
-
- If the lead jsonl is missing (e.g. if `lead.sessionId` was never persisted), the script records an "unavailable" block with the searched path. Always populate `lead.sessionId` in team-state at Phase 3 — the okstra.sh launcher already passes it as `CLAUDE_SESSION_ID`.
|
|
447
|
-
- Convergence re-verification agents are dispatched as fresh subagents under the same `teamName` and will be discovered automatically. If you want them split out, set a distinct `agentName` on dispatch and post-process.
|
|
448
|
-
|
|
449
|
-
### Lead Duration
|
|
450
|
-
|
|
451
|
-
`durationMs` for the lead is computed from the first to last timestamp in the lead jsonl. If you need wall-clock from run-start to report-completion instead, override `leadUsage.durationMs` after running the script.
|
|
376
|
+
- If a worker has status `not-run`, `collect_usage` records an `unavailable` block.
|
|
377
|
+
- Adapter-native and underlying provider usage are separate accounting sources and must not be added together without an explicit pricing model.
|
|
378
|
+
- `durationMs` uses the selected adapter's documented session boundary.
|
|
452
379
|
|
|
453
380
|
## Team State Persistence
|
|
454
381
|
|
|
455
382
|
Information to be recorded in the team-state JSON file:
|
|
456
|
-
- `teamName` — record the audit label set in Phase 3 (`okstra-<task-key>` + stage suffix)
|
|
383
|
+
- `teamName` — record the manifest-provided audit label set in Phase 3 (`okstra-<task-key>` + stage suffix) and preserve that exact value consistently within the run. The selected adapter owns any runtime-session matching derived from this audit field.
|
|
457
384
|
- Current status of each worker role
|
|
458
385
|
- Start/end times for each worker
|
|
459
386
|
- Prompt history path for each worker
|