okstra 0.121.1 → 0.123.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/docs/architecture/storage-model.md +14 -0
- package/docs/architecture.md +38 -8
- package/docs/cli.md +45 -5
- package/docs/for-ai/README.md +2 -2
- package/docs/for-ai/skills/okstra-rollup.md +1 -1
- package/docs/for-ai/skills/{okstra-schedule.md → okstra-schedule-gen.md} +3 -3
- package/docs/project-structure-overview.md +4 -3
- package/docs/task-process/implementation-planning.md +33 -9
- package/docs/task-process/implementation.md +21 -2
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/claude-worker.md +1 -1
- package/runtime/bin/lib/okstra/usage.sh +3 -3
- package/runtime/prompts/launch.template.md +9 -6
- package/runtime/prompts/lead/adapters/claude-code.md +104 -0
- package/runtime/prompts/lead/adapters/codex.md +45 -0
- package/runtime/prompts/lead/adapters/external.md +46 -0
- package/runtime/prompts/lead/context-loader.md +5 -5
- package/runtime/prompts/lead/convergence.md +11 -28
- package/runtime/prompts/lead/okstra-lead-contract.md +44 -94
- package/runtime/prompts/lead/plan-body-verification.md +50 -5
- package/runtime/prompts/lead/report-writer.md +59 -54
- package/runtime/prompts/lead/team-contract.md +33 -106
- package/runtime/prompts/profiles/_common-contract.md +3 -3
- package/runtime/prompts/profiles/_implementation-deliverable.md +3 -1
- package/runtime/prompts/profiles/_implementation-executor.md +6 -1
- package/runtime/prompts/profiles/_implementation-verifier.md +2 -2
- package/runtime/prompts/profiles/final-verification.md +2 -0
- package/runtime/prompts/profiles/implementation-planning.md +14 -4
- package/runtime/prompts/profiles/requirements-discovery.md +1 -1
- package/runtime/prompts/wizard/prompts.ko.json +44 -0
- package/runtime/python/okstra_ctl/codex_dispatch.py +23 -1
- package/runtime/python/okstra_ctl/design_prep.py +1462 -0
- package/runtime/python/okstra_ctl/design_surfaces.py +243 -0
- package/runtime/python/okstra_ctl/final_report_schema.py +33 -1
- package/runtime/python/okstra_ctl/implementation_stage.py +35 -0
- package/runtime/python/okstra_ctl/incremental_carry.py +294 -21
- package/runtime/python/okstra_ctl/incremental_scope.py +51 -5
- package/runtime/python/okstra_ctl/lead_runtime.py +4 -0
- package/runtime/python/okstra_ctl/material.py +1 -1
- package/runtime/python/okstra_ctl/model_discovery.py +98 -0
- package/runtime/python/okstra_ctl/models.py +8 -3
- package/runtime/python/okstra_ctl/render.py +81 -194
- package/runtime/python/okstra_ctl/report_views.py +22 -7
- package/runtime/python/okstra_ctl/run.py +53 -5
- package/runtime/python/okstra_ctl/team_reconcile.py +3 -1
- package/runtime/python/okstra_ctl/user_response.py +67 -2
- package/runtime/python/okstra_ctl/wizard.py +283 -3
- package/runtime/python/okstra_token_usage/report.py +11 -0
- package/runtime/schemas/final-report-v1.0.schema.json +339 -0
- package/runtime/skills/okstra-inspect/SKILL.md +2 -2
- package/runtime/skills/okstra-rollup/SKILL.md +1 -1
- package/runtime/skills/{okstra-schedule → okstra-schedule-gen}/SKILL.md +62 -20
- package/runtime/skills/okstra-user-response/SKILL.md +8 -6
- package/runtime/templates/reports/final-report.template.md +71 -4
- package/runtime/templates/reports/i18n/en.json +32 -1
- package/runtime/templates/reports/i18n/ko.json +32 -1
- package/runtime/validators/validate-run.py +515 -5
- package/runtime/validators/validate-schedule.py +11 -7
- package/runtime/validators/validate_session_conformance.py +58 -33
- package/src/cli-registry.mjs +14 -0
- package/src/commands/inspect/design-prep.mjs +23 -0
- package/src/commands/inspect/stage-map.mjs +100 -0
- package/src/commands/lifecycle/install.mjs +3 -0
- package/src/commands/lifecycle/uninstall.mjs +8 -23
- package/src/lib/skill-catalog.mjs +10 -1
|
@@ -8,7 +8,7 @@ profile document.
|
|
|
8
8
|
- Team contract (shared):
|
|
9
9
|
- `Claude lead` is synthesis-only and stays distinct from `Claude worker` (or, in `implementation`, the `Executor` and verifiers).
|
|
10
10
|
- `Report writer worker` is the **author** of the final-report file; `Claude lead` reviews and approves the produced draft and does NOT write the file itself (see `team-contract` and `report-writer` for the authoritative contract).
|
|
11
|
-
- default model assignments are resolved from centralised defaults; the fallback values are `Claude lead`/`Report writer worker`=`opus`, `Claude worker`=`opus`, `Codex worker`=`gpt-5.6`, `Antigravity worker`=`auto`. Phase-specific overrides (e.g. `implementation`'s executor binding) live in the per-profile document.
|
|
11
|
+
- default model assignments are resolved from centralised defaults; the fallback values are `Claude lead`/`Report writer worker`=`opus`, `Claude worker`=`opus`, `Codex worker`=`gpt-5.6-sol`, `Antigravity worker`=`auto`. Phase-specific overrides (e.g. `implementation`'s executor binding) live in the per-profile document.
|
|
12
12
|
- every required worker listed in the per-profile `Required workers:` block must be attempted; the final verdict waits until each has either a result or an explicit terminal status (`timeout`, `error`, `not-run`).
|
|
13
13
|
- unnamed generic parallel workers must not replace the required role roster, and no additional sub-agent dispatch is allowed beyond this roster.
|
|
14
14
|
- Worker interaction model (shared — read before inferring behaviour from the roster):
|
|
@@ -30,7 +30,7 @@ profile document.
|
|
|
30
30
|
- This rule does NOT relax any phase-specific Forbidden actions list; safety rules in the per-profile document remain in force regardless of the user's authority.
|
|
31
31
|
- Anti-escalation rule (shared):
|
|
32
32
|
- treating "다음 단계 진행해" or equivalent user phrases as authorisation to start a *different* lifecycle phase is forbidden. The next phase begins only in a separate okstra run launched with the new `--task-type`. Per-profile documents may further restrict this within their own scope.
|
|
33
|
-
- Run-scoped
|
|
33
|
+
- Run-scoped worker-resource lifecycle (shared — run-start resource setup, per-batch cleanup, wrap-up resource disposition, run-end shutdown): these are lead-only operating duties and live in `prompts/lead/okstra-lead-contract.md` "Run-scoped worker-resource lifecycle". Profiles do not restate them.
|
|
34
34
|
- Brief handoff contract (shared — applies whenever the run consumes a task brief produced by `okstra-brief-gen`):
|
|
35
35
|
- the brief is a **pre-discovery artifact**: it converts a domain-reporter's words (non-expert *or* developer) into expert-consumable form so this and later phases can run with zero fill-in questions to the operator. The brief is **not** authoritative on solution decisions; it is authoritative on the reporter's intent.
|
|
36
36
|
- **Reporter confirmation precondition (BLOCKING)**: the brief's frontmatter carries `reporter-confirmations: <complete | partial | pending | skipped>` set by `okstra-brief-gen` Step 6.5. Every phase that consumes the brief MUST read this field before doing analysis. The handling matrix is:
|
|
@@ -71,7 +71,7 @@ profile document.
|
|
|
71
71
|
- each row's `Kind` column picks one of `{material, decision, data-point}`: `material` for files / snapshots / logs / screenshots the user must attach (the `User input` cell will hold a path or URL); `decision` for choices and yes/no confirmations only the user can make; `data-point` for a single number, ID, date, or short string the user can answer inline. A `decision` alternative must be a terminal choice the user can pick as-is; if acting on an alternative still requires the user to supply a concrete value (a path, string, number, or file), that value is its own `data-point` / `material` row — never phrase a data-entry action (e.g. "경로 구체화", "값 입력") as a selectable `decision` option, because the rendered `<select>` cannot capture the value the option demands. Items that mix "yes/no + file path if yes" are one row of `Kind=material` with the combined expectation written into `Expected form`.
|
|
72
72
|
- each row's `Blocks` column picks one of `{approval, next-phase, none}`. `approval` is reserved for items that gate an approval action, especially the `implementation-planning` `approved:` frontmatter flip; outside `implementation-planning`, unresolved brief reporter-confirmation rows use `next-phase` instead. `next-phase` blocks the next run from starting cleanly. `none` is informational/audit-only.
|
|
73
73
|
- write every entry in full, descriptive sentences that a non-developer can act on without further context. Avoid abbreviations and internal jargon. The `Statement` cell must state *what* is needed, *why* the answer / attachment changes the next step, and (for `material`) *where* the user can find it and *where* to place it. The `Expected form` cell must state the answer shape (예/아니오, 보기 중 하나, 숫자/날짜, 파일 경로, 짧은 서술 등); supply concrete option choices when applicable.
|
|
74
|
-
- if a phase requires a recommended answer, alternatives, or an evidence-check note, encode it inside the existing 4-column schema: put evidence notes in `Statement` as `Evidence checked: <path:line>` or `Evidence checked: none — <human-only reason>`, and put recommendations/options in `Expected form` as `Recommended: <answer> — <rationale>; Alternatives: <
|
|
74
|
+
- if a phase requires a recommended answer, alternatives, or an evidence-check note, encode it inside the existing 4-column schema: put evidence notes in `Statement` as `Evidence checked: <path:line>` or `Evidence checked: none — <human-only reason>`, and put recommendations/options in `Expected form` as `Recommended: (a) <answer> — <rationale>; Alternatives: (b) <option> (c) <option>`. The recommended answer is always the first option and MUST carry the `(a)` label; alternatives continue the same letter sequence from `(b)` (a lone alternative is `(b) <option>`, never restart at `(a)`), so the full option set reads `(a) (b) (c) …` in order and renders each as its own selectable option. Do **not** append a pick-one answer-space summary such as `(A / B 중 택1)` or `(… 중 택N)` to `<options>` — the rendered `<select>` already enforces single choice, and that annotation leaks verbatim into an option label. Do not add `Recommended`, `Evidence`, `Alternatives`, or `evidence-checked` columns, and do not break the merged record-meta cell back into separate columns.
|
|
75
75
|
- the same `final-report.md` file is the canonical artifact carried into the next run; the user appends answers inline before rerunning. The preferred turn-around is `scripts/okstra.sh --resume-clarification --task-key <project-id>:<task-group>:<task-id>` (opens the latest report in `$EDITOR`, then auto-reruns the same phase with `--clarification-response` carry-in). The lower-level form `--clarification-response <path>` remains available for scripted runs.
|
|
76
76
|
- if a clarification response was carried in for this run, render the conditional `## 0. Clarification Response Carried In From Previous Run` section (the template's `RENDER_IF` guard activates it), walk every `C-*` row of the prior report's `## 1. Clarification Items` table, reconcile each one against new evidence, and update its `Status` to `resolved` or `obsolete` before issuing the next decision/verdict. When no carry-in path was provided, omit the `## 0.` heading entirely — the validator fails reports that emit an empty Section 0 stub (e.g. "No prior clarification response was provided for this run.").
|
|
77
77
|
- Verdict Card (shared — applies to every final-report regardless of profile):
|
|
@@ -30,7 +30,8 @@ are collected and convergence finished. Phase 1-5 do not need it.
|
|
|
30
30
|
- **Pure code changes** (no persisted state, no infra mutation): a reachable revert SHA is sufficient. Record the exact `git revert <SHA>` command that would undo the change, and confirm `git rev-parse <SHA>` resolves.
|
|
31
31
|
- **Feature-flag-gated changes**: confirm the off-switch path was exercised in this run's validation evidence (i.e. one of the validation commands ran with the flag off and succeeded). A plan that ships a flag without exercising the off-path does NOT satisfy this requirement.
|
|
32
32
|
- **Schema migrations, config-format changes, or any change with persisted state**: a **dry-run of the rollback step is mandatory**, not preferred. Record the exact rollback command and its captured exit code / stdout. If the migration tool offers no dry-run mode (`--dry-run`, `--plan`, equivalent), the executor MUST refuse to claim rollback verification and instead end the run with a routing recommendation back to `implementation-planning` for a safer rollback strategy. Skipping this step on a stateful change is treated as a `contract-violated` outcome by `final-verification`.
|
|
33
|
-
- **Manual user test draft**: when this run produces a user-observable change (UI / API / CLI / artifact), write `target / environment / steps / expected result` per change into §5.7.9 (data field `implementation.manualUserTest`, `applicable=true` with `items`). Environment line: if the project has a `docker-compose.yml`, use `/okstra-container-build` (which runs `okstra container up <task-id>`) then connect to the published port; otherwise the project's run command (e.g. `npm start`). When there is no user-observable change, set `applicable=false` and give a one-line `exemptionReason` instead of items.
|
|
33
|
+
- **Manual user test draft**: when this run produces a user-observable change (UI / API / CLI / artifact), write `target / environment / steps / expected result` per change into §5.7.9 (data field `implementation.manualUserTest`, `applicable=true` with `items`). Treat effective `manual-user-test` PREP content only as a seed: reconcile it with the approved plan's `Acceptance:` and this run's actual diff before writing the final steps. Environment line: if the project has a `docker-compose.yml`, use `/okstra-container-build` (which runs `okstra container up <task-id>`) then connect to the published port; otherwise the project's run command (e.g. `npm start`). When there is no user-observable change, set `applicable=false` and give a one-line `exemptionReason` instead of items. These are the steps a human (or `final-verification`) re-runs by hand, NOT the automated validation commands in `Validation evidence`; planning PREP is never a second final-verification manual-test source.
|
|
34
|
+
- **Design preparation handoff**: `implementation.manualUserTest` remains the only manual-test handoff to final-verification. For each effective non-`manual-user-test` item whose `reviewAt.phase` is `final-verification` and whose question remains unresolved after inspecting the actual diff, add one common `missingInformation` row. Set `source` to `design-prep:<PREP-ID>:<assessment-fingerprint>`, put `ifStillOpen` and the unresolved question in `item`, and put the guardrails plus risk in `risk`. Do not introduce an implementation-only PREP schema.
|
|
34
35
|
- **Routing recommendation for `final-verification`**: brief note on whether the changes are ready for final-verification phase or need a new error-analysis / planning loop first.
|
|
35
36
|
- **Follow-up tasks (Section 4 of the final report)**: every item discovered during this run that was *not* delivered MUST appear in the final report's `## 4. Follow-up Tasks (후속 작업)` table with a concrete `Origin`, `New Task ID`, `Suggested task-type`, `Scope`, and `Reason / Why deferred`. Sources include: out-of-scope discoveries that the executor consciously chose not to fold into this run, verifier concerns the executor declined to fix in-place, scope-boundary items from the approved plan that turned out to need their own ticket, and any unresolved `## 1. Clarification Items` row carried over from the approved plan (`Status` ∈ `{open, answered}` at approval time). An empty section is acceptable but only when expressed as the single line `- 후속 작업 없음.` — silence is treated as a contract violation. Rows with `Auto-spawn? = yes` will be materialised by `scripts/okstra-spawn-followups.py` in Phase 7; rows with `Auto-spawn? = no` MUST also appear in `Section 3. Recommended Next Steps` so the user knows to act manually.
|
|
36
37
|
|
|
@@ -52,6 +53,7 @@ are collected and convergence finished. Phase 1-5 do not need it.
|
|
|
52
53
|
## Lead post-stage persistence (BLOCKING — runs after the Executor emits `### Stage Carry Evidence`)
|
|
53
54
|
|
|
54
55
|
- Parse the executor's `### Stage Carry Evidence` JSON block. If absent or unparsable, end with status `contract-violated` and route to a follow-up `error-analysis`.
|
|
56
|
+
- The `### Stage Carry Evidence` JSON may include `designPrepEvidence[]`. Emit a row only when this stage produced concrete evidence that refines an effective PREP item: `itemId`, the injected `assessmentFingerprint`, `resolution`, and non-empty `evidence[]` are required; `overrides` is optional and only records observed, non-authoritative refinements. Carry evidence never represents user approval. Downstream resolution accepts it only from transitive dependency stages with the matching fingerprint.
|
|
55
57
|
- For this run's single stage: write its JSON verbatim to `runs/<impl-task-key>/carry/stage-<N>.json`. Refuse to overwrite an existing file (one stage = one sidecar; re-runs are out of scope for this version).
|
|
56
58
|
- For this run's single stage: append a `status:"done"` row to `runs/<plan-task-key>/consumers.jsonl` with `completed_at`, `carry_path`, `report_path` (this run's final-report path relative to the run root), and the SHA of HEAD. Append it with `okstra_ctl.consumers.append_consumer` (NOT a raw filesystem write) — that call honours the consumers lock AND releases this stage's worktree-registry occupancy, so later runs stop seeing a finished stage as a concurrent run. `report_path` lets `final-verification` cite each stage's originating report when assembling its Source Implementation Report list.
|
|
57
59
|
- The verifier round, Phase 5.5 convergence, and this Phase 6 report run **once per run** over this stage's diff — NOT per step.
|
|
@@ -11,7 +11,7 @@ until Phase 5 ends, then drop from active context for Phase 6/7.
|
|
|
11
11
|
|
|
12
12
|
## Executor role binding (carried over from the thin core)
|
|
13
13
|
|
|
14
|
-
- **Executor dispatch labelling.**
|
|
14
|
+
- **Executor dispatch labelling.** The core functional role label is `<provider>-executor` (e.g. `codex-executor`). Provider, role, and model identity are owned by `prompts/lead/okstra-lead-contract.md` "Model assignments"; the selected runtime adapter owns provider-native dispatch-label mapping (including any `name` / `**Pane role:**` fields) and token-attribution wiring under its "Semantic operation mapping".
|
|
15
15
|
- The `Executor` (bound in `implementation.md` thin core) is the **only worker permitted to use Edit / Write / state-mutating Bash commands** on project files. All other workers run read-only. When the executor provider is `codex` or `antigravity`, the actual file mutation happens inside the executor CLI's own auto-edit mode (e.g. `codex exec --sandbox workspace-write`, antigravity's equivalent) — not through Claude-side Edit/Write tools — but the safety rules in this sidecar still apply identically.
|
|
16
16
|
- When the thin core's Task worktree block resolves status to `created` or `reused`, the Executor MUST run every Edit / Write / build / test / commit command with the worktree path as cwd. Treat it as `project_root` for the duration of this run. Do NOT mutate the caller's original checkout. Do NOT `cd` out of the worktree to reach files. If a file outside the worktree is genuinely needed, treat it as a planning gap: record it in `Out-of-plan edits` and continue.
|
|
17
17
|
- **How to set cwd per Bash call**: the Claude Bash tool inherits its cwd from the lead session, which is NOT the worktree. To put cwd-sensitive toolchains (`cargo`, `npm`, `pnpm`, `bun`, `pytest`, `make`, `go`) into the worktree, prefix the command with `cd {{EXECUTOR_WORKTREE_PATH}} && ` inside the same Bash invocation — e.g. `cd {{EXECUTOR_WORKTREE_PATH}} && cargo test -p foo`. **Never wrap in `bash -lc "..."` or `bash -c "..."`** — the wrapper hides the leading `cd` token from Claude Code's permission auto-allow layer (causing prompts on every call) without any safety benefit. For tools that accept an explicit working-directory flag (`git -C <path>`, `cargo --manifest-path`, `pytest --rootdir`), prefer that form over the `cd && ` chain. Edit / Write / Read tool calls already use absolute paths and need no cwd handling. The codex / antigravity executor CLI wrappers (`okstra-codex-exec.sh -C`, `okstra-antigravity-exec.sh --include-directories`) already inject worktree cwd at the CLI layer, so this rule applies primarily to the Claude executor.
|
|
@@ -40,6 +40,11 @@ until Phase 5 ends, then drop from active context for Phase 6/7.
|
|
|
40
40
|
- load every `runs/<plan-key>/carry/stage-<i>.json` for `i ∈ depends-on(this stage)` and inject them into the executor's working context as "runtime carry-in". For a `depends-on (none)` stage, no sidecar load — task-brief only.
|
|
41
41
|
- this stage's `depends-on` are all already `status:done`. Its file list, step order, Stage Validation commands, Stage Exit Contract, and rollback path are the authoritative scope.
|
|
42
42
|
- **Clarification answers carried in (read before the first edit):** when `instruction-set/clarification-response.md` exists, it carries the user's answers to the approved plan's `## 1. Clarification Items` rows (the planning HTML form's `# Attached User Responses`). Treat each answer as an authoritative refinement of the plan's scope for the matching row; an answer that contradicts or expands the approved scope beyond the plan is a re-plan trigger (route to a new `implementation-planning` run), not a silent in-run change. **CLI executor (codex/antigravity):** that file sits outside the CLI sandbox, so the lead MUST transcribe its body into the dispatched executor prompt at dispatch time (same rule as the preflight / stage-discipline transcription above) — a path reference never reaches the CLI process.
|
|
43
|
+
- **Effective design preparation (runtime-resolved after stage selection):**
|
|
44
|
+
|
|
45
|
+
{{DESIGN_PREP_CONTEXT}}
|
|
46
|
+
|
|
47
|
+
Within the approved stage, effective user overrides are authoritative. AI proposals remain working assumptions, not user decisions. Obey every injected guardrail and `reviewAt` point. A conflict with approved scope, the selected option, or Stage Map structure stops execution and routes to a new `implementation-planning` run. Do not reread planning PREP sidecars or independently merge stale or duplicate inputs; the injected context is the stage-scoped decision.
|
|
43
48
|
- inspect the current state of every file the plan names; if any file has changed materially since the plan was written, stop and route to a new `implementation-planning` run instead of editing speculatively
|
|
44
49
|
- "materially changed" means: the function, class, section, or behaviour the plan targets has been edited, renamed, moved, removed, or otherwise altered in a way that invalidates the plan's reasoning. Cosmetic edits (whitespace, comment-only changes, unrelated function modifications elsewhere in the same file) do NOT trigger a re-plan; cite the diff (`git log --oneline <plan-created-at>..HEAD -- <file>`) in the final report and proceed.
|
|
45
50
|
- distinguish the two file-scope rules (they are not in conflict):
|
|
@@ -9,10 +9,10 @@ at Phase 5, BEFORE constructing the verifier worker dispatch prompts.
|
|
|
9
9
|
|
|
10
10
|
## Verifier roles (resolved at run-prep time)
|
|
11
11
|
|
|
12
|
-
- **Verifier dispatch labelling.**
|
|
12
|
+
- **Verifier dispatch labelling.** The core functional role label is `<provider>-verifier` (here, and identically in `final-verification`). Provider, role, and model identity are owned by `prompts/lead/okstra-lead-contract.md` "Model assignments"; the selected runtime adapter owns provider-native dispatch-label mapping (including any `name` / `**Pane role:**` fields) and token-attribution wiring under its "Semantic operation mapping".
|
|
13
13
|
- The verifier slots are `Claude verifier` and `Codex verifier`, plus `Antigravity verifier` **only when `antigravity` is in the resolved `--workers` roster**. Every verifier in the resolved roster is dispatched regardless of which provider holds the executor role; the executor's own provider is run *separately* as a verifier (a fresh CLI session with no shared context) so that no verdict is produced from the same session that wrote the diff. Verifiers MUST NOT call Edit, Write, or any Bash command that mutates files outside the run's artifact directories. If a verifier wants a fix, it records the recommendation in its worker result; it does not apply the fix itself.
|
|
14
14
|
- Session isolation — not model-variant divergence — is the primary self-review safeguard: each verifier is a separate CLI invocation with its own context window, so reusing the same model variant for executor and same-provider verifier is acceptable. Different model variants (e.g. executor=opus / Claude verifier=sonnet) remain recommended when available.
|
|
15
|
-
- Phase-specific model defaults override the shared defaults: `Claude verifier`=`opus`, `Codex verifier`=`gpt-5.6`, `Antigravity verifier`=`auto` (only when present in the roster). The `Executor`'s model is taken from the provider-specific worker model corresponding to `--executor`: claude→`--claude-model` (default `opus`), codex→`--codex-model` (default `gpt-5.6`), antigravity→`--antigravity-model` (default `auto`).
|
|
15
|
+
- Phase-specific model defaults override the shared defaults: `Claude verifier`=`opus`, `Codex verifier`=`gpt-5.6-sol`, `Antigravity verifier`=`auto` (only when present in the roster). The `Executor`'s model is taken from the provider-specific worker model corresponding to `--executor`: claude→`--claude-model` (default `opus`), codex→`--codex-model` (default `gpt-5.6-sol`), antigravity→`--antigravity-model` (default `auto`).
|
|
16
16
|
- Verifiers read from the SAME working tree path the Executor used so they observe the exact diff the Executor produced. Verifiers remain strictly read-only there.
|
|
17
17
|
|
|
18
18
|
## Verifier QA duties (independent re-run mandate)
|
|
@@ -39,6 +39,8 @@
|
|
|
39
39
|
- **Two-tier command lookup (shared with `implementation`):** when this phase performs its own independent re-validation, the command source is exactly the same two tiers `implementation` verifiers use — Tier 1 is the originating task brief / approved plan's `validation` set, Tier 2 is `<PROJECT_ROOT>/.okstra/project.json` under `qaCommands`. Auto-detecting tools from manifest files is forbidden; missing tiers are recorded as `qa-command not configured: <category>` rather than guessed. The `cmd` deny-list (`--fix`, `--write`, ` -w`, ` -u`, `--snapshot-update`, `INSTA_UPDATE=<not-no>`, `cargo update`, `npm install` without `ci`, etc.) is enforced identically. NOTE: runtime fail-fast validation (`okstra_ctl.qa_commands.validate_qa_commands`) only fires at `--task-type implementation` run-prep, so this phase MUST self-check each `qaCommands` entry against the deny-list before executing it — if a denied token is present, skip the command and record it as a `Read-only command log` line `qa-command rejected (denied token: <token>): <label>`.
|
|
40
40
|
- **Tier 3 — stage conformance scripts (whole-task union):** because this phase verifies the **integrated, merged** state, it re-runs conformance against that state rather than per-stage. Read the task-level manifest `<task_root>/qa/conformance-manifest.json` (the directory is the `TASK_QA_PATH` token) and, in **whole-task scope**, run the `runCommand` of **every** `entries[]` item against the merged worktree, refreshing each `<task_root>/qa/result-<stageKey>.json` (`{ "stageKey", "overall": "PASS"|"FAIL"|"MISSING", "ranAt", "requirements" }`). In **single-stage scope**, run only the entry whose `stageKey` matches the verified stage. An entry carrying an `exemption` or user `waiver` is NOT executed — record the skip and reason; a `waiver` becomes a `conditional-accept` condition surfaced in the section 7 Verdict (conformance left unverified by user acknowledgement). Each `runCommand` runs in the worktree cwd with `qaEnv` env (replica DB DSN / app base URL / env file) — **replica / test environment only**, never shared / staging / prod, and the same source/lockfile mutation deny-list applies (a conformance script MAY mutate only its `qaEnv` replica datastore). Interpret each result from the exit code + stdout `QA-RESULT: PASS|FAIL` (last wins) and `REQ <id>: PASS|FAIL: <reason>` lines; no `QA-RESULT` marker → `MISSING`. Any entry whose result is not `PASS` (including `MISSING` or a never-run/missing sidecar) is an **Acceptance Blocker** (`major`+). This is the same gate the `validate-run.py` Tier 3 check enforces on the result sidecars.
|
|
41
41
|
- **Manual user test results**: take each item from the source implementation report's §5.7.9 Manual User Test (Draft), execute the ones reproducible in this environment (e.g. `/okstra-container-build`, which runs `okstra container up`, then the documented steps), and record `result` (`pass` / `fail` / `blocked`) + observed value in §5.8.7 (data field `finalVerification.manualUserTest`). Steps that need human-only interaction this run cannot perform are recorded as `blocked` with the reason (handed to the user), never silently skipped. A failed manual test is an Acceptance Blocker. If the draft was an exemption (`applicable=false`), reaffirm the reason in one line (`applicable=false` + `exemptionReaffirm`).
|
|
42
|
+
For manual testing, read only the source implementation report's `implementation.manualUserTest`. Do not execute planning `designPreparation` / `manual-user-test` PREP items directly. The implementation report has already reconciled the approved seed with the actual diff. Record reproducible results; human-only or unavailable environments become `result: blocked` with the exact reason.
|
|
43
|
+
- **Non-manual design-preparation handoff**: read only source implementation report `missingInformation` rows whose `source` starts with `design-prep:`. Record `ifStillOpen: block` as an acceptance blocker and `ifStillOpen: follow-up` as residual risk. This phase does not read planning PREP sidecars directly, merge their inputs, or mutate the planning snapshot.
|
|
42
44
|
- **Could-not-verify roll-up (§5.8.9)**: the template mechanically aggregates every not-confirmed check into one scannable list — `gap` requirement-coverage rows, `not-configured` / `env-unavailable` / `rejected` command rows, and `blocked` manual tests. You do not hand-author it, but you MUST give those rows their honest status so nothing unverified hides across sections: a check silently recorded as `executed`/`covered` will not surface in the roll-up. This is okstra's answer to "say what could not be verified this run."
|
|
43
45
|
- **Routing recommendation**: the next safe phase — one of `release-handoff`, `done`, `error-analysis`, `implementation-planning` — tied to the verdict and blocker list. `release-handoff` is allowed ONLY when the Verdict Token is `accepted`. `release-handoff` is additionally allowed ONLY when the verification scope (the `Verification scope:` line of the injected `VERIFICATION_TARGET` block, recorded as the report's `verificationScope` field) is `whole-task`; a `single-stage` accepted run routes to `release-handoff(stage-group)` (or `implementation` / `done`); plain `release-handoff` remains whole-task-only. Enforcement: `validators/validate-run.py` rejects a `single-stage` report whose routing cites plain `release-handoff`.
|
|
44
46
|
- **Verified-row recording** (single-stage scope only): when the Verdict Token is `accepted`, the lead MUST run `okstra handoff record-verified --plan-run-root <plan-run-root> --stage <N> --report-path <final-report.md path> --data-json <final-report data.json path>` and quote the command + exit code in the report. The helper re-validates taskType/scope/verdict from data.json, so a non-accepted or whole-task report is rejected at the tool layer.
|
|
@@ -38,12 +38,22 @@
|
|
|
38
38
|
- feasible plan options
|
|
39
39
|
- dependency and risk visibility
|
|
40
40
|
- recommended execution order
|
|
41
|
+
- Implementation Design Preparation (`implementation-design-prep-v1`, BLOCKING):
|
|
42
|
+
- **Detector SSOT:** the planner MUST run the V1 detector defined by `scripts/okstra_ctl/design_surfaces.py` (`detect_design_surfaces()` over the detector's `RULES`) and MUST NOT invent or copy a second keyword list into the plan or prompt. **Enforced:** `validators/validate-run.py` `_validate_detector_coverage` reruns that detector and compares every `(stage, kind)` plus its trigger evidence.
|
|
43
|
+
- **Exactly-once coverage:** for every detector-produced `(stage, kind)`, the planner MUST write exactly one `designSurfaceCoverage` row on that stage. **Enforced:** `validators/validate-run.py` `_validate_detector_coverage` rejects missing, duplicate, extra-detector-kind, or evidence-mismatched rows; `schemas/final-report-v1.0.schema.json` `$defs.DesignSurfaceCoverage` enforces the row shape.
|
|
44
|
+
- **Disposition:** a row MUST use `inline-contract` only when the stage already states the kind-specific minimum implementation contract; otherwise it MUST use `prep-item` and reference one or more `designPreparation.items`. `not-applicable` is legal only with a concrete rationale consistent with the stage action. **Enforced:** `schemas/final-report-v1.0.schema.json` `$defs.DesignSurfaceCoverage` enforces the disposition-specific fields, and `prompts/lead/plan-body-verification.md` `P-Prep-S<stage>-<kind>` verifies semantic sufficiency.
|
|
45
|
+
- **AI-prepared proposal:** every referenced PREP item MUST record `kind`, `stageRefs`, `need`, evidence-cited `knownFacts`, `openQuestions`, a concrete evidence-backed `aiProposal` (`summary`, `details`, `assumptions`, `evidence`, `confidence`), `humanConfirmation`, explicit `status`, and the safest reversible default available. **Enforced:** `schemas/final-report-v1.0.schema.json` `$defs.DesignPrepItem` / `$defs.DesignPrepProposal` enforce required fields, `validators/validate-run.py` `_validate_prep_references` enforces the bidirectional stage/kind link, and `prompts/lead/plan-body-verification.md` rejects empty or non-implementable proposals.
|
|
46
|
+
- **Status choice:** prefer `provisional` with a `workingAssumption`, concrete `guardrails`, `reviewAt`, `ifStillOpen`, and canonical `requestPath`; use `blocked` only for business policy, external authority, a destructive migration decision, or the absence of any safe reversible assumption. **Enforced:** `schemas/final-report-v1.0.schema.json` `$defs.DesignPrepItem` enforces state-specific fields, `validators/validate-run.py` `_validate_design_prep_states` enforces confirmation/request invariants, and `prompts/lead/plan-body-verification.md` judges whether the disposition is justified. A declared `blocked` status does not by itself fail plan-body verification.
|
|
47
|
+
- **Planner-only test surface:** add `manual-user-test` only when a test prerequisite changes the implementation interface or acceptance contract; the V1 detector never emits it. **Enforced:** `validators/validate-run.py` `_validate_detector_coverage` rejects detector-produced `manual-user-test`, `schemas/final-report-v1.0.schema.json` permits its planner-authored shape, and `prompts/lead/plan-body-verification.md` verifies the stage-action rationale.
|
|
48
|
+
- **Trivial task:** when the detector returns no surfaces and no interface/acceptance-changing manual test input exists, `designPreparation` MUST use `mode: no-design-inputs`, an empty `items` array, and a concrete reason tied to the plan. **Enforced:** `schemas/final-report-v1.0.schema.json` `$defs.DesignPreparation` requires the reason and empty array for that mode; `validators/validate-run.py` `_validate_design_prep_contract` validates the marked V1 payload.
|
|
41
49
|
- Approval gate (phase-specific addendum to shared authority rule):
|
|
42
50
|
- The YAML frontmatter `approved: true|false` field is the only authorised approval gate. report-writer always emits `approved: false`. The user clears it either by (a) editing the frontmatter line to `approved: true` directly, or (b) invoking the next phase with `--approve` so the CLI flips the frontmatter on the user's behalf. `okstra_ctl.run._validate_approved_plan` reads this field and refuses entry until it is `true`.
|
|
43
51
|
- Cross-verification mode:
|
|
44
52
|
- Phase 5.5 finding convergence runs in **adversarial mode** for this phase (`convergence.adversarial=true`). Verifiers actively try to refute each worker finding (requirement gap / risk / option) by re-inspecting its cited evidence; the burden of proof sits on the claim. See `prompts/lead/convergence.md` §"Adversarial Verification Mode".
|
|
45
53
|
- §5.5.9 plan-body verification runs with an **adversarial posture** (`prompts/lead/plan-body-verification.md` §"Adversarial plan-body posture"): verifiers open and confirm every cited path / command and put the burden of proof on the plan. The gate threshold is majority-based for kinds `b`/`c`/`e`, but a single `DISAGREE` blocks on its own for the concrete, safety-critical kinds `a` (path/symbol mismatch) / `d` (rollback order) — and `f` on `P-Req-*` items. A majority also needs ≥2 participating votes, so a lone dissent whose peer returned a non-result does not block on a majority-gated kind (see that contract's §"Adversarial plan-body posture").
|
|
46
54
|
- **Incremental re-verification scope (clarification re-runs):** when the lead's `okstra incremental-scope` decision is `mode == "incremental"` (procedure in `prompts/launch.template.md` §"Clarification Response Carried In"), workers re-analyze ONLY the stages listed in `reverify_stages` (the downstream closure of the impacted stages). Workers MUST NOT re-open, re-score, or re-judge any stage in `carry_stages` — those stages' prior plan-item verdicts are carried forward verbatim, and a worker never overwrites a carried verdict with its own judgement. When the decision is `mode == "full"` (the default), every stage is re-analyzed as usual.
|
|
55
|
+
- **Single incremental-scope decision:** the lead calls `okstra incremental-scope` exactly once for the re-run, passing answered-clarification stage impacts through `--impacted` and changed design-preparation IDs through `--prep-items`; the CLI unions their `stageRefs` before applying the existing dependency closure and cutoff. An answer that changes the selected option, Stage Map, or recommended approach is not a local impact: pass both CSVs empty so the same call returns `mode == "full"`. Unknown PREP IDs or invalid `stageRefs` also return an explicit full decision instead of being guessed.
|
|
56
|
+
- **Stage-aware carry:** for an incremental decision, pass its `carry_stages` and `reverify_stages` CSVs unchanged to `okstra incremental-carry`. The helper carries the prior whole stage rows and their owned PREP / `P-Prep-*` artifacts; overlap, cross-scope ownership, scope leaks, or canonical conflicts return `CarryError`. On that error, discard the partial merge and run full re-verification.
|
|
47
57
|
{{INCLUDE:_coverage-critic.md}}
|
|
48
58
|
- Non-goals:
|
|
49
59
|
- code-level micro-optimization unless it changes the implementation approach
|
|
@@ -56,13 +66,13 @@
|
|
|
56
66
|
{{INCLUDE:_clarification-recommendation.md}}
|
|
57
67
|
- **Evidence note required inside `Statement`**: every clarification row includes `Evidence checked: <path:line>` or `Evidence checked: none — <human-only reason>` in the `Statement` cell. `none` is allowed ONLY when the row's nature is "only a human can answer this" (reporter intent, business priority, organisational decision). A row with `none` that *could* have been answered by the codebase is a defect of this phase, restated from the pre-planning rule above.
|
|
58
68
|
- Section heading contract (BLOCKING — validator scans for these literal English substrings):
|
|
59
|
-
- The final report MUST include section headings containing each of the following exact strings: `Option Candidates`, `Trade-off`, `Recommended Option`, `Stage Map`, `Stage Exit Contract`, `Stage Validation`, `Dependency`, `Cross-Project Dependencies`, `Decision Drafts`, `Validation Checklist`, `Rollback`, `Requirement Coverage`. (Approval is no longer a body section — it is the YAML frontmatter `approved` field.)
|
|
69
|
+
- The final report MUST include section headings containing each of the following exact strings: `Option Candidates`, `Trade-off`, `Recommended Option`, `Stage Map`, `Stage Exit Contract`, `Stage Validation`, `Dependency`, `Cross-Project Dependencies`, `Decision Drafts`, `Validation Checklist`, `Rollback`, `Requirement Coverage`, `Implementation Design Preparation`. (Approval is no longer a body section — it is the YAML frontmatter `approved` field.) `validators/validate-run.py` enforces the planning headings it scans, while `schemas/final-report-v1.0.schema.json` plus `templates/reports/final-report.template.md` enforce and render the design-preparation heading from its required data block.
|
|
60
70
|
- Korean translations are allowed in parentheses (e.g. `### Recommended Option (권장 옵션)`), but the English keyword must be present verbatim in the heading line.
|
|
61
71
|
- The shape and ordering follow `final-report-template.md` sections 5.4 (`Implementation Plan Deliverables`) + 5.5 (`Stage Map`). `validators/validate-run.py` substring-matches the raw report text, so a Korean-only heading fails the gate — the cause of repeated observed failures.
|
|
62
72
|
- Beyond substring matching, when the Plan Body Verification gate result is `passed` / `passed-with-dissent`, `validators/validate-run.py` runs the **structural** Stage Map validator (`validators/validate-implementation-plan-stages.py`) at the planning boundary — not deferred to the `implementation` entry gate. It enforces: the exact `## 5.5 Stage Map` heading, each `## 5.5.<i> Stage <i>:` section with its four required subsections, the per-stage effective step count (≤8), the `depends-on` DAG, and the per-stage vertical-slice contract (S10). S10 scans for the literal in-section strings `Slice value:`, `Acceptance:`, the three `Test case (success):` / `Test case (boundary):` / `Test case (failure):` lines (S10d), and the Stepwise `action`-cell prefixes `RED:` / `GREEN:` (or a `TDD exemption:` line, which waives both the test-case lines and the RED/GREEN check) — keep these tokens verbatim for the same reason as the heading keywords above.
|
|
63
73
|
- Required deliverable shape (final report, in addition to the standard sections):
|
|
64
74
|
- at least two implementation options. **Each option must include**:
|
|
65
|
-
- **File Structure**: an explicit list of files to create / modify / delete with each file's responsibility (one-line each). Use the form `Create: path — responsibility` / `Modify: path:line-range — change summary` / `Delete: path — reason`.
|
|
75
|
+
- **File Structure**: an explicit list of files to create / modify / delete with each file's responsibility (one-line each). Use the form `Create: path — responsibility` / `Modify: path:line-range — change summary` / `Delete: path — reason`. Write every `path` in full and `<PROJECT_ROOT>`-relative — never ellipsis-abbreviated (`…` / `...` / a trailing `/…`); an abbreviated path does not resolve and is rejected by plan-body verification as a kind-b path mismatch.
|
|
66
76
|
- affected interfaces / public contracts and downstream consumers
|
|
67
77
|
- estimated blast radius (units, configs, deployment manifests, data migrations)
|
|
68
78
|
- trade-off matrix across options (rows = options, columns at minimum: complexity, risk, reversibility, test coverage cost, rollout cost)
|
|
@@ -81,7 +91,7 @@
|
|
|
81
91
|
Validator S10d rejects a missing/empty line in any of the three categories (skipped only when a `TDD exemption:` line is present). The `RED:` step below must encode these cases, not a single assertion.
|
|
82
92
|
- **Per-stage subsections** (`## 5.5.<i> Stage <i>: <title>` for each `i`), each containing the four required subsections:
|
|
83
93
|
- `### Carry-In` — for `depends-on (none)`: task-brief only. Otherwise: each depended-on stage's static exit contract + runtime sidecar path `runs/<impl-key>/carry/stage-<i>.json` placeholder.
|
|
84
|
-
- `### Stepwise Execution Order` — bite-sized table with `step | action | files | command | expected`. **Effective row count ≤ 8** (excluding header / divider / blank). Each step is one cohesive, self-contained change (시간 하한 없음; 함께 바뀌는 여러 파일을 포함할 수 있다); for code steps include actual code or diff sketch. **TDD ordering is MUST, not a preference:** the **first** effective step's `action` cell MUST start with the literal `RED:` and describe the failing test(s) that capture this stage's `Acceptance` **and the three declared `Test case (success|boundary|failure)` lines** (`expected` = FAIL) — the RED step encodes the case set, not a single happy-path assertion; at least one later `action` cell MUST start with the literal `GREEN:` and describe the minimal implementation that makes it pass (`expected` = PASS); an optional refactor step starts with `REFACTOR:`. **Exemption:** doc-only / config-only / pure-rename stages with no observable runtime behaviour may omit RED/GREEN by declaring one line `TDD exemption: <reason>` in the stage section (mirrors the executor's per-step exemption in `_implementation-executor.md`). Validator S10c enforces RED-first + GREEN **and** that the `RED:` step's `expected` reads FAIL / the `GREEN:` step's reads PASS; S10e rejects a `TDD exemption:` whose reason is not one of doc-only / config-only / pure-rename (both in `validators/validate-implementation-plan-stages.py`).
|
|
94
|
+
- `### Stepwise Execution Order` — bite-sized table with `step | action | files | command | expected`. The `files` cell lists each touched path in full and `<PROJECT_ROOT>`-relative — never ellipsis-abbreviated (`…` / `...`), which does not resolve and is rejected by plan-body verification as a kind-b path mismatch. **Effective row count ≤ 8** (excluding header / divider / blank). Each step is one cohesive, self-contained change (시간 하한 없음; 함께 바뀌는 여러 파일을 포함할 수 있다); for code steps include actual code or diff sketch. **TDD ordering is MUST, not a preference:** the **first** effective step's `action` cell MUST start with the literal `RED:` and describe the failing test(s) that capture this stage's `Acceptance` **and the three declared `Test case (success|boundary|failure)` lines** (`expected` = FAIL) — the RED step encodes the case set, not a single happy-path assertion; at least one later `action` cell MUST start with the literal `GREEN:` and describe the minimal implementation that makes it pass (`expected` = PASS); an optional refactor step starts with `REFACTOR:`. **Exemption:** doc-only / config-only / pure-rename stages with no observable runtime behaviour may omit RED/GREEN by declaring one line `TDD exemption: <reason>` in the stage section (mirrors the executor's per-step exemption in `_implementation-executor.md`). Validator S10c enforces RED-first + GREEN **and** that the `RED:` step's `expected` reads FAIL / the `GREEN:` step's reads PASS; S10e rejects a `TDD exemption:` whose reason is not one of doc-only / config-only / pure-rename (both in `validators/validate-implementation-plan-stages.py`).
|
|
85
95
|
- **Per-stage conformance declaration (mandatory one line, in the stage section — same placement freedom as `TDD exemption:`):** the stage MUST carry exactly one of:
|
|
86
96
|
- `Conformance tests: stage-<N> — <task_root>/qa/scripts/stage-<N>.<ext> (requires=[db|io|http|external,...])` — a Tier3 verification script that proves this stage's upstream requirements (brief / requirements-discovery / error-analysis / improvement-discovery → this stage's `Acceptance`) hold against **real** DB rows, real endpoints, or the real external API — NOT mocks. When you emit this line you MUST also (a) write the script to `<task_root>/qa/scripts/stage-<N>.<ext>` and (b) add a matching entry to `<task_root>/qa/conformance-manifest.json` with fields `stageKey` (= `<task-id>-stage-<N>`), `script`, `runCommand`, `requirementIds`, `requires` (subset of `{db, io, http, external}`), `passContract`, `exemption: null`, `waiver: null`. The script's standard interface: a `main` that exits `0`=PASS / non-zero=FAIL, and whose stdout ends with `QA-RESULT: PASS|FAIL` followed by one `REQ <id>: PASS|FAIL: <근거>` line per requirement. When the verification body is a test spec, author it with the project's own test framework (devDependency) invoked via a discovery override at `<task_root>/qa/scripts/` (jest: `--config <project config> --roots <task_root>/qa/scripts`) — never hand-roll `describe`/`expect` and never widen the project's own test config; for TypeScript specs also write `<task_root>/qa/scripts/tsconfig.json` extending the project tsconfig with the runner's `types` entry so editors resolve the file.
|
|
87
97
|
- `Conformance exemption: <reason>` — only for stages that touch no db/io/http/external surface, or where unit tests fully cover the increment. (If the eventual `implementation` diff actually touches one of those surfaces, `validate-run.py`'s diff-surface cross-check is BLOCKING — an exemption cannot hide a real db/io/http/external change.)
|
|
@@ -110,7 +120,7 @@
|
|
|
110
120
|
- the YAML frontmatter MUST include the line `implementation-option:` directly under `approved:` (report-writer always emits it with an **empty value**). The user selects which Option Candidate the next `implementation` run executes by filling this line with that option's name (manual edit or `--implementation-option <name>` CLI). When left empty, the `implementation` run falls back to the `Recommended Option`.
|
|
111
121
|
- **the frontmatter `approved: false` line is rendered unconditionally; if the plan-body verification gate (§5.5.9) returns `blocked-by-disagreement` or `aborted-non-result`, the writer MUST keep `approved: false` and the validator refuses any report that ships with `approved: true` under such a gate result.**
|
|
112
122
|
- every ambiguity flagged during pre-planning that the user must resolve before approval registered as a `Blocks=approval` row in the `## 1. Clarification Items` table (the unified table is the single home for these — the "no separate `Open Questions` block" rule is in the shared `_common-contract.md` clarification policy)
|
|
113
|
-
- **§5.5.9 Plan Body Verification (BLOCKING).** After report-writer finishes the draft, the lead MUST run a worker peer-review round on the consolidated plan body (Option Candidates / Trade-off Matrix / Recommended Option / Stage Map and per-stage sections / Dependency / Validation Checklist / Rollback / Requirement Coverage) and populate `### 5.5.9 Plan Body Verification` in the final report. The round protocol, plan-item ID scheme (`P-Opt-*` / `P-Step-*` / `P-Dep-*` / `P-Val-*` / `P-Rb-*`), verdict semantics, gate-result classification, and dissent log format are defined in `prompts/lead/plan-body-verification.md`. The four gate-result values are `passed`, `passed-with-dissent`, `blocked-by-disagreement`, `aborted-non-result`. When the gate would have been `blocked-by-disagreement` or `aborted-non-result`, the lead MUST NOT silently flip it to one of the passing values to "unblock" the run — that is a contract violation. **Enforced:** `validators/validate-run.py` `_validate_plan_body_gate_recompute` re-derives the gate from `planItems[].verdicts` and fails when the declared `gateResult` claims a healthier outcome than the recorded votes support; `_validate_plan_item_extraction_completeness` fails when any plan-body deliverable category is under-extracted into `planItems`, so a dropped item can no longer dodge the gate. When `convergence.adversarial=true` (the default for this phase), this round uses the adversarial posture — verifiers confirm cited paths/commands and the burden of proof is on the plan — but the gate threshold stays `majority-disagree` (see that skill's §"Adversarial plan-body posture").
|
|
123
|
+
- **§5.5.9 Plan Body Verification (BLOCKING).** After report-writer finishes the draft, the lead MUST run a worker peer-review round on the consolidated plan body (Option Candidates / Trade-off Matrix / Recommended Option / Stage Map and per-stage sections / Dependency / Validation Checklist / Rollback / Requirement Coverage) and populate `### 5.5.9 Plan Body Verification` in the final report. The round protocol, plan-item ID scheme (`P-Opt-*` / `P-Step-*` / `P-Dep-*` / `P-Val-*` / `P-Rb-*`), verdict semantics, gate-result classification, and dissent log format are defined in `prompts/lead/plan-body-verification.md`. The four gate-result values are `passed`, `passed-with-dissent`, `blocked-by-disagreement`, `aborted-non-result`. When the gate would have been `blocked-by-disagreement` or `aborted-non-result`, the lead MUST NOT silently flip it to one of the passing values to "unblock" the run — that is a contract violation. **Enforced:** `validators/validate-run.py` `_validate_plan_body_gate_recompute` re-derives the gate from `planItems[].verdicts` and fails when the declared `gateResult` claims a healthier outcome than the recorded votes support; `_validate_plan_item_extraction_completeness` fails when any plan-body deliverable category is under-extracted into `planItems`, so a dropped item can no longer dodge the gate. When `convergence.adversarial=true` (the default for this phase), this round uses the adversarial posture — verifiers confirm cited paths/commands and the burden of proof is on the plan — but the gate threshold stays `majority-disagree` (see that skill's §"Adversarial plan-body posture"). majority-disagree 항목 중 `planner-fixable` 다수는 사용자 clarification 으로 승격하기 전에 report-writer 자가수정 1회를 거친다(`prompts/lead/plan-body-verification.md` "Self-fix round"). self-fix 로 해소되지 않았거나 `needs-user-input` 다수인 항목만 `Blocks=approval` clarification 이 된다. `validators/validate-run.py` `_validate_self_fix_before_clarification` 가 self-fix 없이 승격된 planner-fixable 다수 항목을 `contract-violated` 로 실패시킨다.
|
|
114
124
|
- **Decision-record evaluation (sole owner)**: this phase is the **single owner** of decision-record evaluation in the okstra lifecycle. The brief never evaluates or drafts decision records — it only forwards `adr-candidate:*` signals. Every `adr-candidate:*` entry inherited from the brief's `Open Questions` is a mandatory evaluation target. In addition, evaluate every decision the recommended option introduces against the three criteria:
|
|
115
125
|
1. **Hard to reverse** — would changing the decision later cost meaningfully more than deciding now?
|
|
116
126
|
2. **Surprising without context** — would a future reader, seeing only the code, wonder "why was it built this way?"?
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
각 단위를 새 task-key 로 시작한다(이 phase 는 다운스트림 run 을 직접 시작하지 않는다).
|
|
43
43
|
- Decision-tree walk (bounded):
|
|
44
44
|
- When the brief's `Desired Outcome`, classification, or routing target depends on a chain of decisions, walk that chain one branch at a time. Each branch is one `Clarification Items` row, not a free-form interview.
|
|
45
|
-
- For every clarification row, put the single best answer and one-line rationale in `Expected form` as `Recommended: ...`. Put other options and one-sentence consequences in the same cell as `Alternatives:
|
|
45
|
+
- For every clarification row, put the single best answer and one-line rationale in `Expected form` as `Recommended: (a) ...`. Put other options and one-sentence consequences in the same cell as `Alternatives: (b) ... (c) ...` — the recommended answer is option `(a)` and alternatives continue from `(b)`, so the labels read `(a) (b) (c) …` in order.
|
|
46
46
|
- **Codebase-first rule**: if a branch can be resolved by `Read` / `Grep` / file inspection, resolve it that way and record `Evidence checked: <path:line>` in the `Statement` cell. Do NOT escalate to the user.
|
|
47
47
|
- Budget: the unified `## 1. Clarification Items` table caps at the smaller of (a) one row per unresolved decision branch, (b) 8 rows total. Beyond the cap, fold remaining ambiguity into the routing recommendation's risk notes.
|
|
48
48
|
- Expected output emphasis:
|
|
@@ -233,6 +233,50 @@
|
|
|
233
233
|
"unknown_option": "보고서에서 내보낸 승인 기록의 옵션 `{option}` 이 plan 의 Option Candidates 에 없습니다. 유효 후보: {candidates}. 보고서에서 다시 내보내거나 '예 — 승인만' 을 선택하세요."
|
|
234
234
|
}
|
|
235
235
|
},
|
|
236
|
+
"design_prep_decision": {
|
|
237
|
+
"label": "설계 준비 항목 {item_id} — {title}\n대상 stage: {stage_refs}\n\nAI 초안\n- 요약: {proposal_summary}\n- 상세: {details}\n- 가정: {assumptions}\n- 가드레일: {guardrails}\n- 요청 문서: {request_path}\n\n이 초안을 어떻게 처리할까요?",
|
|
238
|
+
"echo_template": "design-prep decision: {value}",
|
|
239
|
+
"options": {
|
|
240
|
+
"accept-draft": "AI 초안 수락",
|
|
241
|
+
"modify-draft": "AI 초안 수정",
|
|
242
|
+
"reject-draft": "AI 초안 거절",
|
|
243
|
+
"later": "나중에 결정"
|
|
244
|
+
},
|
|
245
|
+
"echo_variants": {
|
|
246
|
+
"later": "design-prep {item_id}: 나중에 결정 — 입력 파일을 만들지 않음"
|
|
247
|
+
},
|
|
248
|
+
"errors": {
|
|
249
|
+
"invalid_decision": "설계 준비 결정은 accept-draft, modify-draft, reject-draft, later 중 하나여야 합니다."
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
"design_prep_overrides": {
|
|
253
|
+
"label": "설계 준비 항목 {item_id}의 {decision} 내용을 입력하세요. modify-draft는 JSON 객체, reject-draft는 거절 사유를 입력합니다.",
|
|
254
|
+
"echo_template": "design-prep details: {value}",
|
|
255
|
+
"echo_variants": {
|
|
256
|
+
"overrides": "design-prep overrides: JSON 객체 확인됨",
|
|
257
|
+
"note": "design-prep rejection note: 확인됨"
|
|
258
|
+
},
|
|
259
|
+
"errors": {
|
|
260
|
+
"invalid_json": "수정 내용이 올바른 JSON이 아닙니다: {error}",
|
|
261
|
+
"object_required": "수정 내용은 JSON 객체여야 합니다.",
|
|
262
|
+
"note_required": "reject-draft에는 비어 있지 않은 note가 필요합니다."
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
"design_prep_confirm": {
|
|
266
|
+
"label": "설계 준비 입력을 저장하기 전 의미 내용을 확인하세요.\n\nitem: {item_id}\ndecision: {decision}\noverrides: {overrides}\nnotes: {notes}\n\n승인된 스냅샷의 모든 의미 필드:\n{item_snapshot}\n\nrevision / input-id / created-at은 확정 후 원자적으로 할당됩니다.",
|
|
267
|
+
"echo_template": "design-prep confirm: {value}",
|
|
268
|
+
"options": {
|
|
269
|
+
"yes": "예 — 이 의미 내용으로 입력 파일 생성",
|
|
270
|
+
"no": "아니오 — 결정 화면으로 돌아가기"
|
|
271
|
+
},
|
|
272
|
+
"echo_variants": {
|
|
273
|
+
"revise": "design-prep {item_id}: 저장하지 않고 결정 화면으로 돌아감",
|
|
274
|
+
"written": "design-prep {item_id}: revision {revision}, input-id {input_id}, path {path}"
|
|
275
|
+
},
|
|
276
|
+
"errors": {
|
|
277
|
+
"confirmation_required": "설계 준비 입력 저장은 yes 또는 no로 확인해야 합니다."
|
|
278
|
+
}
|
|
279
|
+
},
|
|
236
280
|
"stage_pick": {
|
|
237
281
|
"label": "진행할 stage 를 선택하세요(여러 개 선택 가능). '전체' 는 남은 미완료 stage 를 모두, 개별 선택 시 의존하는 미완료 stage 가 자동 포함됩니다.",
|
|
238
282
|
"label_final_verification": "검증할 implementation stage 를 선택하세요.",
|
|
@@ -452,7 +452,11 @@ def _render_missing_analysis_worker_prompt(
|
|
|
452
452
|
lines.extend(_worktree_headers(manifest, active_context, role))
|
|
453
453
|
lines.extend(_analysis_prompt_body(manifest, active_context, worker_id, model, role))
|
|
454
454
|
executor_tail = _implementation_executor_tail(
|
|
455
|
-
manifest,
|
|
455
|
+
manifest,
|
|
456
|
+
active_context,
|
|
457
|
+
project_root,
|
|
458
|
+
workspace_root,
|
|
459
|
+
role,
|
|
456
460
|
)
|
|
457
461
|
if executor_tail:
|
|
458
462
|
lines.extend(["", executor_tail.rstrip()])
|
|
@@ -806,6 +810,8 @@ def _worktree_headers(
|
|
|
806
810
|
|
|
807
811
|
def _implementation_executor_tail(
|
|
808
812
|
manifest: Mapping[str, Any],
|
|
813
|
+
active_context: Mapping[str, Any],
|
|
814
|
+
project_root: Path,
|
|
809
815
|
workspace_root: Path,
|
|
810
816
|
role: str,
|
|
811
817
|
) -> str:
|
|
@@ -813,6 +819,22 @@ def _implementation_executor_tail(
|
|
|
813
819
|
return ""
|
|
814
820
|
profiles = workspace_root / "prompts" / "profiles"
|
|
815
821
|
parts: list[str] = []
|
|
822
|
+
analysis_profile = _instruction_path(
|
|
823
|
+
manifest,
|
|
824
|
+
active_context,
|
|
825
|
+
"analysisProfilePath",
|
|
826
|
+
)
|
|
827
|
+
if not analysis_profile:
|
|
828
|
+
raise DispatchError("implementation executor profile path is missing")
|
|
829
|
+
executor_profile = (
|
|
830
|
+
_resolve_project_path(project_root, analysis_profile).parent
|
|
831
|
+
/ "implementation-executor.md"
|
|
832
|
+
)
|
|
833
|
+
if not executor_profile.is_file():
|
|
834
|
+
raise DispatchError(
|
|
835
|
+
f"resolved implementation executor profile not found: {executor_profile}"
|
|
836
|
+
)
|
|
837
|
+
parts.append(executor_profile.read_text(encoding="utf-8"))
|
|
816
838
|
preflight_path = profiles / "_coding-conventions-preflight.md"
|
|
817
839
|
if preflight_path.is_file():
|
|
818
840
|
parts.append(preflight_path.read_text(encoding="utf-8"))
|