okstra 0.218.0 → 0.219.1
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 +5 -5
- package/dist/cli-registry.mjs +0 -10
- package/dist/cli-registry.mjs.map +1 -1
- package/dist/commands/lifecycle/config.mjs +2 -3
- package/dist/commands/lifecycle/config.mjs.map +1 -1
- package/dist/commands/pr/pr.d.mts +6 -0
- package/dist/commands/pr/pr.mjs +58 -0
- package/dist/commands/pr/pr.mjs.map +1 -1
- package/dist/lib/runtime-payload.mjs +1 -2
- package/dist/lib/runtime-payload.mjs.map +1 -1
- package/docs/architecture/storage-model.md +1 -1
- package/docs/architecture.md +9 -7
- package/docs/cli.md +3 -4
- package/docs/project-structure-overview.md +4 -5
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/prompts/launch.template.md +1 -1
- package/runtime/prompts/lead/okstra-lead-contract.md +1 -3
- package/runtime/prompts/lead/report-writer.md +10 -17
- package/runtime/prompts/lead/team-contract.md +1 -2
- package/runtime/prompts/wizard/prompts.ko.json +0 -1
- package/runtime/python/okstra_ctl/adapters/hosts/codex/relay.md +1 -1
- package/runtime/python/okstra_ctl/adapters/providers/antigravity/adapter.py +1 -1
- package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +0 -1
- package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +1 -1
- package/runtime/python/okstra_ctl/adapters/providers/grok/adapter.py +0 -1
- package/runtime/python/okstra_ctl/adapters/providers/kimi/adapter.py +0 -1
- package/runtime/python/okstra_ctl/agent/invocation.py +1 -2
- package/runtime/python/okstra_ctl/agent/prompt_cli/cli.py +2 -2
- package/runtime/python/okstra_ctl/agent/prompt_cli/jobs.py +0 -2
- package/runtime/python/okstra_ctl/agent/prompt_cli/materialize.py +2 -27
- package/runtime/python/okstra_ctl/agent/prompt_cli/run_identity.py +0 -4
- package/runtime/python/okstra_ctl/dispatch_core.py +3 -349
- package/runtime/python/okstra_ctl/dispatch_state.py +0 -13
- package/runtime/python/okstra_ctl/domain/provider.py +1 -1
- package/runtime/python/okstra_ctl/domain/role.py +0 -6
- package/runtime/python/okstra_ctl/final_report_paths.py +0 -16
- package/runtime/python/okstra_ctl/i18n.py +2 -2
- package/runtime/python/okstra_ctl/path_hints.py +0 -4
- package/runtime/python/okstra_ctl/paths.py +0 -3
- package/runtime/python/okstra_ctl/phases/final_verification/profile.md +2 -0
- package/runtime/python/okstra_ctl/phases/final_verification/spec.md +2 -0
- package/runtime/python/okstra_ctl/phases/final_verification/target.py +17 -1
- package/runtime/python/okstra_ctl/phases/implementation/entry.py +12 -0
- package/runtime/python/okstra_ctl/phases/implementation/instructions/_implementation-deliverable.md +1 -0
- package/runtime/python/okstra_ctl/phases/implementation/instructions/_implementation-executor.md +1 -0
- package/runtime/python/okstra_ctl/phases/implementation/spec.md +4 -0
- package/runtime/python/okstra_ctl/phases/release_handoff/boundary.json +1 -1
- package/runtime/python/okstra_ctl/phases/release_handoff/operations.py +24 -3
- package/runtime/python/okstra_ctl/phases/release_handoff/profile.md +11 -11
- package/runtime/python/okstra_ctl/phases/release_handoff/spec.md +4 -2
- package/runtime/python/okstra_ctl/render.py +0 -10
- package/runtime/python/okstra_ctl/render_final_report.py +4 -4
- package/runtime/python/okstra_ctl/report_finalize.py +37 -76
- package/runtime/python/okstra_ctl/report_html/render.py +4 -44
- package/runtime/python/okstra_ctl/report_language.py +3 -3
- package/runtime/python/okstra_ctl/report_prose_keys.py +153 -0
- package/runtime/python/okstra_ctl/report_synthesis_packet.py +1 -1
- package/runtime/python/okstra_ctl/run.py +1 -21
- package/runtime/python/okstra_ctl/stage_integrate.py +37 -2
- package/runtime/python/okstra_ctl/stage_rebase.py +189 -0
- package/runtime/python/okstra_ctl/stage_targets.py +29 -62
- package/runtime/python/okstra_ctl/team.py +1 -6
- package/runtime/python/okstra_ctl/wizard/confirmation.py +0 -8
- package/runtime/python/okstra_ctl/wizard/registry.py +2 -3
- package/runtime/python/okstra_ctl/wizard/sources.py +10 -0
- package/runtime/python/okstra_ctl/worker_prompt_policy.py +3 -12
- package/runtime/python/okstra_ctl/worktree/__init__.py +1 -1
- package/runtime/python/okstra_ctl/worktree/decisions.py +3 -4
- package/runtime/python/okstra_ctl/worktree/provision.py +27 -0
- package/runtime/python/okstra_ctl/worktree/rebase.py +108 -0
- package/runtime/python/okstra_ctl/worktree_registry.py +14 -0
- package/runtime/skills/_fragments/wizard-render-bundle.md +1 -1
- package/runtime/skills/okstra-code-review/SKILL.md +1 -1
- package/runtime/skills/okstra-discussion/SKILL.md +1 -1
- package/runtime/skills/okstra-pr-gen/SKILL.md +9 -0
- package/runtime/skills/okstra-run/SKILL.md +1 -1
- package/runtime/skills/okstra-setup/SKILL.md +2 -2
- package/runtime/skills/okstra-setup/references/project-config.md +2 -2
- package/runtime/templates/pr/drafting-rules.md +4 -0
- package/runtime/templates/report-writer-prompt-preamble.md +1 -1
- package/runtime/templates/reports/html/i18n/en.json +0 -1
- package/runtime/templates/reports/html/i18n/ko.json +0 -1
- package/runtime/templates/worker-prompt-preamble.md +1 -1
- package/runtime/validators/validate-run.py +1 -28
- package/runtime/agents/operations/report-translation.json +0 -6
- package/runtime/agents/roles/translator.json +0 -19
- package/runtime/bin/okstra-report-translate.py +0 -404
- package/runtime/prompts/duties/translator.json +0 -32
- package/runtime/python/okstra_ctl/report_translation.py +0 -509
- package/runtime/python/okstra_ctl/report_translation_dispatch.py +0 -356
- package/runtime/templates/translator-prompt-preamble.md +0 -36
|
@@ -206,7 +206,7 @@ The Module column below is where the command's behaviour lives — a `src/` modu
|
|
|
206
206
|
| `token-usage` | `scripts/okstra-token-usage.py` | Wrap installed Python token usage CLI |
|
|
207
207
|
| `spawn-followups`, `error-log` | `scripts/okstra-spawn-followups.py`, `scripts/okstra-error-log.py` | Follow-up task bundle creation and run error-log append helpers |
|
|
208
208
|
| `memory` | `src/commands/memory/memory.mts` | Store/find global conversation memory under `~/.okstra/memory-book`; `add --source-key` returns the stored entry for a key it already holds, under a per-key lock (`src/lib/file-lock.mts`, shared with `chat`) |
|
|
209
|
-
| `pr` | `src/commands/pr/pr.mts` | `okstra pr <template\|branches\|gen>` — PR body template store under `~/.okstra/template/pr/` (default `templates/pr/pr-body.template.md`, shared with release-handoff), base-branch recommendation, and a fixed-text generation bundle — template, `<base>..<head>` commits, `<base>...<head>` diffstat and the `templates/pr/drafting-rules.md` drafting rules — used by the okstra-pr-gen skill and the release-handoff lead. `--json` preserves the same fields as a machine contract. Git-only; no project registration required |
|
|
209
|
+
| `pr` | `src/commands/pr/pr.mts` | `okstra pr <template\|branches\|gen>` — PR body template store under `~/.okstra/template/pr/` (default `templates/pr/pr-body.template.md`, shared with release-handoff), base-branch recommendation, and a fixed-text generation bundle — template, `<base>..<head>` commits, `<base>...<head>` diffstat and the `templates/pr/drafting-rules.md` drafting rules — used by the okstra-pr-gen skill and the release-handoff lead; `check` lists okstra identifiers left in a drafted body. `--json` preserves the same fields as a machine contract. Git-only; no project registration required |
|
|
210
210
|
| `recap` | `scripts/okstra_ctl/recap.py` | `okstra recap <assemble\|record\|note>` Node wrapper backing the okstra-inspect `recap` facet — `assemble` is a read-only phase-transition summary for a task or, with `--task-group`, the group's start order plus each task's latest conclusion; `record` appends one line to `recap/recap-log.jsonl` (task) or `.okstra/tasks/<group>/.recap/recap-log.jsonl` (`--task-group`); `note` writes an agent-authored note under `notes/` and prints the `--clarification-response` argument for a follow-up run |
|
|
211
211
|
| `stage-map` | `scripts/okstra_ctl/stage_map_cli.py` | `okstra stage-map <task-key>` — exposes a task's implementation-planning Stage Map as JSON (`stages[].{stage_number,title,depends_on,step_count}` + consumer-state-based `doneStages[]`). If there is no Stage Map, `stages: []`. The read-side basis from which `okstra-schedule-gen` derives stage units and dependency closure |
|
|
212
212
|
| `design-prep` | `scripts/okstra_ctl/design_prep.py` | `okstra design-prep <list\|show\|write>` thin shim into `scripts/okstra_ctl/design_prep.py` — queries (`list`/`show`) the design items that implementation-planning pre-authored with AI, and records the user-confirmed responses as an append-only sidecar under `design-prep-inputs/` (`write`, `--confirmed` required). It never modifies the report snapshot |
|
|
@@ -360,7 +360,8 @@ Important modules:
|
|
|
360
360
|
| `lead_events.py` | Structured JSONL events emitted by artifact-accounted lead runtimes. Its locked append path assigns monotonic `A-NNN` identifiers to activity events in the same canonical event file. |
|
|
361
361
|
| `worker_prompt_headers.py` | shared rendering of phase-aware worker prompt anchors (`worker_prompt_headers`): coding-preflight only for implementation and compact target identity for final-verification |
|
|
362
362
|
| `worker_prompt_body.py` | provider-neutral initial analysis body/input renderer shared by Codex and external/team dispatch paths |
|
|
363
|
-
| `
|
|
363
|
+
| `report_prose_keys.py` | `PROSE_KEYS` — final-report leaf keys whose values are reader-facing prose; `validators/validate-run.py` uses it to reject null literals (`None`, `null`) in prose cells |
|
|
364
|
+
| `report_language.py` | report-writer `**Report Language:**` resolution (`resolve_report_language`) — precedence project config → global config → `en`; the value is a language tag the report writer authors its prose in, shared by both dispatchers so the stamped language does not depend on which dispatch path ran |
|
|
364
365
|
| `worker_prompt_policy.py` | `PromptPlan` generating SSOT — resolves functional audience, equality group, packet-only input, coding-preflight eligibility, required headers, and size limits without consulting provider/model identity |
|
|
365
366
|
| `worker_prompt_contract.py` | deterministic cross-task initial-prompt validator and normalized cross-worker equality SSOT, reused by dispatch adapters and the Phase 7 persisted-artifact validator |
|
|
366
367
|
| `initial_prompt_materialization.py` | sole owner of roster-derived initial prompt rendering, request compatibility checks, contract validation, and immutable create-if-absent publication; exposes `materialize_initial_prompts(InitialPromptMaterializationRequest) -> tuple[Path, ...]` |
|
|
@@ -376,8 +377,7 @@ Important modules:
|
|
|
376
377
|
| `plan_derivations.py` | the supersession sweep `_common-contract.md` requires an author to do by hand — extracts the symbols, paths, and ids an answered clarification names and reports every plan string that mentions one. Advisory: it locates candidates and never judges which are now false |
|
|
377
378
|
| `scope_provenance.py` | single source of truth for the scope-provenance grammar every phase-emitted requirement must declare, shared by `validators/validate-run.py` and `scripts/okstra_ctl/phases/requirements_discovery/validation.py` so the planning report and fan-out packets cannot drift |
|
|
378
379
|
| `worker_artifact_paths.py` | canonical worker artifact path derivation (e.g. `audit_sidecar_rel` inserts `-audit-` after the first `-worker-` token), so dispatch and validation agree on non-canonical-path rejection |
|
|
379
|
-
| `
|
|
380
|
-
| `report_finalize.py` | Phase 7 post-report sequence **SSOT** — runs `translate` → `token-usage` → `render-views` → `spawn-followups` → `record-verified` → `validate-run` → `record-group-memory` → `teardown-stages` → `prune-run-artifacts` in that load-bearing order. A non-zero exit still runs every later check through `validate-run` and names the earliest failure; `record-group-memory` (this run's conclusion into the task-group's `group-context.md`, plus `nextInGroup` for the closeout) and `teardown-stages` are skipped when any earlier step failed; `prune-run-artifacts` (removes `node_modules` / `.next` under the run directory, and a validated run's dispatch snapshots and publication locks) always runs. Both lead paths converge here: the Codex adapter calls it in-process (`codex_dispatch`), a Claude-led run reaches it through `okstra report-finalize`. Neither reimplements the sequence |
|
|
380
|
+
| `report_finalize.py` | Phase 7 post-report sequence **SSOT** — runs `token-usage` → `render-views` → `spawn-followups` → `record-verified` → `validate-run` → `record-group-memory` → `teardown-stages` → `prune-run-artifacts` in that load-bearing order. A non-zero exit still runs every later check through `validate-run` and names the earliest failure; `record-group-memory` (this run's conclusion into the task-group's `group-context.md`, plus `nextInGroup` for the closeout) and `teardown-stages` are skipped when any earlier step failed; `prune-run-artifacts` (removes `node_modules` / `.next` under the run directory, and a validated run's dispatch snapshots and publication locks) always runs. Both lead paths converge here: the Codex adapter calls it in-process (`codex_dispatch`), a Claude-led run reaches it through `okstra report-finalize`. Neither reimplements the sequence |
|
|
381
381
|
| `wrapper_status.py` | worker wrapper status sidecar reader — the host-side reader of the sidecar `worker_runner.py` writes. `is_terminal` is the one question it answers for the dispatch record and the pane reclaim: does `stage` read `exited` |
|
|
382
382
|
| `worker_runner.py` | runs one worker CLI and records what happened — shared by every provider entrypoint. Owns the `selectors` pump over the child's streams, the stream-arrival idle watchdog (`killpg` on breach), the run-wide progress cap on the log copy, and the status sidecar's whole life. A run that dies after launch still closes its sidecar, so `worker_liveness` never reads a dead worker as running |
|
|
383
383
|
| `session_transcript.py` | worker session transcript — one line per event (time, speaker, body) with a run-wide progress-line cap (`LOG_LINE_CAP`, elision notice) so a single-file dispatch's tool echo cannot dominate the project's `.okstra/` bytes; the fixed shape lets a later lead write share the same file |
|
|
@@ -492,7 +492,6 @@ Token/cost accounting:
|
|
|
492
492
|
| `templates/worker-prompt-preamble.md` | Initial analysis audience procedure and output contract |
|
|
493
493
|
| `templates/implementation-worker-preamble.md` | Shared implementation executor/verifier procedure, including coding-preflight and worktree rules |
|
|
494
494
|
| `templates/report-writer-prompt-preamble.md` | Report-writer input and authoring procedure without analysis or implementation instructions |
|
|
495
|
-
| `templates/translator-prompt-preamble.md` | Translator output ownership and translation conduct, delivered to every provider regardless of host |
|
|
496
495
|
| `scripts/okstra_ctl/adapters/hosts/claude-code/worker-session.md` | Rules that hold because a worker runs inside the lead's Claude Code session; delivered to `runner=native-session` prompts only |
|
|
497
496
|
| `templates/worker-error-contract.md` | Audience-neutral error-path, sidecar schema, and write protocol shared by every initial worker |
|
|
498
497
|
|
package/package.json
CHANGED
package/runtime/BUILD.json
CHANGED
|
@@ -101,7 +101,7 @@ Do not end the turn after the validator result. Task-qualified report paths and
|
|
|
101
101
|
|
|
102
102
|
- Task manifest: `{{TASK_MANIFEST_RELATIVE_PATH}}`
|
|
103
103
|
- Run manifest: `{{RUN_MANIFEST_RELATIVE_PATH}}`
|
|
104
|
-
- User authorization evidence: `userAuthorization` in that run manifest preserves the displayed confirmation, submitted response, and selected input scope. Read it during intake and before requesting execution permission for workers
|
|
104
|
+
- User authorization evidence: `userAuthorization` in that run manifest preserves the displayed confirmation, submitted response, and selected input scope. Read it during intake and before requesting execution permission for workers. Cite the recorded response and exact recipient/material scope in the host tool justification. This record is a relayed user response, not an independent host permission grant. If absent, do not reconstruct approval from current defaults or model selection; use an actual earlier user response or ask only for the missing scope. New recipients or material require a scope comparison before dispatch.
|
|
105
105
|
- Active run context: `{{ACTIVE_RUN_CONTEXT_RELATIVE_PATH}}`
|
|
106
106
|
- Analysis packet: `{{ANALYSIS_PACKET_RELATIVE_PATH}}`
|
|
107
107
|
|
|
@@ -179,7 +179,6 @@ Every `okstra` command the lead documents cite, grouped by phase, each spelled w
|
|
|
179
179
|
| Command | Use when | Procedure |
|
|
180
180
|
|---|---|---|
|
|
181
181
|
| `okstra report-finalize --project-root <dir> --run-manifest <path> --report <path>` | Run the whole Phase 7 sequence; do not run its steps separately. Without `--only` it records `phase-7-persist` first; emit its `progressLines` | `report-writer` "Phase 6 → Phase 7 execution sequence" |
|
|
182
|
-
| `okstra report-translate check-data --run-manifest <path>` | Check an existing translation after a narrative correction | `report-writer` "Phase 6 → Phase 7 execution sequence" |
|
|
183
182
|
| `okstra handoff record-verified --plan-run-root <dir> --stage <N> --report-path <path> --data-json <path>` | Record an accepted final-verification against its stage. `report-finalize` runs it in its `record-verified` step; run it by hand only to repair a registry after that step failed | `report-writer` "Phase 6 → Phase 7 execution sequence" |
|
|
184
183
|
| `okstra team teardown --project-root <dir> --run-manifest <path>` | Close every recorded pane at the end of the run | cmux adapter "Semantic operation mapping" |
|
|
185
184
|
|
|
@@ -192,7 +191,7 @@ Every `okstra` command the lead documents cite, grouped by phase, each spelled w
|
|
|
192
191
|
## Core operating contract
|
|
193
192
|
|
|
194
193
|
- The `leader` owns orchestration, convergence supervision, and final-report review. It does not author the report narrative or assembled record when `Report writer worker` is in the roster. `lead` is a compatibility alias for `leader` and must not be written on new artifacts.
|
|
195
|
-
- Dispatch consumes stored role executions, not provider-named worker IDs. Canonical roles are `leader`, `analyser`, `critic`, `designer`, `planner`, `implementer`, `verifier`, `report-writer
|
|
194
|
+
- Dispatch consumes stored role executions, not provider-named worker IDs. Canonical roles are `leader`, `analyser`, `critic`, `designer`, `planner`, `implementer`, `verifier`, and `report-writer`. `executor` is a compatibility alias for `implementer`.
|
|
196
195
|
- Pane titles and operational rows use the stored `executionLabel`. Do not rebuild that label from a provider name or model string.
|
|
197
196
|
- `report-writer`, when in the roster, is the sole author of the report narrative. Lead reviews the draft and may request a revision through a follow-up dispatch, but MUST NOT edit that narrative or the assembled `data.json`. Contract v3 has no lead-authored fallback; a failed writer dispatch is retried or leaves the run blocked. Historical v2 reports may still carry `header.leadAuthoredFallback`, but no new run writes it.
|
|
198
197
|
- "Session resume", "team is no longer alive", and similar are NOT valid reasons to skip Report writer worker dispatch — see [report-writer](./report-writer.md) "Resume-safe dispatch".
|
|
@@ -619,7 +618,6 @@ The detailed persistence sequence lives in [report-writer](./report-writer.md).
|
|
|
619
618
|
Order of operations:
|
|
620
619
|
|
|
621
620
|
1. Run `okstra report-finalize ...`. Contract v3 collects usage, assembles the role-owned inputs into `data.json` once, renders views, persists follow-ups, validates the run, records this run's conclusion into the task-group's `group-context.md` for the group's sibling tasks, and performs eligible teardown in order. When the task's pointer is terminal and the group has a task not yet started, the result's `nextInGroup` names it and `nextCommand` closes on starting it from its brief — the group's start order is the brief ordinal; the briefs' Related Task Graph edges are quoted as `waits for` and do not reorder it.
|
|
622
|
-
2. When `meta.reportLanguage` is not `en`, the same call dispatches the translator: its `translate` step (directly before `render-views`) materializes the translator prompt when this run has no undispatched reservation, runs the CLI-wrapper dispatch, and requires the `*.i18n.<lang>.json` sidecar. Do not dispatch the translator by hand or split the sequence around it; if the step fails, clear the cause and resume with the `--only translate --only render-views …` hint the result prints (**Enforced:** `okstra_ctl.report_translation_dispatch`).
|
|
623
621
|
|
|
624
622
|
Keep the assigned worker prompt history paths stable in `team-state`, `run-manifest`, and `task-manifest`. Do not rewrite prompt artifacts to `/tmp` or omit prompt metadata for attempted workers.
|
|
625
623
|
|
|
@@ -129,29 +129,22 @@ For historical schema-v1 Markdown only, the following heading table remains a re
|
|
|
129
129
|
|
|
130
130
|
**Enforced:** `okstra_ctl.report_finalize.V3_STEP_ORDER` is the order — `report-finalize` runs the steps from that tuple, so the sequence cannot be reordered by a caller. Running the steps by hand is what this rule forbids, and that path is not reachable through the CLI.
|
|
131
131
|
|
|
132
|
-
Do not run the
|
|
132
|
+
Do not run the ten steps below manually. Invoke `okstra report-finalize`; contract 3.0 runs them in this order:
|
|
133
133
|
|
|
134
134
|
1. **`token-usage`** — collect usage into team state without touching the final record.
|
|
135
135
|
2. **`project-activity`** — report assembly validates every owner input and publishes the final record once.
|
|
136
|
-
3. **`preflight`** — run the same schema and conformance checks used by final validation before
|
|
137
|
-
4. **`
|
|
138
|
-
5. **`
|
|
139
|
-
6. **`
|
|
140
|
-
7. **`
|
|
141
|
-
8. **`
|
|
142
|
-
9. **`
|
|
143
|
-
10. **`
|
|
144
|
-
11. **`prune-run-artifacts`** — remove every `node_modules` and `.next` directory under the run directory, and the dispatch snapshots (`*.mutation-audit.json`) and publication locks (`*.publish.lock`) recorded by a run whose validation passed or by an earlier run in the same run directory as a passed run; it runs even after a failed step.
|
|
136
|
+
3. **`preflight`** — run the same schema and conformance checks used by final validation before rendering, without writing run status. Structural failure skips `spawn-followups`; rendering and final validation still record the failure.
|
|
137
|
+
4. **`render-views`** — render the Markdown reading copy and human HTML from the record. The report writer already wrote the prose in `reportLanguage`; nothing translates it.
|
|
138
|
+
5. **`spawn-followups`** — materialize registered follow-up tasks.
|
|
139
|
+
6. **`record-verified`** — for a final-verification whose verdict clears the work for release, run `okstra handoff record-verified` once per stage in `finalVerification.stageReports`, so the `verified` rows exist before validation reads them; a no-op for other task types and for a verdict that blocks release. Do not run `handoff record-verified` by hand.
|
|
140
|
+
7. **`validate-run`** — validate the record, views, run manifest, and team state.
|
|
141
|
+
8. **`record-group-memory`** — write this run's conclusion (headline, decisions, watch-outs, open follow-ups, record path, next phase) and the group's start order into the task-group's `group-context.md` okstra region, creating the file when the group has none; skipped, like teardown, when an earlier step failed. Sibling tasks read it as `## Task-Group Memory`.
|
|
142
|
+
9. **`teardown-stages`** — remove eligible stage worktrees after successful validation.
|
|
143
|
+
10. **`prune-run-artifacts`** — remove every `node_modules` and `.next` directory under the run directory, and the dispatch snapshots (`*.mutation-audit.json`) and publication locks (`*.publish.lock`) recorded by a run whose validation passed or by an earlier run in the same run directory as a passed run; it runs even after a failed step.
|
|
145
144
|
|
|
146
145
|
After `report-finalize` returns with `ok: true`, the lead closes the run with the launch prompt's User closeout. A generated HTML file alone does not establish successful validation.
|
|
147
146
|
|
|
148
|
-
When the result carries `recovery.mode: same-run`, continue the authorized work in this run. Read every `recovery.issues` entry and failed step output. Correct writer-owned fields through the correction ledger procedure above; correct orchestrator-owned inputs through their owning commands. If plan content changes, prepare and verify the affected items before finalizing. Then execute `recovery.resumeCommand`, which retains this run manifest and resumes from the earliest failure, including reassembly of contract 3.0 inputs.
|
|
149
|
-
|
|
150
|
-
### The translation sidecar: the `translate` step
|
|
151
|
-
|
|
152
|
-
`report-finalize` dispatches the translator itself. Its `translate` step runs directly before `render-views` (which overlays the sidecar), and it is a no-op when `reportLanguage` is `en` or the `*.i18n.<lang>.json` sidecar already exists. When the sidecar is missing, the step reuses this run's undispatched translator reservation if the lead already materialized one, otherwise it materializes the prompt itself — instruction file `state/translator-instructions-<task-type>-<seq>.md` (kept when the lead wrote one), prompt `prompts/translator-worker-prompt-<task-type>-<seq>.md`, `--result worker-results/translator-translations-<task-type>-<seq>.md`, `--audit-source worker-results/translator-worker-<task-type>-<seq>.md`, invocation id `<task-type>-<seq>-translator` (`-r2`, `-r3` after a failed attempt) — then dispatches the worker and waits for it: on a `terminalBackend: cmux-pane` run into a cmux pane like every other worker (the same code as `okstra team dispatch` followed by `okstra team await`; run-end `okstra team teardown` closes that pane), otherwise through the CLI-wrapper dispatcher. Either path records the dispatch and links the result. Do not run `agent-prompt materialize --audience translator` or `worker-dispatch --workers translator` by hand before `report-finalize`; the sequence used to be a manual lead step and was skipped in practice (2026-09-09, fontsninja-v3-site dev-10628-3: a `ko` run finalized in one call, zero translator reservations, English HTML). **Enforced:** `okstra_ctl.report_finalize.V3_STEP_ORDER` places the step; `okstra_ctl.report_translation_dispatch.translate_report` owns it; `_translator_job_from_reservation` in `scripts/okstra_ctl/dispatch_core.py` still refuses two undispatched reservations for one run, which only a hand-made second reservation produces.
|
|
153
|
-
|
|
154
|
-
The step succeeds only when the sidecar exists afterwards; a translator that exits 0 without publishing it fails the step. A failed `translate` does not stop the sequence: `render-views` still writes the view from the English body, `validate-run` records the missing sidecar as an advisory, and the result's resume hint starts at `--only translate --only render-views …` — run that once the cause (a host approval gate, an unavailable provider) is cleared rather than closing the run on an English view.
|
|
147
|
+
When the result carries `recovery.mode: same-run`, continue the authorized work in this run. Read every `recovery.issues` entry and failed step output. Correct writer-owned fields through the correction ledger procedure above; correct orchestrator-owned inputs through their owning commands. If plan content changes, prepare and verify the affected items before finalizing. Then execute `recovery.resumeCommand`, which retains this run manifest and resumes from the earliest failure, including reassembly of contract 3.0 inputs. Keep previous approvals, user decisions, model selections and completed evidence. Do not ask for another `/okstra-run` to repair references, coverage summaries, narrative syntax or command spelling. Ask only when an unresolved user decision or an actual external prerequisite prevents the correction. Do not edit an installed runtime or another repository while recovering a consuming project's task. **Enforced:** `report_finalize._finalize_recovery` returns the same-run command and complete owner issues, `closeout_command` suppresses the new-run closeout for that result, and `tests/report/test_report_finalize.py` checks recovery after a failed step. Execution of the correction remains the lead's responsibility.
|
|
155
148
|
|
|
156
149
|
## Routing pointer
|
|
157
150
|
|
|
@@ -13,7 +13,7 @@ Okstra tasks use one lead plus the exact worker assignments selected in the prep
|
|
|
13
13
|
|
|
14
14
|
### Role Definitions
|
|
15
15
|
|
|
16
|
-
The start screen assigns a **model ref** (`provider/model`) to each **canonical role** slot: `leader`, `analyser`, `critic`, `designer`, `planner`, `implementer`, `verifier`, `report-writer
|
|
16
|
+
The start screen assigns a **model ref** (`provider/model`) to each **canonical role** slot: `leader`, `analyser`, `critic`, `designer`, `planner`, `implementer`, `verifier`, `report-writer`. A provider name is the front of a model ref, not a role. Every `analyser` in the run shares an identical core responsibility. Specialization is additive — it lives in optional Section 7 of the worker output, NOT in differentiated core questions. Cross-verification only converges if every rostered analyser answers the same questions against the same brief.
|
|
17
17
|
|
|
18
18
|
| Canonical role | Core responsibility | Notes |
|
|
19
19
|
|------|------|------|
|
|
@@ -25,7 +25,6 @@ The start screen assigns a **model ref** (`provider/model`) to each **canonical
|
|
|
25
25
|
| `implementer` | Sole change author for one approved stage | Used by `implementation` |
|
|
26
26
|
| `verifier` | Independent review of the assigned duty's subject | Duty varies by task type |
|
|
27
27
|
| `report-writer` | **Authors** the final-report file in Phase 6 | Excluded from Phase 4/5 and convergence |
|
|
28
|
-
| `translator` | Translates the designated sidecar only | Phase 7 |
|
|
29
28
|
|
|
30
29
|
**Dispatch does not invent a missing model assignment.** Launch-time empty slots are filled by the model default chain before the run starts. At dispatch the model for every role comes from `resultContract.workerRoles[*].modelExecutionValue` in `task-manifest.json` (and lead model metadata). There is no per-role hard-coded fallback — see "Model Assignment Rules" below.
|
|
31
30
|
|
|
@@ -569,7 +569,6 @@
|
|
|
569
569
|
},
|
|
570
570
|
"confirmation": {
|
|
571
571
|
"header": "선택 확인:",
|
|
572
|
-
"translation_scope": " 번역 작업자: {model} — 보고서 작성자와 같은 제공자·모델을 사용합니다. 선택 언어의 보고서가 필요하면 보고서 본문과 관련 분석·검증 결과를 전달해 번역하고 최종 보고서를 생성합니다. 같은 작업 범위의 재검증·수정·재시도에도 위에서 선택한 제공자·모델을 사용합니다.",
|
|
573
572
|
"provider_data_scope": "\n전달 대상: 위 역할·모델 목록의 제공자(현재 세션 및 선택한 외부 모델 제공자).\n전달 자료: `{project_root}`의 이 작업에 대한 작업 개요, 작업 수행에 필요한 저장소 소스·문서, 선택한 근거 자료 및 실행 중 생성되는 관련 분석·검증 결과.\n진행을 선택하면 위 대상에 해당 자료를 전달하여 선택한 작업을 실행하는 것을 승인합니다. 선택에 없는 제공자나 작업과 무관한 자료는 승인 범위에 포함되지 않습니다. 실행 환경의 권한 검토는 별도로 적용됩니다.",
|
|
574
573
|
"static_role": " static-role : {role}#{ordinal} / {model}",
|
|
575
574
|
"dynamic_role": " dynamic-role : {role} / reuse selected participant model",
|
|
@@ -190,7 +190,7 @@ If preparation has already failed with a Git lock creation error or `Operation n
|
|
|
190
190
|
|
|
191
191
|
### Permission at the dispatch boundary
|
|
192
192
|
|
|
193
|
-
Read `runManifest.userAuthorization` before a live dispatch
|
|
193
|
+
Read `runManifest.userAuthorization` before a live dispatch. It preserves the confirmation text and the user response relayed through the wizard; quote its relevant recipient/material scope and response in the execution justification alongside the prepared assignment. A missing record is not consent, and the record does not override a host rejection. If review reports missing evidence already present in the record, submit that existing evidence through the permitted review mechanism; ask the user only when the actual approved scope does not cover the dispatch.
|
|
194
194
|
|
|
195
195
|
Before a live CLI worker dispatch, check the current host's declared sandbox and approval policy. In a restricted Codex session, request the host's supported execution permission on the dispatch command itself (`sandbox_permissions: "require_escalated"` for `exec_command` when that mechanism is available and permitted). Scope the request to the prepared run and explain that it starts the selected worker processes. Follow the host's approval decision; a wizard confirmation or a successful preflight does not grant this permission.
|
|
196
196
|
|
|
@@ -303,7 +303,7 @@ def create_provider() -> ProviderSpec:
|
|
|
303
303
|
role: "gemini-3.1-pro"
|
|
304
304
|
for role in (
|
|
305
305
|
"lead", "analyser", "critic", "designer", "planner", "executor",
|
|
306
|
-
"verifier", "report-writer",
|
|
306
|
+
"verifier", "report-writer",
|
|
307
307
|
)
|
|
308
308
|
},
|
|
309
309
|
wrapper="okstra-antigravity-exec.sh",
|
|
@@ -133,7 +133,7 @@ def create_provider() -> ProviderSpec:
|
|
|
133
133
|
models=CODEX,
|
|
134
134
|
default_models={
|
|
135
135
|
role: "gpt-6.1-sol"
|
|
136
|
-
for role in ("lead", "analyser", "critic", "designer", "planner", "executor", "verifier", "report-writer"
|
|
136
|
+
for role in ("lead", "analyser", "critic", "designer", "planner", "executor", "verifier", "report-writer")
|
|
137
137
|
},
|
|
138
138
|
wrapper="okstra-codex-exec.sh",
|
|
139
139
|
supported_roles=ALL_ROLE_TOKENS,
|
|
@@ -39,7 +39,6 @@ AgentAudience = Literal[
|
|
|
39
39
|
"scope-critic",
|
|
40
40
|
"acceptance-critic",
|
|
41
41
|
"report-writer",
|
|
42
|
-
"translator",
|
|
43
42
|
"code-reviewer",
|
|
44
43
|
"schedule-verifier",
|
|
45
44
|
"business-flow-investigator",
|
|
@@ -604,7 +603,7 @@ def load_role_duty_contract(duty_root: Path, audience: AgentAudience) -> DutyCon
|
|
|
604
603
|
def digest_duty_catalog(duty_root: Path) -> str:
|
|
605
604
|
"""Return the canonical digest of every contract file in a snapshot.
|
|
606
605
|
|
|
607
|
-
역할 계약은 하위 `roles/` 에 둔다 — `report-writer`
|
|
606
|
+
역할 계약은 하위 `roles/` 에 둔다 — `report-writer` 는 직무
|
|
608
607
|
id 이면서 역할 id 라, 한 폴더에 두면 두 계약이 같은 파일 이름을 두고 겹친다.
|
|
609
608
|
"""
|
|
610
609
|
names = [
|
|
@@ -114,8 +114,8 @@ def _add_materialize_parser(commands: argparse._SubParsersAction) -> None:
|
|
|
114
114
|
)
|
|
115
115
|
materialize.add_argument(
|
|
116
116
|
"--audit-source",
|
|
117
|
-
help=run_only + "; accepted only for report-writer
|
|
118
|
-
"
|
|
117
|
+
help=run_only + "; accepted only for report-writer, whose result is "
|
|
118
|
+
"not its own worker result",
|
|
119
119
|
)
|
|
120
120
|
materialize.add_argument("--host-runtime", help=standalone_only)
|
|
121
121
|
materialize.add_argument("--execution-runner", choices=("cli-wrapper",), help=standalone_only)
|
|
@@ -81,8 +81,6 @@ def _metadata_job(
|
|
|
81
81
|
if metadata.get("executionIdentityVersion") != 2 or metadata["dispatchKind"] != dispatch_kind:
|
|
82
82
|
raise AgentPromptCliError(f"{metadata_path}: expected v2 dispatchKind {dispatch_kind!r}")
|
|
83
83
|
execution = next(row for row in manifest["roleExecutions"] if row["roleExecutionRef"] == metadata["roleExecutionRef"])
|
|
84
|
-
if execution["role"] == "translator":
|
|
85
|
-
raise AgentPromptCliError("translator uses canonical reservation dispatch: worker-dispatch --workers translator")
|
|
86
84
|
prompt = _project_input(project, metadata["prompt"]["path"], "prompt")
|
|
87
85
|
anchors = prompt_anchor_values(prompt, ("Result Path", "Worker Result Path"))
|
|
88
86
|
result = anchors.get("Worker Result Path") or anchors.get("Result Path")
|
|
@@ -99,7 +99,7 @@ _AUDIENCES = frozenset(get_args(AgentAudience))
|
|
|
99
99
|
# 결과 파일과 별개의 워커 결과 포인터를 가진 audience. 이들만 `--audit-source` 로
|
|
100
100
|
# 두 번째 경로를 받고, 프롬프트에 `**Worker Result Path:**` 앵커가 생긴다.
|
|
101
101
|
# 나머지 audience 의 결과는 하나뿐이고 감사 사이드카는 그 이름에서 파생된다.
|
|
102
|
-
_POINTER_AUDIENCES = frozenset({"report-writer"
|
|
102
|
+
_POINTER_AUDIENCES = frozenset({"report-writer"})
|
|
103
103
|
|
|
104
104
|
|
|
105
105
|
def _materialize(args: argparse.Namespace) -> PreparedAgentInvocation:
|
|
@@ -196,7 +196,7 @@ def _materialize_run(
|
|
|
196
196
|
"the same path in the jobs file's workerResultPath"
|
|
197
197
|
)
|
|
198
198
|
audit_source_path = result_path
|
|
199
|
-
|
|
199
|
+
else:
|
|
200
200
|
if audit_source_path is None:
|
|
201
201
|
# The report writer is the one audience whose result path is not its
|
|
202
202
|
# own worker result: it writes the report body, while the audit
|
|
@@ -234,31 +234,6 @@ def _materialize_run(
|
|
|
234
234
|
result_path=result_path,
|
|
235
235
|
audit_source_path=audit_source_path,
|
|
236
236
|
)
|
|
237
|
-
elif (
|
|
238
|
-
audit_source_path is None
|
|
239
|
-
or _normalized(audit_source_path) == _normalized(result_path)
|
|
240
|
-
):
|
|
241
|
-
# translator 다. report-writer 와 같은 두-경로 audience 인데 종전엔 빠진
|
|
242
|
-
# `--audit-source` 를 `--result` 로 조용히 접었다. 그러면 프롬프트에
|
|
243
|
-
# `**Worker Result Path:**` 앵커가 안 생기는데, `worker-dispatch` 는 그
|
|
244
|
-
# 앵커가 `**Result Path:**` 와 다를 것을 요구하므로 발행은 되지만 어떤
|
|
245
|
-
# 디스패치도 받지 못하는 예약이 남는다. 예약은 회수 명령이 없어 리드가
|
|
246
|
-
# 두 번째 id 로 다시 만드는 순간 "exactly one reservation" 이 영영
|
|
247
|
-
# 깨졌다(2026-09-08 실측, fontsninja-v3-site dev-10627-2
|
|
248
|
-
# requirements-discovery). 발행 시점에 거절한다.
|
|
249
|
-
raise AgentPromptCliError(
|
|
250
|
-
"translator materialization requires --audit-source distinct from "
|
|
251
|
-
"--result: --result is the translator's own report "
|
|
252
|
-
"(e.g. worker-results/translator-translations-<task-type>-<seq>.md) "
|
|
253
|
-
"and --audit-source the worker-result .md the audit sidecar is "
|
|
254
|
-
"derived from (worker-results/translator-worker-<task-type>-<seq>.md). "
|
|
255
|
-
"`worker-dispatch --workers translator` reads both from the prompt's "
|
|
256
|
-
"**Result Path:** and **Worker Result Path:** anchors and refuses a "
|
|
257
|
-
"prompt without the second. To fix a prompt already published "
|
|
258
|
-
"without it, re-run this command with the same --invocation-id and "
|
|
259
|
-
"--prompt plus --replace-undispatched; a new invocation id would "
|
|
260
|
-
"leave two reservations and block the translator for this run"
|
|
261
|
-
)
|
|
262
237
|
_validate_run_identity(
|
|
263
238
|
manifest,
|
|
264
239
|
worker_id=args.worker_id,
|
|
@@ -29,10 +29,6 @@ def _validate_run_identity(
|
|
|
29
29
|
expected = "lead"
|
|
30
30
|
if worker_id != "lead":
|
|
31
31
|
raise AgentPromptCliError("lead assignment requires worker ID 'lead'")
|
|
32
|
-
elif assignment_ref == "translator":
|
|
33
|
-
expected = "translator"
|
|
34
|
-
if worker_id != "translator":
|
|
35
|
-
raise AgentPromptCliError("translator assignment requires worker ID 'translator'")
|
|
36
32
|
elif assignment_ref.startswith("critic/"):
|
|
37
33
|
scope = assignment_ref.split("/", 1)[1]
|
|
38
34
|
expected = CRITIC_DUTY_BY_ASSIGNMENT_SEGMENT.get(scope, "")
|