okstra 0.144.0 → 0.146.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.
Files changed (71) hide show
  1. package/README.md +4 -1
  2. package/docs/architecture.md +22 -4
  3. package/docs/cli.md +53 -6
  4. package/docs/project-structure-overview.md +19 -9
  5. package/package.json +1 -1
  6. package/runtime/BUILD.json +2 -2
  7. package/runtime/agents/workers/report-writer-worker.md +5 -6
  8. package/runtime/bin/okstra-trace-cleanup.sh +28 -2
  9. package/runtime/prompts/lead/adapters/claude-code.md +3 -3
  10. package/runtime/prompts/lead/convergence.md +30 -5
  11. package/runtime/prompts/lead/okstra-lead-contract.md +9 -3
  12. package/runtime/prompts/lead/report-writer.md +20 -14
  13. package/runtime/prompts/lead/team-contract.md +3 -3
  14. package/runtime/prompts/profiles/_common-contract.md +1 -1
  15. package/runtime/prompts/profiles/change-impact-analysis.md +24 -0
  16. package/runtime/prompts/profiles/feature-analysis.md +24 -0
  17. package/runtime/prompts/profiles/forbidden-actions.json +18 -0
  18. package/runtime/prompts/profiles/project-analysis.md +24 -0
  19. package/runtime/prompts/wizard/prompts.ko.json +44 -1
  20. package/runtime/python/okstra_ctl/analysis_inputs.py +369 -0
  21. package/runtime/python/okstra_ctl/analysis_packet.py +4 -10
  22. package/runtime/python/okstra_ctl/clarification_items.py +74 -1
  23. package/runtime/python/okstra_ctl/codex_dispatch.py +117 -58
  24. package/runtime/python/okstra_ctl/convergence_engine.py +3 -1
  25. package/runtime/python/okstra_ctl/dispatch_core.py +19 -56
  26. package/runtime/python/okstra_ctl/dispatch_state.py +167 -3
  27. package/runtime/python/okstra_ctl/path_hints.py +6 -0
  28. package/runtime/python/okstra_ctl/paths.py +7 -44
  29. package/runtime/python/okstra_ctl/render.py +79 -4
  30. package/runtime/python/okstra_ctl/render_final_report.py +13 -4
  31. package/runtime/python/okstra_ctl/report_views.py +134 -3
  32. package/runtime/python/okstra_ctl/run.py +118 -0
  33. package/runtime/python/okstra_ctl/run_context.py +34 -2
  34. package/runtime/python/okstra_ctl/schema_excerpt.py +12 -4
  35. package/runtime/python/okstra_ctl/user_response.py +309 -3
  36. package/runtime/python/okstra_ctl/wizard.py +579 -32
  37. package/runtime/python/okstra_ctl/worker_liveness.py +84 -21
  38. package/runtime/python/okstra_ctl/worker_prompt_body.py +24 -4
  39. package/runtime/python/okstra_ctl/worker_prompt_contract.py +57 -0
  40. package/runtime/python/okstra_ctl/worker_prompt_policy.py +3 -0
  41. package/runtime/python/okstra_ctl/worker_state.py +65 -0
  42. package/runtime/python/okstra_ctl/workflow.py +22 -0
  43. package/runtime/python/okstra_token_usage/antigravity.py +3 -0
  44. package/runtime/python/okstra_token_usage/codex.py +54 -23
  45. package/runtime/python/okstra_token_usage/collect.py +141 -33
  46. package/runtime/python/okstra_token_usage/paths.py +27 -0
  47. package/runtime/python/okstra_vendor/__init__.py +15 -2
  48. package/runtime/schemas/convergence-groups-v1.0.schema.json +0 -1
  49. package/runtime/schemas/final-report-v1.0.schema.json +849 -3
  50. package/runtime/skills/okstra-run/SKILL.md +27 -5
  51. package/runtime/skills/okstra-setup/references/project-config.md +13 -4
  52. package/runtime/templates/reports/change-impact-analysis-input.template.md +58 -0
  53. package/runtime/templates/reports/feature-analysis-input.template.md +59 -0
  54. package/runtime/templates/reports/final-report.template.md +220 -0
  55. package/runtime/templates/reports/i18n/en.json +8 -0
  56. package/runtime/templates/reports/i18n/ko.json +8 -0
  57. package/runtime/templates/reports/project-analysis-input.template.md +58 -0
  58. package/runtime/templates/reports/report.js +84 -5
  59. package/runtime/templates/reports/user-response.template.md +19 -1
  60. package/runtime/validators/lib/fixtures.sh +1 -1
  61. package/runtime/validators/validate-report-views.py +61 -7
  62. package/runtime/validators/validate-run.py +94 -1
  63. package/runtime/validators/validate_analysis_report.py +895 -0
  64. package/src/cli-registry.mjs +7 -10
  65. package/src/commands/execute/render-bundle.mjs +3 -0
  66. package/src/commands/execute/worker-state.mjs +29 -0
  67. package/src/commands/inspect/worker-liveness.mjs +5 -3
  68. package/src/commands/lifecycle/preflight.mjs +13 -3
  69. package/src/lib/runtime-readiness.mjs +90 -0
  70. package/runtime/python/okstra_ctl/phase_cleanup.py +0 -235
  71. package/src/commands/execute/phase-cleanup.mjs +0 -38
@@ -64,7 +64,7 @@ This adapter maps the neutral Okstra lead operations to Claude Code host primiti
64
64
  - Follow the core Result Path + terminal-status completion contract. The Claude adapter's wake mechanism is one `Bash(run_in_background: true)` poll covering every pending Result Path, not foreground sleep or an idle-notification dependency. A spawn acknowledgement is never completion.
65
65
  - The background poll uses a per-worker deadline of twice the expected duration: 20 minutes for `requirements-discovery`, 30 for `error-analysis`, 40 for `implementation-planning`, 40 for `implementation`, and 20 for `final-verification`. On timeout, record terminal status and apply the core's single shared retry budget.
66
66
  - Each in-process worker heartbeat audit sidecar must update at least every five minutes while its result is pending. A missing or stale heartbeat consumes the same one-retry budget; after the second silent hang, record `timeout`. The result file remains the authoritative completion signal.
67
- - **The background poll checks liveness, not only Result Paths.** Result Paths change once, at the very end, so polling them alone pays the full deadline for a worker that died at minute three. Each poll iteration MUST also run, in the same background shell, one `okstra worker-liveness` call covering every pending worker — `--audit <audit-sidecar-path>` for each in-process worker, `--prompt <prompt-history-path>` for each CLI-wrapper worker. The dispatch record's `livenessMode` selects the flag; never infer it from provider or filename. It exits non-zero when a worker is `stalled` (heartbeat older than the cadence budget) or `did-not-launch`; either verdict ends the wait for that worker immediately and spends the core's one-retry budget, rather than waiting out the deadline. The command reports only — it never kills or re-dispatches. It shares its heartbeat budget with the Phase 7 audit (`okstra_ctl.worker_heartbeat`), so a worker the live probe passes cannot fail the post-hoc one for cadence.
67
+ - **The background poll checks liveness, not only Result Paths.** Result Paths change once, at the very end, so polling them alone pays the full deadline for a worker that died at minute three. Each poll iteration MUST also run, in the same background shell, one `okstra worker-liveness` call covering every pending worker — `--audit <audit-sidecar-path>` for each in-process worker, and a paired `--team-state <path> --worker <id>` for each CLI-wrapper worker. The dispatch record's `livenessMode` selects the selector; never infer it from provider or filename. The wrapper selector resolves its prompt path and authoritative dispatch `startedAt` from team-state. It exits non-zero when a worker is `stalled` (heartbeat older than the cadence budget) or `did-not-launch`; either verdict ends the wait for that worker immediately and spends the core's one-retry budget, rather than waiting out the deadline. The command reports only — it never kills or re-dispatches. It shares its heartbeat budget with the Phase 7 audit (`okstra_ctl.worker_heartbeat`), so a worker the live probe passes cannot fail the post-hoc one for cadence.
68
68
  - The Claude Code harness blocks long foreground sleeps and shorter-sleep circumvention loops. Keep the result poll in a single background shell and let wrapper agents use their documented `BashOutput` loop.
69
69
  - On approved cleanup, reconcile the current live session roster before sending shutdown requests. Never target the lead session.
70
70
  - Collect usage before teardown. Resume through the recorded Claude session id and keep all run artifacts authoritative.
@@ -88,7 +88,7 @@ This adapter maps the neutral Okstra lead operations to Claude Code host primiti
88
88
  - At run start, record `teamName` as the audit label and `teamCreate: { attempted: false, status: "implicit", splitPane: <bool> }` in team-state. A concurrent run records `status: "skipped", reason: "concurrent-run"`. Populate `lead.sessionId`; the session transcript lives under `~/.claude/projects/<encoded-cwd>/<sessionId>.jsonl`.
89
89
  - Record the lead pane once with `mkdir -p "<RUN_DIR>/state" && { . "$HOME/.okstra/bin/lib/okstra/tmux-pane.sh" 2>/dev/null && okstra_resolve_caller_pane; } > "<RUN_DIR>/state/lead-pane.id" 2>/dev/null || true`. This is silent setup and must not gate cleanup; the cleanup script protects the lead pane itself.
90
90
  - Collect and persist token usage before any live-roster cleanup, including cleanup between batches and the run-end shutdown sequence.
91
- - Before each new worker batch (and before the next phase's render-bundle), the batch/phase-boundary reclaim is `okstra phase-cleanup --run-dir "<RUN_DIR>" --project-root "<PROJECT_ROOT>" --fallback-team "session-<lead.sessionId-prefix>"` (tmux-aware: it skips pane reclaim in a non-tmux session). Pass `--fallback-team` every time: after a resume or compaction the session id is re-issued, and without the label the reconcile finds no live roster and prints nothing to dismiss. It reclaims only completed panes and prints `dismissible-teammates`; send `SendMessage(to: <name>, message: { type: "shutdown_request" })` only to those confirmed-complete teammates. Never target the lead or an incomplete critic/reverify worker. (This is the batch/phase boundary reclaim; the run-end keep/clean sequence below is a separate, final step for when no next phase follows.)
91
+ - Before each new worker batch (and before the next phase's render-bundle), reclaim the prior round's completed teammate panes in two passes, adding `--keep report-writer-worker` to **both** passes while the report writer is in flight. First source the count: `$HOME/.okstra/bin/okstra-trace-cleanup.sh --list --run-dir "<RUN_DIR>" [--keep report-writer-worker]` never kills and prints one `<pane_id>\t<pane_title>` line per pane it would reclaim — count those lines as `<n>`. Then perform the reclaim by running the same command **without** `--list`, and emit the neutral contract's `PROGRESS: phase-batch-cleanup panes=<n>` checkpoint with that count. Call both passes after collecting that round's results and token usage and before the next dispatch, so no in-flight worker pane is caught. This `tmux kill-pane`s the harness teammate panes; `shutdown_request` only idles the agent and never frees the pane, so it stays part of the run-end sequence for roster/token hygiene. In a non-tmux session there are no panes, both passes no-op, and `<n>` is `0` — still emit the checkpoint. The lead pane (read from `<RUN_DIR>/state/lead-pane.id`) is always preserved.
92
92
  - After batch cleanup, record the current live session generation with `okstra token-usage "<TEAM_STATE_PATH>" --record-observed-session --project-root "<PROJECT_ROOT>"`. This protects usage accounting when Claude Code re-issues the session id after resume or compaction.
93
93
  - Claude Code cannot delete the implicit team or surgically remove an idle roster entry. Explain that teammates may remain visible until session end and, when needed, give the manual action `Delete team <teamName> in Teams/FleetView`.
94
94
  - The `SessionEnd` hook runs `$HOME/.okstra/bin/okstra-team-reconcile.sh --session-end` as the safety net for the current live session.
@@ -102,6 +102,6 @@ This adapter maps the neutral Okstra lead operations to Claude Code host primiti
102
102
  > This phase is ending. The following Okstra panes and worker teammates remain — close and clean them up?
103
103
  > <quoted `--list` output>
104
104
  > (Yes) Close everything and clean up teammates / (No) Keep everything
105
- 5. On `keep`, preserve every residual resource and show `$HOME/.okstra/bin/okstra-trace-cleanup.sh --run-dir "<RUN_DIR>"` plus the manual Teams/FleetView action. Tell the user that `keep` holds only until the next boundary: if this session goes on to another phase/batch, that transition's `okstra phase-cleanup` reclaims the kept **completed** panes unattended (in-flight resources and the lead pane are never touched).
105
+ 5. On `keep`, preserve every residual resource and show `$HOME/.okstra/bin/okstra-trace-cleanup.sh --run-dir "<RUN_DIR>"` plus the manual Teams/FleetView action. Tell the user that `keep` holds only until the next boundary: if this session goes on to another phase/batch, that transition's round-boundary cleanup reclaims the kept **completed** panes unattended (in-flight resources and the lead pane are never touched).
106
106
  6. On approved `clean`, emit the teardown checkpoint, run `$HOME/.okstra/bin/okstra-trace-cleanup.sh --run-dir "<RUN_DIR>"`, then run `$HOME/.okstra/bin/okstra-team-reconcile.sh --project-root "<PROJECT_ROOT>" --fallback-team "session-<lead.sessionId-prefix>"` exactly once. The resolver reads the current live session's `~/.claude/teams/session-<live>/config.json`, falling back to the snapshot directory only when the live directory is absent, and prints `dismissible-member: <name>` records.
107
107
  7. Send `SendMessage(to: <name>, message: { type: "shutdown_request" })` to each printed, confirmed-complete non-lead member. The `message` MUST be the object literal shown, NEVER a JSON string in a text field. Never target the lead or use `TaskStop`; teammates are not background tasks.
@@ -48,7 +48,7 @@ Configure this in the `convergence` block of `task-manifest.json`. If the block
48
48
  | `enabled` | `true` | If `false`, skip the convergence loop and use the existing consensus/divergence method |
49
49
  | `maxRounds` | phase-aware: `1` for `requirements-discovery`, `2` otherwise (range 1–3) | Maximum number of re-verification rounds. Discovery's routing/missing-input outputs gain little from a second round; other phases (especially `error-analysis`) keep `2`. Lead resolves the effective value when the manifest omits the key and records it in `config.effectiveMaxRounds` of the convergence state artifact. |
50
50
  | `verificationMode` | `"lightweight"` | `"lightweight"` or `"full-reanalysis"` |
51
- | `adversarial` | phase-aware: `true` for `requirements-discovery` / `error-analysis` / `implementation-planning`, `false` otherwise | When `true`, Phase 5.5 runs in **adversarial mode** (see §"Adversarial Verification Mode"): verifiers actively try to refute each finding, the burden of proof sits on the claim, and `verificationMode` is forced to `"full-reanalysis"` scoped to the finding's cited evidence. Resolved by `scripts/okstra_ctl/render.py` `_build_convergence_block` and recorded in `config.adversarial` of the convergence state artifact. |
51
+ | `adversarial` | phase-aware: `true` for `requirements-discovery` / `error-analysis` / `implementation-planning` / `project-analysis` / `feature-analysis` / `change-impact-analysis`, `false` otherwise | When `true`, Phase 5.5 runs in **adversarial mode** (see §"Adversarial Verification Mode"): verifiers actively try to refute each finding, the burden of proof sits on the claim, and `verificationMode` is forced to `"full-reanalysis"` scoped to the finding's cited evidence. Resolved by `scripts/okstra_ctl/render.py` `_build_convergence_block` and recorded in `config.adversarial` of the convergence state artifact. |
52
52
 
53
53
  **Auto-disable rule (BLOCKING).** Convergence requires ≥2 analyser workers to produce a meaningful consensus tally. When the active profile's `Required workers:` block (see `prompts/profiles/*.md`) resolves to fewer than 2 analyser workers — e.g. `release-handoff` (zero analyser workers, lead-only) — the lead MUST treat `convergence.enabled` as `false` for that run regardless of manifest configuration, skip Phases 5.5 and the plan-body verification round ([plan-body-verification](./plan-body-verification.md)), and record `finalState: "converged"` with `totalRounds: 0`, `round2SkippedReason: "auto-disabled"`, an empty `roundHistory`, and an explanatory note in `config` (e.g. `"autoDisabled": "fewer-than-two-analysers"`). The plan-body round inherits the same rule via its `gating=false` advisory path.
54
54
 
@@ -84,7 +84,7 @@ Read the worker result files generated in Phase 4/5 and extract individual findi
84
84
  - Same semantics but disjoint ticket sets → separate groups (do NOT over-merge across tickets).
85
85
  - Only one worker confirms a finding → one single-source group.
86
86
  4. When grouping is ambiguous, prefer splitting over merging (avoid over-merging). Semantic matching, ticket-set equality, and evidence interpretation remain lead judgments; the engine does not perform fuzzy matching or decide whether evidence is credible.
87
- 5. Write `runs/<task-type>/state/convergence-groups-<task-type>-<seq>.json`. Each group carries its `ticketIds`, `originWorker`, `originEvidence`, `discoveredBy`, and every `<worker>:<item-id>` source in `sourceItems`. When a live command or external read produced reproducible evidence, also include `evidenceArtifacts[]` with its `.okstra/` path, SHA-256 digest, command, and environment. The field is optional because historical or inaccessible evidence may not have a captured artifact. The lead and verifier MUST NOT infer live or external evidence from wording or keyword matching; they use the finding's explicit claim, provenance, and supplied artifacts. Include the resolved worker roster in order with functional `audience` values; do not derive scope from provider or model identity. The `audience` enum is a convergence role, not a phase label: every finding-producing worker uses `analysis` — an `implementation` run's verifiers included — and only the report author uses `report-writer`. There is no `implementation-verifier` audience here; map the verifier roster to `analysis`.
87
+ 5. Write `runs/<task-type>/state/convergence-groups-<task-type>-<seq>.json`. Each group carries its `ticketIds`, `originWorker`, `originEvidence`, `discoveredBy`, and every `<worker>:<item-id>` source in `sourceItems`. For analysis sidetracks where ticket tagging is not required, `ticketIds: []` is the canonical value; never synthesize `"unknown"` or another placeholder. `scripts/okstra_ctl/convergence_engine.py` and `schemas/convergence-groups-v1.0.schema.json` enforce the required array field and reject non-string or blank entries while allowing the empty array. When a live command or external read produced reproducible evidence, also include `evidenceArtifacts[]` with its `.okstra/` path, SHA-256 digest, command, and environment. The field is optional because historical or inaccessible evidence may not have a captured artifact. The lead and verifier MUST NOT infer live or external evidence from wording or keyword matching; they use the finding's explicit claim, provenance, and supplied artifacts. Include the resolved worker roster in order with functional `audience` values; do not derive scope from provider or model identity. The `audience` enum is a convergence role, not a phase label: every finding-producing worker uses `analysis` — an `implementation` run's verifiers included — and only the report author uses `report-writer`. There is no `implementation-verifier` audience here; map the verifier roster to `analysis`.
88
88
  6. Do not write a queue or classification in this grouped-input artifact. `okstra convergence seed` classifies Round 0 by mode:
89
89
  - Collaborative mode: multi-source groups become `full-consensus` immediately; only single-source groups enter the working queue.
90
90
  - Adversarial mode: every finding enters the working queue regardless of source count. Semantic grouping merges provenance only; it does not decide a finding is reliable.
@@ -160,7 +160,15 @@ Use each finding as a guide but reanalyze the original code/data yourself. High
160
160
 
161
161
  ## Adversarial Verification Mode
162
162
 
163
- Active only when `config.adversarial == true` (default for `requirements-discovery`, `error-analysis`, and `implementation-planning`; see §"Configuration"); when `false`, every rule in this section is inert and the collaborative behaviour elsewhere in this contract applies unchanged. In adversarial mode the verifier's job inverts: instead of confirming a peer's finding, the verifier **tries to break it**, and the burden of proof sits on the claim — a finding survives only if refutation attempts fail.
163
+ Active only when `config.adversarial == true` (default for `requirements-discovery`, `error-analysis`, `implementation-planning`, `project-analysis`, `feature-analysis`, and `change-impact-analysis`; see §"Configuration"); when `false`, every rule in this section is inert and the collaborative behaviour elsewhere in this contract applies unchanged. In adversarial mode the verifier's job inverts: instead of confirming a peer's finding, the verifier **tries to break it**, and the burden of proof sits on the claim — a finding survives only if refutation attempts fail.
164
+
165
+ ### Read-only analysis task contract
166
+
167
+ For `project-analysis`, `feature-analysis`, and `change-impact-analysis`, every analysis worker independently analyses the full confirmed target. Provider or model diversity is an independent evidence source, never a reason to split the target into disjoint worker assignments. Only the `project-analysis` first exploration pass may divide navigation by component; every worker then returns to the whole confirmed target before producing findings.
168
+
169
+ A single evidence-backed refutation makes the affected finding `contested` while that refutation remains unresolved. Lead MUST NOT use majority voting to override it and MUST NOT promote a lead-only finding into confirmed facts. The report writer records current-run refutations and resolutions from the convergence state under `crossVerification`. `analysisReviewResolution` is reserved for a prior report's `## ANALYSIS REVIEW` carry-in and MUST remain empty without that carry-in. A `still-unresolved` carry-in item cannot appear in `analysisCommon.confirmedFacts`. **Enforcement:** `validators/validate_analysis_report.py` rejects non-empty `analysisReviewResolution` without a prior review and rejects a still-unresolved reviewed ID that appears in confirmed facts; the convergence-state validator preserves the engine's `contested` classification.
170
+
171
+ If every required analysis worker produces a non-result, the run verdict is `blocked`; Lead synthesis is not a worker result. A partial worker failure stays in `executionStatus`, but it does not by itself change the deterministic `analysis-complete` / `analysis-partial` scope verdict. **Enforcement:** `validators/validate_analysis_report.py` recomputes these verdict conditions from structured `data.json`.
164
172
 
165
173
  ### Scoped full-reanalysis
166
174
 
@@ -260,6 +268,23 @@ outside the common 9-header count above. Other providers do not receive it.
260
268
 
261
269
  The rationale for both drops is §"Reverify prompt: required-reading suppression" below.
262
270
 
271
+ Immediately after the anchor headers (and the provider-specific plain-file
272
+ header when present), copy this phase-boundary block before any reverify
273
+ instructions:
274
+
275
+ ```markdown
276
+ **Task Type:** <task-manifest taskType>
277
+ **Forbidden actions:**
278
+ <active-run-context workflow.forbiddenActions, verbatim>
279
+ ```
280
+
281
+ Do not summarize, shorten, or reconstruct the forbidden-actions text. The
282
+ selected adapter validates the task type and exact block through
283
+ `okstra_ctl.worker_prompt_contract.validate_reverify_prompt()` before starting
284
+ the wrapper. `validators/validate-run.py` separately fails the run when the
285
+ run-level error log records a phase-boundary `contract-violation`; a correct
286
+ finding does not make evidence obtained across the phase boundary admissible.
287
+
263
288
  `<modelExecutionValue>` MUST be resolved from one of these canonical sources, in priority order:
264
289
 
265
290
  1. `task-manifest.json` → `resultContract.requiredWorkerRoles[].modelExecutionValue` for the receiving role
@@ -492,9 +517,9 @@ Save it to `runs/<task-type>/state/convergence-<task-type>-<seq>.json`.
492
517
  Schema rules:
493
518
 
494
519
  - `schemaVersion`: literal string `"1.3"` for all new runs — both adversarial and collaborative. Historical readers accept `"1.0"` / `"1.1"` / `"1.2"` unchanged and never rewrite those artifacts during validation. v1.3 adds the strict coverage-critic ledger and rejects unknown top-level fields; work-state remains v1.0.
495
- - `config.adversarial`: boolean. `true` when this run used adversarial verification (default for `requirements-discovery` / `error-analysis` / `implementation-planning`). When `true`, `config.verificationMode` is `"full-reanalysis"` (scoped) and every `disagree` vote carries a non-null `disagreeBasis`.
520
+ - `config.adversarial`: boolean. `true` when this run used adversarial verification (default for `requirements-discovery` / `error-analysis` / `implementation-planning` / `project-analysis` / `feature-analysis` / `change-impact-analysis`). When `true`, `config.verificationMode` is `"full-reanalysis"` (scoped) and every `disagree` vote carries a non-null `disagreeBasis`.
496
521
  - `config.effectiveMaxRounds`: the integer the lead actually used after resolving the phase-aware default (`1` for `requirements-discovery`, `2` otherwise). MUST equal `config.maxRounds` when the manifest explicitly set it.
497
- - `findings[].ticketIds`: array of ticket keys from Phase 4 grouping (parsed per the Round 0 step 5 rule). MAY be empty when the discovering worker tagged the finding `unknown`.
522
+ - `findings[].ticketIds`: array of ticket keys from Phase 4 grouping (parsed per the Round 0 step 5 rule). It is empty when the phase does not require ticket tagging; `"unknown"` is not a ticket key and must not be synthesized.
498
523
  - `findings[].rounds[].votes.<worker>.verdict`: enum, one of `agree | disagree | supplement | verification-error`. Lower-case tokens; map upper-case AGREE/DISAGREE/SUPPLEMENT verdicts emitted by workers to their lower-case form and map the input alias `unverifiable` to persisted `verification-error`. The latter represents either a terminal non-result dispatch or a completed dispatch that could not verify a particular finding (§"Worker failure handling in reverify"). Every vote has a non-empty `explanation`.
499
524
  - `findings[].rounds[].votes.<worker>.disagreeBasis`: enum `counter-evidence | burden-not-met | null`. Non-null only when `verdict == "disagree"` AND `config.adversarial == true`; `null` (or absent, treated as null) otherwise. See §"Adversarial Verification Mode".
500
525
  - `findings[].classification`: enum, one of `full-consensus | partial-consensus | worker-unique | contested`. No other value is permitted.
@@ -103,7 +103,7 @@ Required checkpoints:
103
103
  - `PROGRESS: phase-5-collect worker=<role> status=<terminal-status>` — once per worker, immediately after the result file is verified.
104
104
  - `PROGRESS: phase-5.5-convergence round=<N> queue=<count>` — at the start of each convergence round (Phase 5.5).
105
105
  - `PROGRESS: phase-5.6-critic provider=<provider> gaps=<n>` — after the critic result is collected (Phase 5.6, opt-in; the critic dispatch itself fires concurrently with the first 5.5 reverify round). Omitted when `convergence.critic.enabled == false`.
106
- - `PROGRESS: phase-batch-cleanup panes=<n> teammates=<m>` — immediately after cleaning up the previous batch's panes and completed teammates, at each batch boundary (① just before the first `phase-5.5-convergence` round ② just before the `phase-6-synthesis` report-writer dispatch). Expose only the counts and NEVER expose `%NNN`/lead-pane.id/raw worker handles. Just before the first batch (analysis-worker dispatch) there is nothing to clean up, so it is a no-op and the marker is omitted.
106
+ - `PROGRESS: phase-batch-cleanup panes=<n>` — immediately after cleaning up the previous batch's panes, at each batch boundary (① just before the first `phase-5.5-convergence` round ② just before the `phase-6-synthesis` report-writer dispatch). `<n>` is the number of panes reclaimed at that boundary — trace panes plus completed teammate panes, which are panes too — read from the cleanup's `--list` pass taken immediately before the reclaim, never estimated. Expose only the counts and NEVER expose `%NNN`/lead-pane.id/raw worker handles. Just before the first batch (analysis-worker dispatch) there is nothing to clean up, so it is a no-op and the marker is omitted.
107
107
  - `PROGRESS: phase-6-synthesis dispatching report-writer-worker` — at the start of Phase 6.
108
108
  - `PROGRESS: phase-7-persist updating manifests` — at the start of Phase 7.
109
109
  - `PROGRESS: phase-7-teardown shutting-down-workers` — only after usage collection and user approval, immediately before `shutdown_workers`; omitted when no cleanup resource exists or the user keeps it.
@@ -198,6 +198,12 @@ Extract from the compact intake files: task key, task type, work category, workf
198
198
 
199
199
  If previous run reports exist, use as historical context only. If discovery metadata or current artifacts conflict with a newer user instruction, prefer the user instruction. If `reference-expectations.md` explicitly says expectations were not provided (you can confirm this without reading the file if the brief's "Expected state" section is empty), treat that as missing information and say `I don't know` rather than inventing expected states.
200
200
 
201
+ ### Phase 1.5 — Analysis scope confirmation (BLOCKING)
202
+
203
+ For `project-analysis`, `feature-analysis`, and `change-impact-analysis`, Lead MUST use the run manifest's immutable pre-dispatch `analysisScopeConfirmation` snapshot as the structured reporter-confirmation evidence before Phase 4 worker dispatch. Its `status` MUST be `complete`; its `taskBriefPath` and `briefSha256` bind that status to the exact brief bytes captured when the run manifest was created. A later edit to the live brief, clarification prose, or inferred consent cannot substitute for this snapshot. `project-analysis` confirms which areas remain shallow; `feature-analysis` confirms the exact feature target and covered flows; `change-impact-analysis` confirms the proposed change, preserved behavior, and dependency boundary.
204
+
205
+ If that snapshot is incomplete, missing, or malformed, Lead MUST follow the shared Reporter Confirmation Required / Clarification Items contract, stop before dispatch, and publish a `blocked` report. It MUST NOT silently widen the target. **Enforcement:** `scripts/okstra_ctl/render.py` records the brief path, reporter-confirmation status, and brief byte digest in the run manifest before the lead can dispatch workers; `validators/validate_analysis_report.py` validates only that immutable snapshot, rejects required-worker execution before a complete snapshot, and recomputes the analysis verdict; `validators/validate-run.py` runs that check only after schema validation succeeds.
206
+
201
207
  ## Phase 2 — Phase 5: Prompt preparation, teammate setup, execution, completion poll
202
208
 
203
209
  These phases are governed by [team-contract](./team-contract.md). It is the canonical source for:
@@ -284,7 +290,7 @@ Convergence is enabled by default. Configure via task-manifest.json:
284
290
  - `convergence.enabled`: true/false (default: true)
285
291
  - `convergence.maxRounds`: 1–3 — **phase-aware default**: `1` for `requirements-discovery`, `2` for all other task types
286
292
  - `convergence.verificationMode`: `"lightweight"` | `"full-reanalysis"` (default: `"lightweight"`; the adversarial phases below force `"full-reanalysis"`)
287
- - `convergence.adversarial`: true/false — **phase-aware default**: `true` for `requirements-discovery` / `error-analysis` / `implementation-planning`, `false` otherwise. When `true`, Phase 5.5 runs in adversarial mode (verifiers refute findings; burden of proof on the claim). See [convergence](./convergence.md) "Adversarial Verification Mode".
293
+ - `convergence.adversarial`: true/false — **phase-aware default**: `true` for `requirements-discovery` / `error-analysis` / `implementation-planning` / `project-analysis` / `feature-analysis` / `change-impact-analysis`, `false` otherwise. When `true`, Phase 5.5 runs in adversarial mode (verifiers refute findings; burden of proof on the claim). See [convergence](./convergence.md) "Adversarial Verification Mode".
288
294
 
289
295
  When `task-manifest.json` does not set `convergence.maxRounds`, lead MUST resolve the effective value via the phase-aware default above before entering Phase 5.5 and put it in the grouped input at `config.effectiveMaxRounds`.
290
296
 
@@ -391,7 +397,7 @@ After persistence, reply briefly in the resolved Report Language with: completio
391
397
  ## Run-scoped worker-resource lifecycle
392
398
 
393
399
  - At run start, call the selected adapter's setup required to distinguish lead-owned resources from worker-owned resources.
394
- - Before every new worker batch, clean only confirmed-complete resources from the prior batch, call `record_lead_event` for the batch-cleanup checkpoint, and never terminate the lead or an incomplete worker; the batch-reclaim primitive is the selected adapter's.
400
+ - Before every new worker batch, and between worker rounds within a phase, close the prior round's completed teammate resources before the next dispatch — never the lead and never an in-flight worker; call `record_lead_event` for the batch-cleanup checkpoint. The round-boundary teammate reclaim primitive is the selected adapter's.
395
401
  - After Phase 7 persistence and `collect_usage`, enumerate residual adapter-owned resources. If none remain, skip the question.
396
402
  - If resources remain, call `prompt_user` once with a binary keep-or-clean choice. The answer controls the entire residual set; do not ask a second backend-specific cleanup question.
397
403
  - On keep, preserve all resources and provide the selected adapter's manual-cleanup instruction.
@@ -4,7 +4,7 @@
4
4
 
5
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
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.
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. The worker-result pointer at `**Worker Result Path:**` records those two paths and the reconciled convergence input. These three completion artifacts land on disk before the worker returns; the heartbeat audit sidecar remains a separate required audit artifact.
8
8
 
9
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.
10
10
 
@@ -12,7 +12,7 @@ Two `frontmatter` approval fields are always emitted with their unset default
12
12
 
13
13
  **As the report-writer worker:** YOU write the data.json and invoke the renderer; the files on disk are the canonical record, so do not return either artifact inline.
14
14
 
15
- **As the lead:** 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.
15
+ **As the lead:** prepare the report-writer prompt, dispatch the Report writer worker per the Phase 6 dispatch template in okstra-lead-contract.md, and review the three completion artifacts plus the separate audit sidecar in Phase 7. Do not call `write_artifact` against the report paths or worker-result pointer yourself when Report writer worker is in the roster.
16
16
 
17
17
  ## When to Use
18
18
 
@@ -26,7 +26,7 @@ Two `frontmatter` approval fields are always emitted with their unset default
26
26
  2. Persist the exact prompt history with the required anchor headers and audience-specific reading list.
27
27
  3. Emit the Phase 6 checkpoint.
28
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.
29
+ 5. Call `await_workers([handle])` and verify the data.json Result Path, rendered Markdown sibling, and worker-result pointer at Worker Result Path. Verify the separate heartbeat audit sidecar before accepting the run. **Enforced:** both dispatch adapters keep the three completion paths in `WorkerJob.completion_paths`, and `validators/validate_session_conformance.py` validates the audit sidecar.
30
30
 
31
31
  The assignment's `modelExecutionValue` feeds both adapter dispatch and the prompt header in item 9 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.
32
32
 
@@ -35,8 +35,8 @@ The prompt MUST include, in this order at the top:
35
35
  1. `**Project Root:** <absolute-path>`
36
36
  2. `**Prompt History Path:** <project-relative-path>` (under current run `prompts/`)
37
37
  3. `**Result Path:** runs/<task-type>/reports/final-report-<task-type>-<seq>.data.json` — canonical JSON SSOT. The renderer produces the sibling `.md` automatically.
38
- 4. `**Audit sidecar path:** <absolute-path>` — the generated report-writer audit destination derived from the Markdown `**Worker Result Path:**`, never from Result Path.
39
- 5. `**Worker Result Path:** runs/<task-type>/worker-results/report-writer-worker-<task-type>-<seq>.md` — canonical Markdown worker-result source for the audit-path derivation.
38
+ 4. `**Worker Result Path:** runs/<task-type>/worker-results/report-writer-worker-<task-type>-<seq>.md` — canonical three-path worker-result pointer and source for the audit-path derivation.
39
+ 5. `**Audit sidecar path:** <absolute-path>` — the generated report-writer heartbeat/read-confirmation destination derived from the Markdown `**Worker Result Path:**`, never from Result Path.
40
40
  6. `Assigned worker prompt history path: <absolute-path>`
41
41
  7. The four BLOCKING dispatch anchor headers generated from the report-writer audience (the worker cannot synthesize any of these paths):
42
42
  - `**Worker Preamble Path:** <absolute-path>` — selects `templates/report-writer-prompt-preamble.md`.
@@ -49,18 +49,18 @@ The prompt MUST include, in this order at the top:
49
49
  - `<instruction-set>/final-report-schema.json` — a task-type excerpt of the data.json schema (the other task-types' deliverable blocks and their unreachable `$defs` are stripped; ~38% of the full schema is `$defs` alone). This is your authoring aid for the data.json shape — the installed schema, not the excerpt, is what the run is judged against. Do **NOT** pull the full `schemas/final-report-v1.0.schema.json` — it carries all task-types and its `schemas/...` path is not part of the task bundle. (Validation still runs against the full schema post-hoc via the renderer, so the excerpt never relaxes the contract.)
50
50
  - `<instruction-set>/final-report-template.md` — the **phase-stripped** template (every other task-type's §5.x deliverable block removed by `render.py`'s `_strip_phase_blocks`, leaving only your run's §5.x). Do **NOT** also pull the full `templates/reports/final-report.template.md` source (it re-adds ~330 lines of other phases' deliverables and is not in the task bundle).
51
51
  11. A one-line MCP pointer instead of the verbatim block (redundant — the brief is already in the report-writer's Required reading, item 10): `**MCP servers:** follow the task brief's "## Available MCP Servers" section (already in your Required reading).`
52
- 12. The convergence classifications (Full/Partial/Contested/Worker-Unique), the round history data (`roundHistory[]`), the `round2SkippedReason` value, and pointers to all worker result files under `worker-results/`. The report-writer worker populates `crossVerification.roundHistory` in the data.json so Section 6 can show which rounds executed, queue sizes, and why Round 2 was (or was not) skipped. The renderer prints the full per-round table only when more than one round ran; single-round or zero-round histories are auto-collapsed to a one-line summary.
52
+ 12. `Convergence state: runs/<task-type>/state/convergence-<task-type>-<seq>.json`, followed by pointers to all analysis-worker result files under `worker-results/`. The convergence path is deterministic and is listed even before Phase 5.5 creates the file. Read its classifications (Full/Partial/Contested/Worker-Unique), `roundHistory[]`, `round2SkippedReason`, and `finalClassificationCounts`; populate `crossVerification.roundHistory` in data.json so Section 6 can show which rounds executed, queue sizes, and why Round 2 was (or was not) skipped. The renderer prints the full per-round table only when more than one round ran; single-round or zero-round histories are auto-collapsed to a one-line summary.
53
53
  13. `**Report Language:** <en|ko>` — must be either `en` or `ko`; `auto`
54
54
  has been resolved by the lead from project.json / global config
55
55
  before the dispatch is constructed. The worker copies this verbatim
56
56
  into `data.json.meta.reportLanguage`.
57
57
  14. For implementation-planning runs: a literal block listing the 12 required English section headings — `Option Candidates`, `Trade-off`, `Recommended Option`, `Stage Map`, `Stepwise Execution Order`, `Dependency`, `Validation Checklist`, `Rollback`, `Requirement Coverage`, `Plan Body Verification`, `Cross-Project Dependencies`, `Decision Drafts`. This list is `PLANNING_REQUIRED_SECTIONS` in `validators/validate-run.py`; that tuple is the SSOT and this block must match it exactly. 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.
58
- 15. 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 <Audit sidecar 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.`
58
+ 15. An explicit instruction: `You are the author of THREE files: (a) the final-report data.json at <Result Path>, (b) its rendered Markdown sibling produced through "okstra render-final-report <Result Path>", and (c) the worker-result pointer at <Worker Result Path>. Maintain the separate heartbeat audit sidecar at <Audit sidecar path>. Do not return the report inline. The dispatch fails when any of the three completion artifacts is missing, and session conformance fails when the audit sidecar is missing or invalid.`
59
59
  16. The prose budget (dedup contract): `verdictCard.finalConclusion` is the conclusion SSOT — at most 3 sentences. `rationale.*` fields stay within 2 sentences each and reference the verdict card / row IDs instead of restating their prose; `readerSummary` fields are one line each; `summary` stays at 3-5 rows unless the run covers multiple tickets. The schema field descriptions carry the same budgets (`tests/contract/test_report_prose_budget.py` guards both surfaces). Generation time scales with output volume, so exceeding the budget is a cost bug, not extra diligence.
60
60
 
61
61
  **Fix-run incremental authoring (applies when the run's profile carries a "Fix-Run Carry" block).** Do not author the data.json from scratch. Start by copying the previous run's data.json (the `Previous report` path in the Fix-Run Carry block) to this run's Result Path, then update ONLY the blocks the fix run changed: `meta`/`header` (run seq, dates), `executionStatus`, `implementation.verifierResults`, `implementation.validationEvidence`, `implementation.commitList` / `diffSummary`, `crossVerification`, `verdictCard`, `finalVerdict`, and any `evidence` rows the fix touched. Deliverable prose for unchanged sections is carried forward verbatim — do not re-generate it. Then invoke the renderer exactly as in a full run. The schema validation and renderer contract are unchanged, so an incrementally-authored data.json passes the same post-hoc gates. The lead's dispatch prompt MUST include the previous data.json path when the carry block is present.
62
62
 
63
- **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 audit file (Audit sidecar path). Do NOT end the turn with a prose "waiting for the report" statement.
63
+ **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 pending set covering the data.json (Result Path), rendered Markdown sibling, and worker-result pointer (Worker Result Path). Check the separate audit sidecar before accepting conformance. Do NOT end the turn with a prose "waiting for the report" statement. **Enforced:** the adapters reject a completed transition while any `completionPaths` entry is absent; `validators/validate_session_conformance.py` owns the audit check.
64
64
 
65
65
  ### Resume-safe dispatch
66
66
 
@@ -273,19 +273,25 @@ When the run's `task-type` is `release-handoff`, the final report MUST include S
273
273
 
274
274
  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.
275
275
 
276
- ### Mandatory worker-results audit file (BLOCKING)
276
+ ### Mandatory worker-result pointer and audit sidecar (BLOCKING)
277
277
 
278
- You (the report-writer worker) MUST also write a worker-results audit file at the absolute path the lead provides as `**Audit sidecar path:**`, derived from `**Worker Result Path:**` and defaulting to:
278
+ You (the report-writer worker) MUST write the worker-result pointer at `**Worker Result Path:**`, defaulting to:
279
279
 
280
280
  ```
281
- runs/<task-type>/worker-results/report-writer-worker-audit-<task-type>-<seq>.md
281
+ runs/<task-type>/worker-results/report-writer-worker-<task-type>-<seq>.md
282
282
  ```
283
283
 
284
- This file is checked by the validator whenever the role's terminal status is `completed`. Without it the run fails with `report-writer is completed but worker result file is missing`.
284
+ Its body contains exactly the project-relative data.json path, rendered Markdown path, and convergence-state input path. Analysis-worker result files stay in `## Inputs`; do not copy their list into the pointer. **Enforced:** both dispatch adapters include this pointer in `WorkerJob.completion_paths` and refuse `completed` while it is absent.
285
+
286
+ The pointer's frontmatter and header follow `team-contract` "Result Frontmatter" and the standard worker-result header sections. Use `workerId: "report-writer"` and copy the remaining canonical values from `analysis-material.md`; do not duplicate the final-report body.
287
+
288
+ You MUST also write the separate heartbeat/read-confirmation audit file at `**Audit sidecar path:**`, derived from Worker Result Path and defaulting to:
285
289
 
286
- **Frontmatter + header schema** — both the worker-results audit file AND the final-report file are governed by `team-contract` ("Result Frontmatter" and the standard worker-result header sections). That document is the single source of truth; do NOT restate the field list here. Use `workerId: "report-writer"` for both files and copy every other frontmatter value verbatim from `analysis-material.md`. The body of this audit file is short: name the canonical final-report path you wrote, list the input artifacts you reconciled, and record any structural deviations from `final-report.template.md`. Do NOT duplicate the full final-report body here — it's an audit pointer, not a second copy.
290
+ ```
291
+ runs/<task-type>/worker-results/report-writer-worker-audit-<task-type>-<seq>.md
292
+ ```
287
293
 
288
- Skipping this file because "the real report is in `reports/`" is wrong. Both files are required.
294
+ The selected report-writer preamble defines that audit shape. **Enforced:** `validators/validate_session_conformance.py` checks its reading confirmation, progress stages, timestamps, and cadence whenever the role completes.
289
295
 
290
296
  ### Main Body Section
291
297
 
@@ -130,9 +130,9 @@ Each probe matches exactly one dispatch backend. The dispatch record's `liveness
130
130
  | Worker | Backend | Flag | What it reads |
131
131
  |---|---|---|---|
132
132
  | any in-process worker (including `claude-worker` and `report-writer-worker`) | in-process dispatch | `--audit` | its registered audit sidecar's newest `- PROGRESS:` heartbeat |
133
- | `codex-worker` / `antigravity-worker` | CLI wrapper | `--prompt` | `<prompt>.log` / `<prompt>.status.json` |
133
+ | `codex-worker` / `antigravity-worker` | CLI wrapper | `--team-state <path> --worker <id>` | the worker's persisted `promptPath` and `startedAt`, then `<prompt>.log` / `<prompt>.status.json` |
134
134
 
135
- The mismatch is not intermittent, it is guaranteed: only the `okstra-*-exec.sh` wrappers ever write `<prompt>.log` / `<prompt>.status.json`, so an in-process worker produces neither by construction. Probing an in-process worker with `--prompt` therefore reports `did-not-launch` for a worker that is running normally, every time, as soon as the 60s launch grace passes. Probe in-process workers with `--audit`.
135
+ The mismatch is not intermittent, it is guaranteed: only the `okstra-*-exec.sh` wrappers ever write `<prompt>.log` / `<prompt>.status.json`, so an in-process worker produces neither by construction. Probe in-process workers with `--audit`; use the paired `--team-state` / `--worker` selector only for a wrapper assignment. Its launch grace begins at the atomic `in-progress` transition's `startedAt`, never at prompt-materialization time.
136
136
 
137
137
  This is a transport-adapter liveness choice only. It does not change the reducer's worker identity or its verification responsibility: both remain bound to the registered worker instance and canonical artifacts.
138
138
 
@@ -147,7 +147,7 @@ After each worker subagent returns (regardless of role), Lead MUST verify the ca
147
147
  - The wrapper subagent returned an explicit `*_RESULT_MISSING` sentinel (codex-worker / antigravity-worker step 8c — `CODEX_RESULT_MISSING` / `ANTIGRAVITY_RESULT_MISSING`).
148
148
  - The result file is absent at the resolved absolute path even though the worker returned without a `*_RESULT_MISSING` sentinel — for example, claude-worker returned its final assistant message but never persisted the artifact, or the wrapper exited 0 and the codex/antigravity sub-agent forwarded raw stdout despite the contract.
149
149
  - The result file exists but cannot be parsed (frontmatter unreadable, sections 1–5 entirely missing). A truncated file in the middle of section 5 is NOT covered here — it goes to the validator's regular `error` path, not the retry path.
150
- - `okstra worker-liveness --prompt` reports a **CLI-wrapper** worker (`codex` / `antigravity`) `did-not-launch` — neither `<prompt-path>.log` nor `<prompt-path>.status.json` exists past the launch grace (default 60s). The wrapper writes its status sidecar before invoking the CLI and hard-fails loudly with a distinct exit code on every argument check before that, so the absence of BOTH artifacts means the dispatch itself never reached the script. Without this trigger the only evidence was a lead noticing two missing files by eye, and the run paid the full polling cap for a worker that never started.
150
+ - `okstra worker-liveness --team-state <path> --worker <id>` reports a **CLI-wrapper** worker (`codex` / `antigravity`) `did-not-launch` — neither `<prompt-path>.log` nor `<prompt-path>.status.json` exists after the persisted `startedAt` plus the launch grace (default 60s). The wrapper writes its status sidecar before invoking the CLI and hard-fails loudly with a distinct exit code on every argument check before that, so the absence of BOTH artifacts means the dispatch itself never reached the script. Without this trigger the only evidence was a lead noticing two missing files by eye, and the run paid the full polling cap for a worker that never started.
151
151
  - `okstra worker-liveness --audit` reports an **in-process** worker `stalled` — its registered audit sidecar's newest `- PROGRESS:` heartbeat is older than the cadence budget, or the sidecar carries no heartbeat at all. This is the in-process equivalent of the CLI wrappers' idle watchdog: the wrapper reaps a silent CLI itself, but nothing reaped a silent in-process worker until its deadline.
152
152
  - The result file exists but its audit sidecar does not, at `runs/<task-type>/worker-results/<worker>-audit-<task-type>-<seq>.md`. Workers write both in the same step, so a result without a sidecar means the Reading Confirmation block — the only evidence the worker read its inputs — was never produced. `validate-run.py` fails the run on this at Phase 7 either way (`validate_worker_results_audit`); checking it here spends the existing one-retry budget while the role can still be re-dispatched, instead of surfacing hours later when the worker session is gone.
153
153
 
@@ -9,7 +9,7 @@ profile document.
9
9
  - Worker interaction model (shared — read before inferring behaviour from the roster):
10
10
  - the per-profile `Required workers:` block is a **roster**, not a behaviour contract. Each role's interaction mode changes across operating phases of the same run.
11
11
  - **Phase 4 / 5 (independent analysis)**: analyser workers (`claude`, `codex`, `antigravity` when opted in) produce findings independently and have no access to one another's outputs. `report-writer` does not analyse.
12
- - **Phase 5.5 (convergence — peer review by workers)**: workers peer-review each other's findings across up to `effectiveMaxRounds` rounds; the lead mediates but does not vote. See `prompts/lead/convergence.md` for the round protocol (replay of findings, `AGREE` / `DISAGREE` / `SUPPLEMENT` verdicts), queue invariants, and final classification (`full-consensus` / `partial-consensus` / `contested` / `worker-unique`). For `requirements-discovery`, `error-analysis`, and `implementation-planning` this phase runs in **adversarial mode** (`convergence.adversarial=true`): verifiers try to refute each finding against its cited evidence and the burden of proof sits on the claim — see that skill's §"Adversarial Verification Mode".
12
+ - **Phase 5.5 (convergence — peer review by workers)**: workers peer-review each other's findings across up to `effectiveMaxRounds` rounds; the lead mediates but does not vote. See `prompts/lead/convergence.md` for the round protocol (replay of findings, `AGREE` / `DISAGREE` / `SUPPLEMENT` verdicts), queue invariants, and final classification (`full-consensus` / `partial-consensus` / `contested` / `worker-unique`). For `requirements-discovery`, `error-analysis`, `implementation-planning`, `project-analysis`, `feature-analysis`, and `change-impact-analysis` this phase runs in **adversarial mode** (`convergence.adversarial=true`): verifiers try to refute each finding against its cited evidence and the burden of proof sits on the claim — see that skill's §"Adversarial Verification Mode".
13
13
  - Do NOT conclude "no peer review happens" from the roster alone — every profile that lists ≥2 analyser workers runs convergence by default (`convergence.enabled=true` in `task-manifest.json`).
14
14
  - **provider-unavailable fallback (tolerance).** A worker dispatch can fail to produce a result for two distinct reasons, and both take the same recovery path. (1) **Pane budget:** the dispatch is rejected with `no room for another tmux split` (or an equivalent teammate-pane creation failure). (2) **Sandbox CLI-start failure (non-tmux path):** an external CLI worker wrapper exits non-zero within seconds with empty stdout and its live-log shows `operation not permitted` (e.g. `agy`'s `listen tcp 127.0.0.1:0: bind` under a seatbelt sandbox around a non-tmux subagent's Bash tool). In either case the lead retries that worker in-process without `run_in_background`; if it was an external CLI worker, the lead instead **substitutes** an in-process `claude` analysis. Either way the lead records the substitution as provider unavailable in the run log and the convergence notes. Completed external-CLI worker trace panes are reclaimed automatically by the `SubagentStop` hook, but okstra cannot directly reclaim the teammate panes the harness creates, so this fallback is the last line of defence against pane-budget exhaustion and sandbox-blocked CLI workers. (This is a prompt instruction, not a code-enforced gate.)
15
15
  - Tooling — read-only MCP availability (shared):
@@ -0,0 +1,24 @@
1
+ # Change Impact Analysis Profile
2
+
3
+ - Purpose: assess the read-only impact of a proposed change, including preserved behavior, affected dependencies, and constraints that a later planning phase must resolve
4
+ - Required workers:
5
+ - claude
6
+ - codex
7
+ - report-writer
8
+ - Optional workers (opt-in via `--workers`):
9
+ - antigravity
10
+ {{INCLUDE:_common-contract.md}}
11
+ - Phase 1.5 questions:
12
+ - What user intent and preserved behavior define the proposed change boundary?
13
+ - Which direct and transitive dependencies need impact analysis?
14
+ - Which constraints or open decisions must be passed to implementation-planning?
15
+ - Required report blocks:
16
+ - preserved behavior and impacted items
17
+ - dependency propagation with test and operational impact
18
+ - constraints and open decisions for implementation-planning
19
+ - Cross-verification mode:
20
+ - Phase 5.5 convergence runs in adversarial mode (`convergence.adversarial=true`).
21
+ - Non-goals:
22
+ - source or configuration edits
23
+ - tests, builds, migrations, or deployments
24
+ - implementation alternatives, file change specifications, or execution plans
@@ -0,0 +1,24 @@
1
+ # Feature Analysis Profile
2
+
3
+ - Purpose: analyse a confirmed feature target's behavior, rules, state changes, external calls, and test coverage scope without designing or changing an implementation
4
+ - Required workers:
5
+ - claude
6
+ - codex
7
+ - report-writer
8
+ - Optional workers (opt-in via `--workers`):
9
+ - antigravity
10
+ {{INCLUDE:_common-contract.md}}
11
+ - Phase 1.5 questions:
12
+ - What confirmed target and user intent bound this analysis?
13
+ - Which normal, alternate, and failure flows must be described?
14
+ - Which behavior must be preserved while the feature is analysed?
15
+ - Required report blocks:
16
+ - confirmed target and scope boundary
17
+ - normal, alternate, and failure flows
18
+ - rules, state transitions, external calls, and test coverage scope
19
+ - Cross-verification mode:
20
+ - Phase 5.5 convergence runs in adversarial mode (`convergence.adversarial=true`).
21
+ - Non-goals:
22
+ - source or configuration edits
23
+ - tests, builds, migrations, or deployments
24
+ - implementation alternatives, file change specifications, or execution plans
@@ -14,6 +14,24 @@
14
14
  "free external data fetch beyond the brief's Source Material or Phase 1.5 resolved scope",
15
15
  "interpreting user phrases like `다음 단계 진행해` as authorisation to enter another phase"
16
16
  ],
17
+ "project-analysis": [
18
+ "source or configuration edits",
19
+ "tests, builds, migrations, or deployments",
20
+ "starting any other lifecycle phase inside this run"
21
+ ],
22
+ "feature-analysis": [
23
+ "source or configuration edits",
24
+ "tests, builds, migrations, or deployments",
25
+ "starting any other lifecycle phase inside this run"
26
+ ],
27
+ "change-impact-analysis": [
28
+ "source or configuration edits",
29
+ "tests, builds, migrations, or deployments",
30
+ "starting any other lifecycle phase inside this run",
31
+ "implementation alternatives",
32
+ "file change specifications",
33
+ "stepwise execution plans"
34
+ ],
17
35
  "error-analysis": [
18
36
  "source code edits, refactors, or fix attempts",
19
37
  "implementation design or planning artifacts",
@@ -0,0 +1,24 @@
1
+ # Project Analysis Profile
2
+
3
+ - Purpose: map a bounded project area so later work can navigate components, dependencies, entry points, repositories, and external integrations without changing the source
4
+ - Required workers:
5
+ - claude
6
+ - codex
7
+ - report-writer
8
+ - Optional workers (opt-in via `--workers`):
9
+ - antigravity
10
+ {{INCLUDE:_common-contract.md}}
11
+ - Phase 1.5 questions:
12
+ - Which repositories, directories, and external systems are inside the scan scope?
13
+ - Which components or feature areas must remain shallow rather than receiving a detailed analysis?
14
+ - Which user intent and preserved boundaries constrain this map?
15
+ - Required report blocks:
16
+ - scan scope and excluded areas
17
+ - components, dependency directions, entry points, repositories, and external integrations
18
+ - shallow feature index and unresolved navigation questions
19
+ - Cross-verification mode:
20
+ - Phase 5.5 convergence runs in adversarial mode (`convergence.adversarial=true`).
21
+ - Non-goals:
22
+ - source or configuration edits
23
+ - tests, builds, migrations, or deployments
24
+ - implementation alternatives, file change specifications, or execution plans
@@ -90,7 +90,7 @@
90
90
  }
91
91
  },
92
92
  "task_type_text": {
93
- "label": "Task type? (입력 가능: requirements-discovery, improvement-discovery, error-analysis, implementation-planning, implementation, final-verification, release-handoff)",
93
+ "label": "Task type? (입력 가능: requirements-discovery, improvement-discovery, project-analysis, feature-analysis, change-impact-analysis, error-analysis, implementation-planning, implementation, final-verification, release-handoff)",
94
94
  "echo_template": "task-type: {value}"
95
95
  },
96
96
  "brief_keep": {
@@ -123,6 +123,49 @@
123
123
  "label": "task brief markdown 의 경로를 알려주세요 (project root 기준 상대경로 또는 절대경로)",
124
124
  "echo_template": "brief: {value}"
125
125
  },
126
+ "feature_evidence_pick": {
127
+ "label": "변경 영향 분석에 사용할 수락된 기능 기준선 보고서를 선택하세요.",
128
+ "echo_template": "feature-evidence: {value}",
129
+ "options": {
130
+ "__skip__": "건너뛰기",
131
+ "__free_input__": "다른 보고서 경로 입력"
132
+ },
133
+ "echo_variants": {
134
+ "skip": "feature-evidence: (none)",
135
+ "selected": "feature-evidence: {path}"
136
+ }
137
+ },
138
+ "feature_evidence": {
139
+ "label": "기능 기준선 final-report 경로를 입력하세요.",
140
+ "echo_template": "feature-evidence: {value}"
141
+ },
142
+ "project_evidence_pick": {
143
+ "label": "분석에 사용할 수락된 프로젝트 문맥 보고서를 선택하세요.",
144
+ "echo_template": "project-evidence: {value}",
145
+ "options": {
146
+ "__skip__": "건너뛰기",
147
+ "__free_input__": "다른 보고서 경로 입력"
148
+ },
149
+ "echo_variants": {
150
+ "skip": "project-evidence: (none)",
151
+ "selected": "project-evidence: {path}"
152
+ }
153
+ },
154
+ "project_evidence": {
155
+ "label": "프로젝트 문맥 final-report 경로를 입력하세요.",
156
+ "echo_template": "project-evidence: {value}"
157
+ },
158
+ "analysis_target_pick": {
159
+ "label": "프로젝트 기능 색인에서 분석 대상을 선택하세요.",
160
+ "echo_template": "analysis-target: {value}",
161
+ "options": {
162
+ "__free_input__": "자연어로 대상 입력"
163
+ }
164
+ },
165
+ "analysis_target": {
166
+ "label": "분석할 기능·여정·역량을 자연어로 입력하세요.",
167
+ "echo_template": "analysis-target: {value}"
168
+ },
126
169
  "handoff_stage_pick": {
127
170
  "label": "PR 로 내보낼 범위를 선택하세요 (복수 선택 가능 — 검증 accepted + 미-PR stage 만 표시). 제외된 stage: {blocked}",
128
171
  "echo_template": "handoff-scope: {value}",