okstra 0.206.1 → 0.207.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 (73) hide show
  1. package/README.md +1 -1
  2. package/dist/cli-registry.mjs +7 -1
  3. package/dist/cli-registry.mjs.map +1 -1
  4. package/docs/architecture/storage-model.md +1 -0
  5. package/docs/architecture.md +28 -4
  6. package/docs/cli.md +13 -11
  7. package/docs/project-structure-overview.md +4 -2
  8. package/package.json +1 -1
  9. package/runtime/BUILD.json +2 -2
  10. package/runtime/agents/operations/code-review.json +1 -1
  11. package/runtime/bin/lib/okstra/usage.sh +3 -3
  12. package/runtime/bin/okstra-compact-reminder.sh +1 -1
  13. package/runtime/prompts/duties/direction-selection-worker.json +1 -1
  14. package/runtime/prompts/launch.template.md +1 -1
  15. package/runtime/prompts/lead/adapters/cmux.md +4 -3
  16. package/runtime/prompts/lead/convergence.md +41 -9
  17. package/runtime/prompts/lead/okstra-lead-contract.md +31 -19
  18. package/runtime/prompts/lead/report-writer.md +8 -6
  19. package/runtime/prompts/profiles/_clarification-recommendation.md +4 -4
  20. package/runtime/prompts/profiles/_common-contract.md +1 -1
  21. package/runtime/prompts/wizard/prompts.ko.json +2 -1
  22. package/runtime/python/okstra_ctl/adapters/hosts/antigravity/relay.md +1 -1
  23. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/relay.md +5 -5
  24. package/runtime/python/okstra_ctl/adapters/hosts/codex/relay.md +1 -1
  25. package/runtime/python/okstra_ctl/adapters/hosts/external/relay.md +3 -2
  26. package/runtime/python/okstra_ctl/adapters/hosts/grok/relay.md +1 -1
  27. package/runtime/python/okstra_ctl/adapters/hosts/kimi/relay.md +1 -1
  28. package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +17 -26
  29. package/runtime/python/okstra_ctl/agent/prompt_cli/batch.py +183 -0
  30. package/runtime/python/okstra_ctl/agent/prompt_cli/cli.py +60 -10
  31. package/runtime/python/okstra_ctl/agent/prompt_cli/jobs.py +21 -4
  32. package/runtime/python/okstra_ctl/approval_decisions.py +32 -2
  33. package/runtime/python/okstra_ctl/assignment_resolver.py +8 -0
  34. package/runtime/python/okstra_ctl/blocking_checks.py +7 -0
  35. package/runtime/python/okstra_ctl/code_review_target.py +92 -6
  36. package/runtime/python/okstra_ctl/dispatch_checkpoints.py +121 -0
  37. package/runtime/python/okstra_ctl/dispatch_core.py +54 -32
  38. package/runtime/python/okstra_ctl/dispatch_state.py +12 -5
  39. package/runtime/python/okstra_ctl/domain/provider.py +5 -0
  40. package/runtime/python/okstra_ctl/domain/worker_presentation.py +21 -2
  41. package/runtime/python/okstra_ctl/domain/write_policy.py +2 -1
  42. package/runtime/python/okstra_ctl/execution_mutation_audit.py +19 -8
  43. package/runtime/python/okstra_ctl/initial_prompt_materialization.py +5 -0
  44. package/runtime/python/okstra_ctl/lead_progress.py +33 -1
  45. package/runtime/python/okstra_ctl/manager_view.py +26 -19
  46. package/runtime/python/okstra_ctl/model_io/lines.py +21 -4
  47. package/runtime/python/okstra_ctl/models.py +4 -1
  48. package/runtime/python/okstra_ctl/operation_invocation.py +11 -2
  49. package/runtime/python/okstra_ctl/phases/final_verification/profile.md +1 -1
  50. package/runtime/python/okstra_ctl/phases/implementation/instructions/_implementation-executor.md +1 -1
  51. package/runtime/python/okstra_ctl/phases/implementation/instructions/_implementation-verifier.md +14 -3
  52. package/runtime/python/okstra_ctl/phases/implementation_option_selection/profile.md +1 -1
  53. package/runtime/python/okstra_ctl/phases/implementation_planning/profile.md +1 -1
  54. package/runtime/python/okstra_ctl/phases/technical_verification/profile.md +1 -1
  55. package/runtime/python/okstra_ctl/process_group.py +118 -0
  56. package/runtime/python/okstra_ctl/render.py +6 -2
  57. package/runtime/python/okstra_ctl/report_assembly.py +17 -2
  58. package/runtime/python/okstra_ctl/report_finalize.py +106 -2
  59. package/runtime/python/okstra_ctl/run.py +1 -1
  60. package/runtime/python/okstra_ctl/run_artifact_prune.py +200 -0
  61. package/runtime/python/okstra_ctl/team.py +108 -9
  62. package/runtime/python/okstra_ctl/wizard/steps_options.py +8 -0
  63. package/runtime/python/okstra_ctl/worker_dispatch.py +44 -3
  64. package/runtime/python/okstra_ctl/worker_prompt_policy.py +19 -0
  65. package/runtime/python/okstra_ctl/worker_runner.py +21 -3
  66. package/runtime/python/okstra_ctl/write_policy.py +57 -7
  67. package/runtime/python/okstra_project/dirs.py +14 -0
  68. package/runtime/python/okstra_project/resolver.py +2 -1
  69. package/runtime/schemas/execution-manifest-v2.schema.json +2 -1
  70. package/runtime/skills/okstra-code-review/SKILL.md +70 -32
  71. package/runtime/skills/okstra-code-review/references/review-calibration.md +26 -6
  72. package/runtime/skills/okstra-run/SKILL.md +2 -2
  73. package/runtime/templates/manager/view.template.html +18 -1
@@ -18,11 +18,16 @@ A cell covers its whole rule group, so it can carry several findings from severa
18
18
  rule: DRY
19
19
  line: 42
20
20
  severity: must-fix
21
+ timing: now
21
22
  snippet: `discount = subtotal * 0.15 if tier == "gold" else 0`
23
+ failure: when the gold rate changes in `domain/tiers.py`, this line keeps charging 15% and the two prices disagree.
24
+ evidence: `domain/tiers.py:18`
22
25
  note: The same tier→rate table is already in `domain/tiers.py:18`; a rate change now has two homes. Call the existing lookup instead of re-expressing it here.
23
26
  ```
24
27
 
25
- Fields: `cell` (`target × axis`, exactly as the census wrote it — the axis is the rule group, and there is never one cell per individual rule), `verdict` (`clean` | `finding`), `rule` (the specific rule this finding violates, spelled as its pack spells it; omitted on `clean`), `line` (a line **this diff changed**), `severity`, `snippet` (the quoted changed line), `note` (1–2 sentences: what is wrong plus a concrete fix).
28
+ Fields: `cell` (`target × axis`, exactly as the census wrote it — the axis is the rule group, and there is never one cell per individual rule), `verdict` (`clean` | `finding`), `rule` (the specific rule this finding violates, spelled as its pack spells it; omitted on `clean`), `line` (a line **this diff changed**, numbered at the head commit), `severity`, `timing` (`now` | `park`, below), `snippet` (the quoted changed line, verbatim — the orchestrator locates the finding by it), `failure` (required at `must-fix` and `should-fix`: the input or state that produces the wrong result, and what goes wrong), `evidence` (required at `must-fix` and `should-fix`: every `path:line` you opened to establish the failure — the definitions of the symbols the claim depends on, not only the cited line), `note` (1–2 sentences: what is wrong plus a concrete fix).
29
+
30
+ **Open the definition before you claim its behaviour.** A claim about what a called function, method, or value does — that it reads `this`, throws, mutates its argument, returns `null` — cites that definition in `evidence`. A claim you could not check against its definition is not a finding; it is `clean`. The orchestrator opens every `evidence` location and rejects a finding the code contradicts.
26
31
 
27
32
  There is no length budget. Dropping a real finding to stay brief is the failure this review exists to prevent, and a missing cell is re-dispatched as unfinished work, never read as a clean.
28
33
 
@@ -36,6 +41,15 @@ There is no length budget. Dropping a real finding to stay brief is the failure
36
41
 
37
42
  Grade the defect, not your confidence. If you are not confident, the verdict is `clean` — see the hedge test below.
38
43
 
44
+ **Name the failure.** A `must-fix` or `should-fix` states the input or state that produces the wrong result (`if the header is absent, line 42 throws before the 401 is returned`). Code that works as written is not a defect, however you would have written it differently: alternative structures, defensive guards for states no caller reaches, and "consider extracting / renaming / memoizing" are improvements. An improvement is either `park` or `clean`, never a `now` finding.
45
+
46
+ ## Timing — `now` or `park`
47
+
48
+ - `now` — this change should fix it before it merges: a defect on a changed line, or a rule violation the change introduced.
49
+ - `park` — real, but not this change's to fix: the fix lies outside the diff, or the code is correct and the finding asks for more (a regression test for behaviour that already works, a follow-up refactor). Parked findings are listed in the report and **do not score**.
50
+
51
+ Every finding carries `timing`. When unsure, ask whether merging without the fix leaves this change wrong; if not, it is `park`.
52
+
39
53
  ## When `clean` is the right verdict
40
54
 
41
55
  `clean` is a result, not a concession. Return it when:
@@ -62,19 +76,25 @@ Loose typing in test files (`any`, dynamic casts, untyped fixtures) is a **typin
62
76
 
63
77
  ## The report
64
78
 
65
- Merged by the orchestrator, written to `reviewPath`. Sections, in this order, empty ones omitted except `Coverage` and `Score`:
79
+ Merged and adjudicated by the orchestrator, written to `reviewPath`. Sections, in this order, empty ones omitted except `Coverage` and `Score`:
66
80
 
67
81
  ```
68
82
  ## Coverage
69
83
  ## Must-fix
70
84
  ## Should-fix
71
85
  ## Nits
86
+ ## Parked
87
+ ## Rejected
72
88
  ## Score
73
89
  ```
74
90
 
75
- - **Coverage** — one or two lines: N changed files → S `structural` / F `semantic` / T `state-and-tests` / G `general` cells, all verdicted; M files excluded with reasons; the applied packs, and any pack that was unavailable. The four counts are cell counts at the census's granularity — one cell per target per axis.
76
- - **Findings** — each one opens with `` `path/to/file.py:42` `` + the verdict's `rule` name + severity + points, then the snippet as a blockquote, then the 1–2 sentence note with its fix.
77
- - **Score** — every finding gets a row, and the table is emitted even when there are none, with a single total row reading 0:
91
+ - **Must-fix / Should-fix / Nits** — confirmed `now` findings only.
92
+ - **Parked** — `park` findings, with their severity, not scored.
93
+ - **Rejected** — findings the orchestrator's adjudication disproved or that cite no changed line: the reviewer's claim in one line, then the contradicting `path:line` and what it shows. Not scored.
94
+
95
+ - **Coverage** — two or three lines: the reviewers (`provider/model`, one or two); N changed files → S `structural` / F `semantic` / T `state-and-tests` / G `general` cells, all verdicted by every reviewer; M files excluded with reasons; the applied packs, and any pack that was unavailable; and how the findings were settled — agreed, graded by the orchestrator, confirmed by the orchestrator, rejected. The four cell counts are at the census's granularity — one cell per target per axis.
96
+ - **Findings** — each one opens with `` `path/to/file.py:42` `` + the verdict's `rule` name + severity + points, then the snippet as a blockquote, then the 1–2 sentence note with its fix. Its note then says how it was settled: `agreed`, `graded by orchestrator` (with both reviewers' values), or `confirmed by orchestrator`.
97
+ - **Score** — every confirmed `now` finding gets a row, and the table is emitted even when there are none, with a single total row reading 0:
78
98
 
79
99
  ```
80
100
  | # | Location | Rule | Severity | Points |
@@ -83,4 +103,4 @@ Merged by the orchestrator, written to `reviewPath`. Sections, in this order, em
83
103
  | | | | **Total** | **3** |
84
104
  ```
85
105
 
86
- The report's prose is written in Korean. Paths, identifiers, rule names, and quoted code stay verbatim.
106
+ The report's prose is written in the `Report language` the target CLI returned (the project's `reportLanguage`). Paths, identifiers, rule names, and quoted code stay verbatim.
@@ -261,9 +261,9 @@ okstra config set pr-template-path "<value>" --scope global
261
261
 
262
262
  If an action has an unknown `command`, `key`, or `scope`, stop and report the wizard output instead of inventing a command.
263
263
 
264
- Before rendering the next phase's bundle — and between worker rounds within a phase (reverify/critic/gapverify batches), after you have collected that round's results and token usage and before you dispatch the next round — close the panes of the dispatches that finished in the prior round so they do not accumulate, in two passes. First count: `okstra team reclaim --project-root <projectRoot> --run-manifest <RUN_MANIFEST_PATH> --dry-run` closes nothing and prints one `<paneId>\t<kind>` line per pane it would close — count those lines as `<n>`. Then run the same command **without** `--dry-run` to close them, and emit `PROGRESS: phase-batch-cleanup panes=<n>` with that count at the batch boundary. The command reads each dispatch's recorded status, so an in-progress worker keeps its pane whichever moment you call it. It closes only the panes okstra opened and recorded — a pane the harness opened for its own teammate carries no recorded id and is not okstra's to close. `shutdown_request` alone only idles the agent and frees no pane, so it stays part of the run-end sequence for roster/token hygiene. A `cli-wrapper` run holds no pane at all, so `<n>` is `0` — still emit the checkpoint.
264
+ Before rendering the next phase's bundle — and between worker rounds within a phase (reverify/critic/gapverify batches), after you have collected that round's results and token usage and before you dispatch the next round — close the panes of the dispatches that finished in the prior round so they do not accumulate: `okstra team reclaim --project-root <projectRoot> --run-manifest <RUN_MANIFEST_PATH>` closes them, records `phase-batch-cleanup panes=<n>` with the number it closed, and prints that `PROGRESS:` line last — emit it as printed and do not call `okstra lead-progress append` for it. The command reads each dispatch's recorded status, so an in-progress worker keeps its pane whichever moment you call it. It closes only the panes okstra opened and recorded — a pane the harness opened for its own teammate carries no recorded id and is not okstra's to close. `shutdown_request` alone only idles the agent and frees no pane, so it stays part of the run-end sequence for roster/token hygiene. A `cli-wrapper` run holds no pane at all and `team reclaim` refuses it, so record the checkpoint there with `okstra lead-progress append … --phase phase-batch-cleanup --field panes=0`.
265
265
 
266
- Before you ask the user for any approval, clarification, or decision after workers have been dispatched, run the same two passes first: `okstra team reclaim … --dry-run` to count the panes, then the same command without `--dry-run` to close them, emit `PROGRESS: phase-gate-cleanup panes=<n>`, and `TaskStop` each completed worker. A `TaskStop` by itself idles the task but leaves the pane open — the `team reclaim` call is what closes it. This keeps a user gate from being shown while finished worker panes remain; in-progress dispatches keep their panes. Then follow `prompts/lead/okstra-lead-contract.md` "User confirmation before an approval blocker": read cited plan items, worker findings, and files before asking, and ask in the user's language with each option's outcome.
266
+ Before you ask the user for any approval, clarification, or decision after workers have been dispatched, run `okstra team reclaim … --gate` first: it closes the finished panes and prints `PROGRESS: phase-gate-cleanup panes=<n>` for you to emit, without recording a batch cleanup. Then `TaskStop` each completed worker. A `TaskStop` by itself idles the task but leaves the pane open — the `team reclaim` call is what closes it. This keeps a user gate from being shown while finished worker panes remain; in-progress dispatches keep their panes. Then follow `prompts/lead/okstra-lead-contract.md` "User confirmation before an approval blocker": read cited plan items, worker findings, and files before asking, and ask in the user's language with each option's outcome.
267
267
 
268
268
  Build the `okstra render-bundle` invocation from `outcome.renderArgv`, passing every token verbatim and in order (including empty strings — they are intentional `use phase default` markers).
269
269
 
@@ -59,9 +59,26 @@ h3 { font-size: 15px; margin: 0; }
59
59
  table { width: 100%; border-collapse: collapse; }
60
60
  th, td { text-align: left; padding: 7px 10px; border-bottom: 1px solid var(--line); vertical-align: top; }
61
61
  th { color: var(--muted); font-weight: 600; font-size: 12px; white-space: nowrap; }
62
- .wrap { display: inline-block; min-width: 220px; }
63
62
  code.id { white-space: nowrap; word-break: normal; }
64
63
  code { font: 12px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace; word-break: break-all; }
64
+ .children table { table-layout: fixed; }
65
+ .children th:nth-child(1) { width: 23%; }
66
+ .children th:nth-child(2) { width: 22%; }
67
+ .children td { padding-top: 14px; padding-bottom: 14px; overflow-wrap: anywhere; }
68
+ .child-ticket { display: block; margin-bottom: 4px; }
69
+ code.child-key { word-break: normal; }
70
+ .child-status { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 4px 10px; margin: 8px 0 0; font-size: 12px; }
71
+ .child-status dt { color: var(--muted); }
72
+ .child-status dd { margin: 0; }
73
+ .child-assignment { line-height: 1.65; }
74
+ .child-links { display: flex; flex-wrap: wrap; gap: 8px 16px; margin-top: 10px; font-size: 12px; }
75
+ .child-error { color: var(--blocked); margin: 8px 0 0; font-size: 12px; }
76
+ @media (max-width: 700px) {
77
+ .children table, .children tbody, .children tr, .children td { display: block; width: 100%; }
78
+ .children thead { display: none; }
79
+ .children tr { padding: 12px 0; border-bottom: 1px solid var(--line); }
80
+ .children td { padding: 6px 0; border: 0; }
81
+ }
65
82
  .chip {
66
83
  display: inline-block;
67
84
  padding: 1px 8px;