okstra 0.214.1 → 0.216.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 (118) hide show
  1. package/README.md +2 -1
  2. package/dist/cli-registry.d.mts +14 -0
  3. package/dist/cli-registry.mjs +12 -0
  4. package/dist/cli-registry.mjs.map +1 -1
  5. package/dist/commands/chat/chat.mjs +2 -56
  6. package/dist/commands/chat/chat.mjs.map +1 -1
  7. package/dist/commands/execute/render-bundle.mjs +5 -2
  8. package/dist/commands/execute/render-bundle.mjs.map +1 -1
  9. package/dist/commands/execute/wizard.mjs +6 -0
  10. package/dist/commands/execute/wizard.mjs.map +1 -1
  11. package/dist/commands/memory/memory.mjs +57 -6
  12. package/dist/commands/memory/memory.mjs.map +1 -1
  13. package/dist/lib/file-lock.d.mts +1 -0
  14. package/dist/lib/file-lock.mjs +60 -0
  15. package/dist/lib/file-lock.mjs.map +1 -0
  16. package/dist/lib/python-command.mjs +11 -1
  17. package/dist/lib/python-command.mjs.map +1 -1
  18. package/dist/lib/skill-catalog.mjs +1 -0
  19. package/dist/lib/skill-catalog.mjs.map +1 -1
  20. package/dist/lib/types.d.mts +1 -1
  21. package/docs/architecture.md +2 -2
  22. package/docs/cli.md +36 -14
  23. package/docs/project-structure-overview.md +6 -3
  24. package/package.json +1 -1
  25. package/runtime/BUILD.json +2 -2
  26. package/runtime/bin/lib/okstra/cli.sh +9 -2
  27. package/runtime/bin/lib/okstra/globals.sh +2 -0
  28. package/runtime/bin/lib/okstra/interactive.sh +8 -2
  29. package/runtime/bin/lib/okstra/usage.sh +3 -1
  30. package/runtime/bin/okstra.sh +7 -1
  31. package/runtime/prompts/duties/discussion-worker.json +32 -0
  32. package/runtime/prompts/lead/convergence.md +58 -136
  33. package/runtime/prompts/lead/okstra-lead-contract.md +45 -12
  34. package/runtime/prompts/profiles/_common-contract.md +1 -1
  35. package/runtime/prompts/wizard/prompts.ko.json +14 -1
  36. package/runtime/python/okstra_ctl/adapters/providers/antigravity/adapter.py +4 -0
  37. package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +4 -11
  38. package/runtime/python/okstra_ctl/agent/invocation.py +1 -0
  39. package/runtime/python/okstra_ctl/agent/prompt_cli/dynamic_verifier.py +2 -2
  40. package/runtime/python/okstra_ctl/agent/prompt_cli/materialize.py +4 -4
  41. package/runtime/python/okstra_ctl/agent/prompt_cli/run_identity.py +2 -2
  42. package/runtime/python/okstra_ctl/analysis_packet.py +3 -0
  43. package/runtime/python/okstra_ctl/consumers.py +8 -2
  44. package/runtime/python/okstra_ctl/convergence.py +143 -29
  45. package/runtime/python/okstra_ctl/convergence_critic_prompt.py +57 -0
  46. package/runtime/python/okstra_ctl/convergence_critic_verify_prompt.py +106 -0
  47. package/runtime/python/okstra_ctl/convergence_engine.py +140 -95
  48. package/runtime/python/okstra_ctl/convergence_reverify_prompt.py +3 -27
  49. package/runtime/python/okstra_ctl/convergence_store.py +11 -4
  50. package/runtime/python/okstra_ctl/dispatch_core.py +4 -1
  51. package/runtime/python/okstra_ctl/domain/role.py +1 -0
  52. package/runtime/python/okstra_ctl/manager_cli.py +27 -1
  53. package/runtime/python/okstra_ctl/manager_launch.py +44 -4
  54. package/runtime/python/okstra_ctl/manager_sync.py +14 -1
  55. package/runtime/python/okstra_ctl/manager_view.py +53 -1
  56. package/runtime/python/okstra_ctl/next_phase.py +1 -0
  57. package/runtime/python/okstra_ctl/phases/catalog.py +2 -1
  58. package/runtime/python/okstra_ctl/phases/discussion/__init__.py +1 -0
  59. package/runtime/python/okstra_ctl/phases/discussion/boundary.json +11 -0
  60. package/runtime/python/okstra_ctl/phases/discussion/cli.py +512 -0
  61. package/runtime/python/okstra_ctl/phases/discussion/entry.py +116 -0
  62. package/runtime/python/okstra_ctl/phases/discussion/followup.py +876 -0
  63. package/runtime/python/okstra_ctl/phases/discussion/memory.py +294 -0
  64. package/runtime/python/okstra_ctl/phases/discussion/overview.py +85 -0
  65. package/runtime/python/okstra_ctl/phases/discussion/profile.json +31 -0
  66. package/runtime/python/okstra_ctl/phases/discussion/profile.md +48 -0
  67. package/runtime/python/okstra_ctl/phases/discussion/report.py +73 -0
  68. package/runtime/python/okstra_ctl/phases/discussion/report_assets/discussion.template.html +15 -0
  69. package/runtime/python/okstra_ctl/phases/discussion/report_assets/discussion.template.md +6 -0
  70. package/runtime/python/okstra_ctl/phases/discussion/spec.md +197 -0
  71. package/runtime/python/okstra_ctl/phases/discussion/store.py +1143 -0
  72. package/runtime/python/okstra_ctl/phases/discussion/validation.py +111 -0
  73. package/runtime/python/okstra_ctl/phases/discussion/wizard.py +90 -0
  74. package/runtime/python/okstra_ctl/phases/discussion/workflow.py +667 -0
  75. package/runtime/python/okstra_ctl/phases/implementation/instructions/_implementation-deliverable.md +1 -1
  76. package/runtime/python/okstra_ctl/phases/implementation_planning/host-rules.md +4 -1
  77. package/runtime/python/okstra_ctl/phases/implementation_planning/instructions/plan-body-verification.md +1 -1
  78. package/runtime/python/okstra_ctl/phases/requirements_discovery/spec.md +1 -1
  79. package/runtime/python/okstra_ctl/plan_run_root.py +8 -0
  80. package/runtime/python/okstra_ctl/render.py +7 -20
  81. package/runtime/python/okstra_ctl/render_final_report.py +2 -1
  82. package/runtime/python/okstra_ctl/report_assembly.py +22 -0
  83. package/runtime/python/okstra_ctl/report_contract.py +2 -0
  84. package/runtime/python/okstra_ctl/report_narrative.py +13 -4
  85. package/runtime/python/okstra_ctl/report_synthesis_packet.py +10 -0
  86. package/runtime/python/okstra_ctl/run.py +40 -7
  87. package/runtime/python/okstra_ctl/stage_close.py +46 -11
  88. package/runtime/python/okstra_ctl/stage_reopen.py +151 -0
  89. package/runtime/python/okstra_ctl/verdict_blocks.py +11 -35
  90. package/runtime/python/okstra_ctl/wizard/cli.py +8 -0
  91. package/runtime/python/okstra_ctl/wizard/confirmation.py +4 -1
  92. package/runtime/python/okstra_ctl/wizard/engine.py +8 -0
  93. package/runtime/python/okstra_ctl/wizard/ids.py +12 -0
  94. package/runtime/python/okstra_ctl/wizard/registry.py +35 -3
  95. package/runtime/python/okstra_ctl/wizard/render.py +4 -1
  96. package/runtime/python/okstra_ctl/wizard/sources.py +2 -2
  97. package/runtime/python/okstra_ctl/wizard/state.py +11 -1
  98. package/runtime/python/okstra_ctl/wizard/steps_identity.py +4 -4
  99. package/runtime/python/okstra_ctl/worker_prompt_policy.py +24 -6
  100. package/runtime/python/okstra_token_usage/pricing.py +2 -0
  101. package/runtime/schemas/convergence-groups-v1.0.schema.json +1 -1
  102. package/runtime/schemas/convergence-groups-v2.0.schema.json +1 -1
  103. package/runtime/schemas/final-report-v3.0.schema.json +90 -1
  104. package/runtime/skills/_fragments/wizard-bash-invocation-rule.md +1 -0
  105. package/runtime/skills/_fragments/wizard-confirm-step.md +7 -0
  106. package/runtime/skills/_fragments/wizard-lead-takeover.md +8 -0
  107. package/runtime/skills/_fragments/wizard-preflight.md +75 -0
  108. package/runtime/skills/_fragments/wizard-prompt-loop.md +22 -0
  109. package/runtime/skills/_fragments/wizard-relay-protocol.md +40 -0
  110. package/runtime/skills/_fragments/wizard-render-bundle.md +74 -0
  111. package/runtime/skills/okstra-discussion/SKILL.md +347 -0
  112. package/runtime/skills/okstra-pr-gen/SKILL.md +7 -0
  113. package/runtime/skills/okstra-run/SKILL.md +22 -2
  114. package/runtime/templates/manager/view.template.html +3 -0
  115. package/runtime/templates/reports/html/i18n/en.json +5 -0
  116. package/runtime/templates/reports/html/i18n/ko.json +5 -0
  117. package/runtime/validators/validate-brief.py +3 -2
  118. package/runtime/validators/validate-run.py +4 -6
@@ -58,9 +58,43 @@ Every `okstra` command the lead documents cite, grouped by phase, each spelled w
58
58
  | `okstra incremental-scope --prev-data <path>` | Decide re-verify vs carry-forward stages on a clarification re-run | launch prompt "Incremental re-verification" |
59
59
  | `okstra incremental-carry --prev-data <path> --prev-seq <seq> --cur-narrative <path>` | Merge carried-forward plan-item verdicts after `plan-items seed` | launch prompt "Incremental re-verification" |
60
60
  | `okstra stage-map <task-key>` | Read the prior Stage Map and done stages before re-planning | host orchestration rules (implementation-planning) |
61
- | `okstra stage-close <task-key> --stage <N> --from-commit <sha>` | Close a stage whose work already landed outside okstra | host orchestration rules (implementation-planning) |
61
+ | `okstra stage-close <task-key> --stage <N> --from-commit <sha> [--supersede-failed <reason>]` | Close a stage whose work already landed outside okstra, or a `failed` stage whose failure no longer applies |
62
+ | `okstra stage-reopen <task-key> --stage <N> --reason <why> [--evidence <report>]` | Reopen a `done` stage for a fix run, e.g. after a `blocked` final-verification of that stage | host orchestration rules (implementation-planning) |
62
63
  | `okstra git-reconcile --plan-run-root <dir> --project-id <id> --task-group <group> --task-id <id> --work-category <category>` | Detect (`--check --text`) or record (`--apply --stage <N> --use-ref <ref>`) stage SHAs made stale by git history outside okstra | host orchestration rules (implementation) |
63
64
 
65
+ ### discussion — the discussion record
66
+
67
+ | Command | Use when | Procedure |
68
+ |---|---|---|
69
+ | `okstra discussion confirm-subject <task-key> --subject <what> --question <to-settle> --run-manifest <path>` | The user confirmed the subject and the question to settle | discussion `profile.md` "Facilitator" |
70
+ | `okstra discussion ask <task-key> --author <leader-or-worker-id> --text <question> --run-manifest <path>` | Register a question for the user before putting it to the user | discussion `profile.md` "Facilitator" |
71
+ | `okstra discussion address <task-key> --to <worker-id> --text <question> --run-manifest <path>` | The user asked one participant directly | discussion `profile.md` "Facilitator" |
72
+ | `okstra discussion answer <task-key> --question <Q-NNNN> --author <user-or-worker-id> --text <answer> --run-manifest <path>` | Record the addressee's answer; resending it returns the stored record | discussion `profile.md` "Facilitator" |
73
+ | `okstra discussion decide <task-key> --text <decision> --run-manifest <path>` | Record a user decision; add `--question <Q-NNNN>` when it settles a question | discussion `profile.md` "Facilitator" |
74
+ | `okstra discussion add-material <task-key> --kind <evidence-or-alternative> --author <user-leader-or-worker-id> --text <what> --run-manifest <path>` | New evidence or a new alternative arrived; it becomes an input reference of the next research cycle | discussion `profile.md` "Facilitator" |
75
+ | `okstra discussion draft <task-key>` | Read the record every participant gets as its next input | discussion `profile.md` "Facilitator" |
76
+ | `okstra discussion status <task-key>` | On entry and on resume: the phase, the one question to put to the user next, unrecovered failures and remaining disagreements | discussion `profile.md` "Facilitator" |
77
+ | `okstra discussion cycle-open <task-key> --run-manifest <path>` | Before dispatching research: `dispatch` names the research instruction for every analyser; any other action says why nothing is dispatched | discussion `profile.md` "Research cycle" |
78
+ | `okstra discussion settle <task-key> --run-manifest <path>` | After the research batch settled: record each analyser's result and each failure left after the dispatcher's retry loop | discussion `profile.md` "Research cycle" |
79
+ | `okstra discussion recover <task-key> --failure <X-NNNN> --choice <retry-replace-or-reduce> --run-manifest <path>` | Record the user's choice for one failure; never choose for the user | discussion `profile.md` "Failures" |
80
+ | `okstra discussion cycle-close <task-key> --run-manifest <path>` | After `okstra convergence finalize`: import the claims with their authors and verdicts and end the verification cycle | discussion `profile.md` "Research cycle" |
81
+ | `okstra discussion question-prompt <task-key> --question <Q-NNNN> --run-manifest <path>` | The user addressed one participant: write that question's instruction and materialize batch | discussion `profile.md` "Direct questions" |
82
+ | `okstra discussion collect-answer <task-key> --question <Q-NNNN> --run-manifest <path>` | After the direct-question dispatch settled: record the whole result as the answer, or the failure | discussion `profile.md` "Direct questions" |
83
+ | `okstra discussion add-requirement <task-key> --text <requirement> --author <user-leader-or-worker-id> --run-manifest <path>` | A requirement of the current draft is settled; add `--applies-to <follow-up-label>` when only one follow-up needs it | discussion `profile.md` "Completion" |
84
+ | `okstra discussion add-scope <task-key> --kind <in-scope-or-excluded> --text <what> --author <user-leader-or-worker-id> --run-manifest <path>` | An in-scope or excluded item of the current draft is settled; record an explicit `none` when nothing is excluded | discussion `profile.md` "Completion" |
85
+ | `okstra discussion withdraw <task-key> --item <N-NNNN-or-B-NNNN> --reason <why> --run-manifest <path>` | The user drops a requirement or scope item from the current draft, including one carried from the reopened revision; to replace an item, withdraw it and add the new one | discussion `profile.md` "Completion" |
86
+ | `okstra discussion confirm-completion <task-key> --draft-version <sha256-digest> --direction <direction> --risk <accepted-risks> --run-manifest <path>` | The user saw the draft at that version, chose the direction and confirmed the remaining disagreements and risks: publish the immutable revision | discussion `profile.md` "Completion" |
87
+ | `okstra discussion reopen <task-key> --revision <revision-id> --reason <why> --run-manifest <path>` | The user wants to change a completed discussion: open a new draft on top of the latest revision | discussion `profile.md` "Completion" |
88
+ | `okstra discussion revisions <task-key>` | List the published revisions with their content digests | discussion `profile.md` "Completion" |
89
+ | `okstra discussion revision-show <task-key> --revision <revision-id>` | Print one published revision byte-for-byte | discussion `profile.md` "Completion" |
90
+ | `okstra discussion record <task-key>` | The user wants the whole discussion record, every research result in full | discussion `profile.md` "Completion" |
91
+ | `okstra discussion memory-sync <task-key>` | `status` lists a revision under `memoryRegistration` that the Memory Book does not hold yet: retry its registration with the same source key; after a secret refusal, add `--revision <revision-id> --summary-file <path>` only with the summary the user edited | discussion `profile.md` "Completion" |
92
+ | `okstra discussion follow-up-brief <task-key> --revision <revision-id> --follow-up <label> --target-task <follow-up-task-key> --end-state <N-NNNN>=<EB-PB-or-EO>` | After a revision is published, the user asks for one follow-up task's brief; repeat `--end-state` per requirement and add `:<how to observe it>` when the revision gives no observation method; add `--target-project-root <dir>` for a follow-up in another project | discussion `profile.md` "Follow-ups" |
93
+ | `okstra discussion links <task-key>` | Show the linked follow-ups and which of them need the user's impact review | discussion `profile.md` "Follow-ups" |
94
+ | `okstra discussion impact <task-key> --from <revision-id> --to <revision-id>` | Show what changed between two revisions; add `--follow-up <label>` for one follow-up | discussion `profile.md` "Follow-ups" |
95
+ | `okstra discussion apply <task-key> --revision <latest-revision-id> --target-task <follow-up-task-key> --choice <adopt-or-keep>` | Record the user's choice for one follow-up; never choose for the user | discussion `profile.md` "Follow-ups" |
96
+ | `okstra discussion complete-amendment <task-key> --revision <revision-id> --target-task <follow-up-task-key>` | `links` shows a follow-up `amendment-pending` whose `next` names this command: the user approved the amended plan, so move the follow-up's brief to the revision; a refusal names what is still missing | discussion `profile.md` "Follow-ups" |
97
+
64
98
  ### Any phase — progress, activity, errors, approval
65
99
 
66
100
  | Command | Use when | Procedure |
@@ -108,10 +142,11 @@ Every `okstra` command the lead documents cite, grouped by phase, each spelled w
108
142
  | `okstra convergence seed --groups <path> --work-state <path> --final-state <path> --migration-dir <dir>` | Create, resume, or recover the working state | `convergence` "Round 0" |
109
143
  | `okstra convergence plan-round --work-state <path> --plan <path>` | Write the next round's dispatch plan | `convergence` "Round 1-N" |
110
144
  | `okstra convergence reverify-prompt --run-manifest <path> --plan <path> --worker <worker>` | Print one worker's reverify instructions; never compose them by hand | `convergence` "Re-verification Dispatch" |
111
- | `okstra convergence collect-results --plan <path> --mode <mode> --run-manifest <path> --output <path>` | Read one round's responses into the apply-round input | `convergence` "Round 1-N" |
145
+ | `okstra convergence collect-results --plan <path> --result <worker>=<path> --run-manifest <path> --output <path>` | Read one round's responses into the apply-round input | `convergence` "Round 1-N" |
112
146
  | `okstra convergence apply-round --work-state <path> --plan <path> --results <path>` | Apply a round's results | `convergence` "Round 1-N" |
113
- | `okstra convergence critic-prompt --run-manifest <path>` | Print the coverage-critic instructions; dispatch concurrently with the first reverify round | `convergence` "Coverage critic pass" |
114
- | `okstra convergence critic-verify-prompt --run-manifest <path> --gaps <path> --worker <worker>` | Print one analyser's gap-verification instructions | `convergence` "Gap verification" |
147
+ | `okstra convergence critic-prompt --run-manifest <path>` | Print the critic instructions (acceptance on `final-verification`, coverage elsewhere); dispatch concurrently with the first reverify round | `convergence` "Coverage critic pass" |
148
+ | `okstra convergence critic-verify-prompt --run-manifest <path> --gaps <path> --worker <worker>` | Print one analyser's gap-verification or acceptance-candidate instructions | `convergence` "Gap verification", "Acceptance critic pass" |
149
+ | `okstra convergence collect-acceptance-votes --run-manifest <path> --candidates <path> --result <worker>=<path> --output <path>` | Derive confirmed/downgraded per acceptance candidate from the analysers' responses | `convergence` "Acceptance critic pass" |
115
150
  | `okstra convergence apply-critic-gaps --work-state <path> --results <path>` | Apply the gap-verification batch once, before `finalize` | `convergence` "Coverage critic pass" |
116
151
  | `okstra convergence apply-acceptance-critic --work-state <path> --results <path>` | Record the final-verification acceptance-critic accounting | `convergence` "Acceptance critic pass" |
117
152
  | `okstra convergence finalize --work-state <path> --output <path>` | Write the public final state after every round and critic batch is applied | `convergence` "Round 1-N" |
@@ -196,6 +231,7 @@ A single okstra run executes **exactly one** lifecycle phase. The phase is given
196
231
  | `final-verification` | acceptance verdict, residual risk, regression notes; read-only execution of existing test/validation commands, run-artifact writes (qa result sidecars, `okstra handoff record-verified` on acceptance), and qaEnv-replica-only conformance runs are permitted | source code edits, refactors, scope expansion, mutations of the project or shared environments |
197
232
  | `release-handoff` | user-selected packaging only: PR creation / push of the implementation branch, handoff summary (lead-only phase) | local commits, history-rewriting pushes, direct pushes to a base branch, release-publishing commands, source edits, worker dispatch of any kind |
198
233
  | `improvement-discovery` *(sidetrack — outside `PHASE_SEQUENCE`)* | lens-scoped improvement candidates (`## 5.9` report), per-candidate next-phase recommendation | code edits, planning or root-cause work, candidates outside the lens allowlist or beyond the cap, starting any lifecycle phase inside this run |
234
+ | `discussion` *(sidetrack — outside `PHASE_SEQUENCE`)* | the lead facilitates: researched evidence, assumptions and alternatives, user questions one at a time, recorded user decisions, remaining disagreements and risks; completion only on the user's confirmation | code edits, detailed implementation plans, state-mutating commands, treating agent consensus or a convergence stop as completion, starting a follow-up task or any lifecycle phase inside this run |
199
235
 
200
236
  Phase-transition checklist (lead, end of run):
201
237
 
@@ -407,7 +443,7 @@ examples and critic-specific procedures; the conditional reading table in the
407
443
  output identifies when those sections are needed:
408
444
 
409
445
  ```sh
410
- awk '/^### Lightweight Re-verification Prompt$/ {skip=1} /^## Convergence State Artifact$/ {skip=0} /^## Coverage critic pass$/ {skip=1} /^## Output$/ {skip=0} !skip {print}' '<convergence-contract-path>'
446
+ awk '/^### Adversarial Re-verification Prompt$/ {skip=1} /^## Convergence State Artifact$/ {skip=0} /^## Coverage critic pass$/ {skip=1} /^## Output$/ {skip=0} !skip {print}' '<convergence-contract-path>'
411
447
  ```
412
448
 
413
449
  `tests/contract/test_contract_examples_execute.py::test_convergence_common_read_keeps_protocol`
@@ -530,11 +566,10 @@ The deterministic dispatcher records this through its selected adapter — Lead
530
566
  Convergence is enabled by default. Configure via task-manifest.json:
531
567
 
532
568
  - `convergence.enabled`: true/false (default: true)
533
- - `convergence.maxRounds`: 1–3 — **phase-aware default**: `1` for `requirements-discovery`, `2` for all other task types
534
- - `convergence.verificationMode`: `"lightweight"` | `"full-reanalysis"` (default: `"lightweight"`; the adversarial phases below force `"full-reanalysis"`)
535
- - `convergence.adversarial`: true/false — **phase-aware default**: `true` for `requirements-discovery` / `error-analysis` / `implementation-option-selection` / `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".
569
+ - `convergence.maxRounds`: 1–3 — default `2`
570
+ - `convergence.adversarial` is always `true` and `convergence.verificationMode` always `"full-reanalysis"`: every phase runs Phase 5.5 in adversarial mode (verifiers refute findings; burden of proof on the claim). See [convergence](./convergence.md) "Adversarial Verification Mode".
536
571
 
537
- 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`.
572
+ When `task-manifest.json` does not set `convergence.maxRounds`, lead MUST resolve the effective value via the default above before entering Phase 5.5 and put it in the grouped input at `config.effectiveMaxRounds`.
538
573
 
539
574
  The lead judges semantic similarity, ticket-set equality, and evidence. After writing the grouped input, it drives `okstra convergence seed → plan-round → apply-round → finalize → validate` and MUST NOT calculate queue membership, classification, history arithmetic, skip reasons, final state, or counts itself. `ConvergenceEngine` owns all of those deterministic transitions.
540
575
 
@@ -643,14 +678,12 @@ The run-level error log lives at `<runDir>/logs/errors-<task-type>-<seq>.jsonl`.
643
678
  | Ignoring task bundle model assignments | Task bundle overrides are canonical |
644
679
  | Inserting per-worker emphasis sentences ("you focus on X") into dispatch prompts | Send byte-identical dispatch prompts per [team-contract](./team-contract.md) "Dispatch-prompt invariant" — specialization lives in Section 7 of the worker output, not the prompt body |
645
680
  | Omitting contested or worker-unique findings | All categories must appear in the report |
646
- | Running full re-analysis when lightweight suffices | Default lightweight; full only when manifest opts in |
647
681
  | Using `/tmp/*prompt*.txt` for worker prompt persistence | Persist the exact worker prompt to the assigned run-level `prompts/` path |
648
682
  | Lead writes `final-report-<suffix>.md` itself when `Report writer worker` is in the roster | Dispatch the Report writer worker per [report-writer](./report-writer.md) "Phase 6 dispatch template" |
649
683
  | Skipping Report writer worker dispatch citing "session resume constraint" or "team is gone" | No such constraint exists — see [report-writer](./report-writer.md) "Resume-safe dispatch" |
650
684
  | Selecting a generic worker assignment for Report writer worker | Use the rostered `report-writer-worker` assignment; the selected adapter owns its native field mapping |
651
685
  | Including `final-report-template.md` in analysis worker `[Required reading]` | Template belongs only in the report-writer prompt — see [team-contract](./team-contract.md) audience-scoped enumeration |
652
- | Injecting `[Required reading]` into lightweight reverify prompts | Lightweight reverify forbids re-reading source materials — see [convergence](./convergence.md) "Reverify prompt: required-reading suppression" |
653
- | Letting `convergence.maxRounds` default to 2 for `requirements-discovery` | Resolve effective default to `1` for discovery and put it in the grouped input |
686
+ | Injecting `[Required reading]` into reverify prompts | A reverify reads only the cited evidence — see [convergence](./convergence.md) "Reverify prompt: required-reading suppression" |
654
687
  | Issuing serial Read calls in Phase 1 | The intake files are independent — issue all Read calls in a single message (parallel) |
655
688
  | Running `agent-prompt materialize`, `jobs`, or a jobs-file dispatcher once per `runner=cli-wrapper` worker of a batch | One `okstra agent-prompt materialize --project-root <dir> --run-manifest <path> --batch <file> --jobs-out <jobs-file>` call per batch, chained with the dispatcher the execution surface selects (`okstra team dispatch` on `cmux-pane`, `okstra worker-dispatch` otherwise) and `--jobs-file <jobs-file>`. Native-session rows still dispatch one host call per row — see [convergence](./convergence.md) "Invocation materialization gate" |
656
689
  | Flagging an adapter-shortened dispatch prompt as "incomplete" because it omits host-loaded material | The Worker Preamble pointer and core inputs remain mandatory; the selected adapter may omit duplicate host-loaded definitions |
@@ -9,7 +9,7 @@ profile document.
9
9
  - Worker interaction model (shared — read before inferring behaviour from the roster):
10
10
  - the run's selected roster 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)**: every analyser in the resolved provider assignment roster produces findings independently and has no access to another worker's output. `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` / `unverified`). For `requirements-discovery`, `error-analysis`, `implementation-option-selection`, `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".
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, `SURVIVES` / `SURVIVES-WITH-CAVEAT` / `REFUTED` / `UNVERIFIABLE` verdicts), queue invariants, and final classification (`full-consensus` / `partial-consensus` / `contested` / `worker-unique` / `unverified`). Every phase runs it 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
  - For a new `implementation-planning` run, the plan-body sequence is initial verification → one planner self-fix → targeted re-verification → user gate. The initial verification is round 1, the targeted re-verification is round 2, and a second automatic self-fix is a contract violation. A user-directed correction does not consume the automatic self-fix limit, and a verification failure after that correction does not restart the automatic loop.
15
15
  - **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 because a teammate pane could not be created — this is the harness running out of room for its own teammate panes, not okstra placing a worker. The wording is the host's, so match the condition rather than a fixed string. (2) **Sandbox CLI-start failure:** an external CLI worker wrapper exits non-zero within seconds with empty stdout and its live-log shows `operation not permitted`. In either case the lead spends the one shared retry budget through the assignment's recorded runner. If the provider is still unavailable, record that terminal status and continue only under the convergence quorum rules; never replace it silently with a fixed provider or count a substitute as the original provider's vote. Completed external-CLI workers hold no pane of their own. A pane the harness opened for its own teammate carries no id okstra recorded, so no okstra command closes it — the host and the user own that surface. (This is a prompt instruction, not a code-enforced gate.)
@@ -96,7 +96,7 @@
96
96
  }
97
97
  },
98
98
  "task_type_text": {
99
- "label": "Task type? (입력 가능: requirements-discovery, improvement-discovery, project-analysis, feature-analysis, change-impact-analysis, error-analysis, implementation-option-selection, implementation-planning, implementation, final-verification, release-handoff)",
99
+ "label": "Task type? (입력 가능: requirements-discovery, improvement-discovery, project-analysis, feature-analysis, change-impact-analysis, error-analysis, implementation-option-selection, implementation-planning, implementation, final-verification, release-handoff, discussion)",
100
100
  "echo_template": "task-type: {value}"
101
101
  },
102
102
  "selected_direction_pick": {
@@ -223,6 +223,19 @@
223
223
  "abort": "brief-carry: 중단"
224
224
  }
225
225
  },
226
+ "discussion_start_pick": {
227
+ "label": "무엇에 대한 토론을 시작할까요? discussion 은 brief 대신 이 시작 입력을 받고, 진행자가 토론 대상과 해결할 질문을 먼저 확인합니다.",
228
+ "echo_template": "discussion-start: {value}",
229
+ "options": {
230
+ "__continue__": "이 task 의 토론 이어가기 — {task_key} (마지막 결정·대기 질문 복원)",
231
+ "__brief__": "이 brief 를 시작 입력으로 — {brief}",
232
+ "__free_input__": "티켓·프로젝트 링크 또는 짧은 설명 직접 입력"
233
+ }
234
+ },
235
+ "discussion_start": {
236
+ "label": "토론 시작 입력: 티켓·프로젝트 링크(URL 또는 프로젝트 안 파일 경로)나 토론할 내용을 짧게 입력하세요.",
237
+ "echo_template": "discussion-start: {value}"
238
+ },
226
239
  "base_ref_pick": {
227
240
  "label": "이 task 의 base branch?",
228
241
  "echo_template": "base-ref: {value}",
@@ -33,6 +33,10 @@ ANTIGRAVITY = {
33
33
  "gemini-3.1-pro", "Gemini 3.1 Pro", "gemini-3.1-pro",
34
34
  aliases=("gemini 3.1 pro",),
35
35
  ),
36
+ "gemini-4-argon": ModelSpec(
37
+ "gemini-4-argon", "Gemini 4 Argon", "gemini-4-argon",
38
+ aliases=("gemini 4 argon",),
39
+ ),
36
40
  "gemini-3.8-flash": ModelSpec(
37
41
  "gemini-3.8-flash", "Gemini 3.8 Flash", "gemini-3.8-flash",
38
42
  aliases=("gemini 3.8 flash",),
@@ -44,7 +44,7 @@ CLAUDE = {
44
44
  # opus 채널이 지금 서빙하는 점-릴리스. 엔트리가 없으면 served-model 게이트가
45
45
  # 관측값을 카탈로그에서 못 찾아 dispatch 가 exit 78 로 실패한다 — 실측
46
46
  # 2026-09-23, 두 프로젝트에서 `claude-opus-5-5` 로 같은 실패(dev-10860
47
- # stage-3·4·5). haiku-4-5-20251001 과 같은 이유의 엔트리다.
47
+ # stage-3·4·5).
48
48
  "opus-5-5": ModelSpec(
49
49
  "opus-5-5", "opus-5-5", "claude-opus-5-5", aliases=("claude-opus-5-5",),
50
50
  channel_family="opus", selectable=False,
@@ -66,16 +66,9 @@ CLAUDE = {
66
66
  "haiku": ModelSpec(
67
67
  "haiku", "haiku", "haiku", version_kind="channel", channel_family="haiku"
68
68
  ),
69
- # picker 에서는 감춘다(사유는 fable-5 와 동일).
70
- "haiku-4-5": ModelSpec(
71
- "haiku-4-5", "haiku-4-5", "claude-haiku-4-5", aliases=("claude-haiku-4-5",),
72
- channel_family="haiku", selectable=False,
73
- ),
74
- # 구버전이 아니라 haiku 채널이 실제로 서빙하는 날짜-고정 id 다. 이 엔트리가
75
- # 없으면 served-model 게이트가 관측값을 카탈로그에서 못 찾아 dispatch 가
76
- # "served model is not in the catalog" 로 실패한다(dispatch_core.py).
77
- "haiku-4-5-20251001": ModelSpec(
78
- "haiku-4-5-20251001", "haiku-4-5", "claude-haiku-4-5-20251001",
69
+ # haiku 채널이 서빙하는 점-릴리스(opus-5-5 와 같은 이유).
70
+ "haiku-5-5": ModelSpec(
71
+ "haiku-5-5", "haiku-5-5", "claude-haiku-5-5", aliases=("claude-haiku-5-5",),
79
72
  channel_family="haiku", selectable=False,
80
73
  ),
81
74
  }
@@ -29,6 +29,7 @@ AgentAudience = Literal[
29
29
  "discovery-worker",
30
30
  "diagnosis-worker",
31
31
  "technical-verification-worker",
32
+ "discussion-worker",
32
33
  "planning-worker",
33
34
  "direction-selection-worker",
34
35
  "implementation-executor",
@@ -28,7 +28,7 @@ from ...convergence_store import (
28
28
  from ...worker_prompt_policy import (
29
29
  CRITIC_VERIFY_DISPATCH_KIND,
30
30
  PLAN_VERIFY_DISPATCH_KIND_PREFIX,
31
- is_plan_critic_verification,
31
+ is_critic_verification,
32
32
  verification_dispatch_round,
33
33
  )
34
34
  from .inputs import AgentPromptCliError
@@ -82,7 +82,7 @@ def _dynamic_verifier_source(
82
82
  and manifest.get("executionIdentityVersion") == 2
83
83
  )
84
84
  is_reverify = (
85
- (args.assignment_ref.startswith("reverify/") or is_plan_critic_verification(
85
+ (args.assignment_ref.startswith("reverify/") or is_critic_verification(
86
86
  task_type=str(manifest.get("taskType", "")),
87
87
  assignment_ref=args.assignment_ref, dispatch_kind=args.dispatch_kind,
88
88
  ))
@@ -40,7 +40,7 @@ from ...worker_prompt_contract import (
40
40
  )
41
41
  from ...worker_prompt_policy import (
42
42
  critic_assignment_ref,
43
- is_plan_critic_verification,
43
+ is_critic_verification,
44
44
  is_verification_dispatch_kind,
45
45
  )
46
46
  from ...paths import okstra_home
@@ -278,15 +278,15 @@ def _materialize_run(
278
278
  if (
279
279
  args.assignment_ref == "reverify/critic-worker"
280
280
  and critic_ref in assignments
281
- and is_plan_critic_verification(
281
+ and is_critic_verification(
282
282
  task_type=str(manifest.get("taskType", "")),
283
283
  assignment_ref=critic_ref, dispatch_kind=args.dispatch_kind,
284
284
  )
285
285
  ):
286
286
  recovery = (
287
- f"; for the rostered plan critic, use --assignment-ref {critic_ref} "
287
+ f"; for the rostered critic, use --assignment-ref {critic_ref} "
288
288
  "with --worker-id critic-worker and --audience reverification-worker. "
289
- "Keep the plan-verify-r<N> dispatch kind and, on v2 runs, the selected "
289
+ f"Keep the {args.dispatch_kind} dispatch kind and, on v2 runs, the selected "
290
290
  "critic's --source-role-execution-ref. This is a reference correction; "
291
291
  "the existing critic assignment does not need to be added or changed"
292
292
  )
@@ -10,7 +10,7 @@ from typing import Any, Mapping
10
10
 
11
11
  from ...worker_prompt_policy import (
12
12
  CRITIC_DUTY_BY_ASSIGNMENT_SEGMENT,
13
- is_plan_critic_verification,
13
+ is_critic_verification,
14
14
  resolve_prompt_plan_for_manifest,
15
15
  )
16
16
  from .inputs import AgentPromptCliError
@@ -36,7 +36,7 @@ def _validate_run_identity(
36
36
  elif assignment_ref.startswith("critic/"):
37
37
  scope = assignment_ref.split("/", 1)[1]
38
38
  expected = CRITIC_DUTY_BY_ASSIGNMENT_SEGMENT.get(scope, "")
39
- if is_plan_critic_verification(
39
+ if is_critic_verification(
40
40
  task_type=str(manifest.get("taskType", "")),
41
41
  assignment_ref=assignment_ref, dispatch_kind=dispatch_kind,
42
42
  ):
@@ -84,6 +84,9 @@ WORKER_PROFILE_SECTIONS_BY_TASK_TYPE = {
84
84
  # while the aggregate still looks complete.
85
85
  "Worker diversity rule",
86
86
  ),
87
+ "discussion": (
88
+ "Worker research procedure",
89
+ ),
87
90
  }
88
91
  CLARIFICATION_SECTIONS = (
89
92
  "Clarification Items",
@@ -139,7 +139,8 @@ def append_consumer(plan_run_root: Path, *, impl_task_key: str, stage: int,
139
139
  with consumers_mutex(plan_run_root):
140
140
  if not _equivalent_row_exists(plan_run_root, impl_task_key, stage,
141
141
  status, force_reappend,
142
- fields.get("head_commit")):
142
+ fields.get("head_commit"),
143
+ fields.get("source")):
143
144
  record: Dict[str, Any] = {
144
145
  "impl_task_key": impl_task_key,
145
146
  "stage": stage,
@@ -157,7 +158,7 @@ def append_consumer(plan_run_root: Path, *, impl_task_key: str, stage: int,
157
158
 
158
159
  def _equivalent_row_exists(plan_run_root: Path, impl_task_key: str, stage: int,
159
160
  status: str, force_reappend: bool,
160
- head_commit: Any) -> bool:
161
+ head_commit: Any, source: Any = None) -> bool:
161
162
  rows = read_consumers(plan_run_root)
162
163
  # 같은 tuple 이 이미 있어도, 그 뒤에 다른 lifecycle row 가 왔다면 이 append 는
163
164
  # stage 의 현재 위치를 옮기는 새 사실이다 — fix run 의 started 재기록이 그 경우다.
@@ -167,6 +168,11 @@ def _equivalent_row_exists(plan_run_root: Path, impl_task_key: str, stage: int,
167
168
  if (row.get("impl_task_key") == impl_task_key
168
169
  and row.get("stage") == stage
169
170
  and row.get("status") == status):
171
+ # backfill 행은 리드가 쓸 행의 대역이라 `report_path`·`completed_at` 이
172
+ # 없다. 리드의 행이 그 뒤에 붙어야 최신 done 행이 보고서를 가리킨다.
173
+ if (row.get("source") == "carry-backfill"
174
+ and source != "carry-backfill"):
175
+ continue
170
176
  if not force_reappend:
171
177
  return True
172
178
  if row.get("head_commit") == head_commit: