okstra 0.123.0 → 0.124.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 (82) hide show
  1. package/README.md +1 -0
  2. package/docs/architecture/storage-model.md +1 -1
  3. package/docs/architecture.md +11 -1
  4. package/docs/cli.md +2 -0
  5. package/docs/for-ai/README.md +41 -35
  6. package/docs/for-ai/skills/okstra-brief-gen.md +105 -105
  7. package/docs/for-ai/skills/okstra-container-build.md +61 -61
  8. package/docs/for-ai/skills/okstra-graphify.md +64 -0
  9. package/docs/for-ai/skills/okstra-inspect.md +86 -86
  10. package/docs/for-ai/skills/okstra-manager.md +32 -32
  11. package/docs/for-ai/skills/okstra-memory.md +49 -50
  12. package/docs/for-ai/skills/okstra-pr-gen.md +48 -0
  13. package/docs/for-ai/skills/okstra-rollup.md +58 -58
  14. package/docs/for-ai/skills/okstra-run.md +95 -95
  15. package/docs/for-ai/skills/okstra-schedule-gen.md +106 -106
  16. package/docs/for-ai/skills/okstra-setup.md +63 -64
  17. package/docs/for-ai/skills/okstra-user-response.md +48 -0
  18. package/docs/performance-improvement-plan-v2.md +4 -4
  19. package/docs/pr-template-usage.md +34 -34
  20. package/docs/project-structure-overview.md +91 -70
  21. package/docs/task-process/README.md +33 -33
  22. package/docs/task-process/common-flow.md +26 -26
  23. package/docs/task-process/error-analysis.md +20 -21
  24. package/docs/task-process/final-verification.md +41 -41
  25. package/docs/task-process/implementation-planning.md +33 -33
  26. package/docs/task-process/implementation.md +38 -38
  27. package/docs/task-process/release-handoff.md +46 -46
  28. package/docs/task-process/requirements-discovery.md +22 -23
  29. package/package.json +1 -1
  30. package/runtime/BUILD.json +2 -2
  31. package/runtime/agents/workers/antigravity-worker.md +4 -4
  32. package/runtime/agents/workers/claude-worker.md +2 -2
  33. package/runtime/agents/workers/codex-worker.md +4 -4
  34. package/runtime/agents/workers/report-writer-worker.md +4 -4
  35. package/runtime/prompts/coding-preflight/frameworks/node-server.md +1 -1
  36. package/runtime/prompts/launch.template.md +1 -1
  37. package/runtime/prompts/lead/convergence.md +10 -20
  38. package/runtime/prompts/lead/okstra-lead-contract.md +14 -16
  39. package/runtime/prompts/lead/plan-body-verification.md +18 -18
  40. package/runtime/prompts/lead/report-writer.md +43 -44
  41. package/runtime/prompts/lead/team-contract.md +11 -122
  42. package/runtime/prompts/profiles/_common-contract.md +15 -22
  43. package/runtime/prompts/profiles/_implementation-deliverable.md +1 -1
  44. package/runtime/prompts/profiles/_implementation-executor.md +1 -1
  45. package/runtime/prompts/profiles/_implementation-verifier.md +2 -2
  46. package/runtime/prompts/profiles/error-analysis.md +2 -2
  47. package/runtime/prompts/profiles/final-verification.md +1 -1
  48. package/runtime/prompts/profiles/implementation-planning.md +13 -13
  49. package/runtime/prompts/profiles/implementation.md +1 -1
  50. package/runtime/prompts/profiles/improvement-discovery.md +1 -1
  51. package/runtime/prompts/profiles/release-handoff.md +3 -3
  52. package/runtime/prompts/profiles/requirements-discovery.md +18 -18
  53. package/runtime/skills/_fragments/bash-invocation-rule.md +1 -0
  54. package/runtime/skills/_fragments/preflight-outdated-cli.md +1 -0
  55. package/runtime/skills/_fragments/python-bootstrap-note.md +1 -0
  56. package/runtime/skills/okstra-brief-gen/SKILL.md +117 -122
  57. package/runtime/skills/okstra-container-build/SKILL.md +24 -14
  58. package/runtime/skills/okstra-graphify/SKILL.md +12 -4
  59. package/runtime/skills/okstra-inspect/SKILL.md +104 -98
  60. package/runtime/skills/okstra-manager/SKILL.md +1 -1
  61. package/runtime/skills/okstra-memory/SKILL.md +3 -3
  62. package/runtime/skills/okstra-rollup/SKILL.md +12 -6
  63. package/runtime/skills/okstra-run/SKILL.md +49 -88
  64. package/runtime/skills/okstra-schedule-gen/SKILL.md +36 -30
  65. package/runtime/skills/okstra-setup/SKILL.md +1 -1
  66. package/runtime/skills/okstra-setup/references/project-config.md +17 -16
  67. package/runtime/skills/okstra-usage/SKILL.md +5 -2
  68. package/runtime/skills/okstra-user-response/SKILL.md +15 -3
  69. package/runtime/templates/prd/brief.template.md +92 -92
  70. package/runtime/templates/reports/error-analysis-input.template.md +1 -1
  71. package/runtime/templates/reports/fan-out-unit.template.md +6 -6
  72. package/runtime/templates/reports/final-verification-input.template.md +6 -6
  73. package/runtime/templates/reports/implementation-input.template.md +1 -1
  74. package/runtime/templates/reports/implementation-planning-input.template.md +1 -1
  75. package/runtime/templates/reports/improvement-discovery-input.template.md +1 -1
  76. package/runtime/templates/reports/quick-input.template.md +1 -1
  77. package/runtime/templates/reports/release-handoff-input.template.md +1 -1
  78. package/runtime/templates/reports/schedule.template.md +22 -22
  79. package/runtime/templates/reports/task-brief.template.md +3 -3
  80. package/runtime/templates/reports/user-response.template.md +20 -20
  81. package/runtime/templates/worker-prompt-preamble.md +111 -13
  82. package/runtime/validators/validate-schedule.py +1 -1
@@ -34,7 +34,7 @@ until Phase 5 ends, then drop from active context for Phase 6/7.
34
34
  - Order of operations per plan step: (1) write/extend the test that captures the step's acceptance criterion and confirm it fails for the right reason, (2) implement the minimum change to make it pass, (3) commit the test and its implementation together in a single commit (`feat|fix(<scope>): ...`) — do NOT commit the failing test separately, (4) refactor without changing behaviour and commit separately if any cleanup is made (`refactor(<scope>): ...`). The failing-then-passing transition is preserved as `TDD evidence` in the final report (failing output captured before the merged commit, passing output after), not as two separate commits.
35
35
  - Doc-only / config-only / pure-rename steps that have no observable runtime behaviour are exempt from the failing-test requirement, but the executor MUST cite the exemption per step in the final report (`TDD exemption: <reason>`).
36
36
  - When the touched area has no existing test harness, the executor MUST stand up the minimum harness needed to host one regression test for this run rather than skipping TDD entirely. Record the harness-bootstrap step as an `Out-of-plan edit` if it is not in the plan.
37
- - **DB / IO / SQL changes require real execution — mock-only is NOT validation evidence:** when this run's diff touches DB/IO/SQL (ORM / query-builder code — sequelize / typeorm / prisma / knex / raw SQL — `*.repository.*`, model/entity files, `migrations/**`, `*.sql`, or any changed query string), a mocked unit test cannot observe the SQL the query builder actually emits (observed failure class: `_implementation-verifier.md` §"DB / IO / SQL change — real-execution gate"). The executor MUST run the change against a real (or faithful-replica) datastore — the `db-test` validation step (plan `validation` db step, else `project.json.qaCommands.db-test`), targeting a **local / replica** DB — and cite its exact command + exit code in the final report's `Validation evidence`. If no real DB / `db-test` command is reachable, do NOT claim the change verified: label the DB portion `정적 분석상 …, 미검증(실행 안 함)` in the report, surface it in the routing recommendation, and never downplay the real run as "too heavy". `git push` stays forbidden (universal list); the unverified DB state is carried forward so `final-verification` cannot accept it and `release-handoff` cannot push.
37
+ - **DB / IO / SQL changes require real execution — mock-only is NOT validation evidence:** when this run's diff touches DB/IO/SQL (ORM / query-builder code — sequelize / typeorm / prisma / knex / raw SQL — `*.repository.*`, model/entity files, `migrations/**`, `*.sql`, or any changed query string), a mocked unit test cannot observe the SQL the query builder actually emits (observed failure class: `_implementation-verifier.md` §"DB / IO / SQL change — real-execution gate"). The executor MUST run the change against a real (or faithful-replica) datastore — the `db-test` validation step (plan `validation` db step, else `project.json.qaCommands.db-test`), targeting a **local / replica** DB — and cite its exact command + exit code in the final report's `Validation evidence`. If no real DB / `db-test` command is reachable, do NOT claim the change verified: label the DB portion `static-analysis only …, unverified (not executed)` in the report, surface it in the routing recommendation, and never downplay the real run as "too heavy". `git push` stays forbidden (universal list); the unverified DB state is carried forward so `final-verification` cannot accept it and `release-handoff` cannot push.
38
38
  - **Real-IO test isolation (BLOCKING).** A test that exercises a **real** datastore, HTTP endpoint, external service, message queue, or filesystem — a live DB connection / DSN, a real `fetch` / `axios` / `http` request, an actual S3 / queue client, anything the project's normal CI test suite cannot run because that backend is absent — MUST be written under the task's qa scripts directory `<task_root>/qa/scripts/` (`<TASK_QA_PATH>/scripts`; the `qa/` root itself holds only data sidecars — the Tier 3 conformance manifest and `result-*.json`). It MUST NOT be written into the project source test tree — `src/**`, `test/**`, `tests/**`, `**/__test__/**`, `**/__tests__/**`, `*.spec.*`, `*.test.*`, or anywhere the project's lint/test globs collect. Two reasons: (a) the project's CI / normal suite has no real DB or network, so a real-IO test placed in source silently breaks the pipeline; (b) it is an okstra verification artifact, and the artifact-home rule confines okstra outputs to `.okstra/`. **The dividing line is the IO, not the intent:** a unit test that stubs/spies only *injected collaborators* (mock — no real socket, no real DB handle) is a TDD red-green artifact and stays in source; the moment a test opens a real connection or makes a real network call it belongs in qa. A stage's real-IO requirement check is a Tier 3 conformance script under `<task_root>/qa/scripts/` (declared via the implementation-planning conformance entry) — never smuggle real IO into a `*.spec.*` in source to make it run "as a unit test". The `db-test` real-execution gate above is satisfied by the conformance/db-test path against the replica, NOT by adding a live-DB `*.spec.*` to the project suite. **Author qa specs with the project's own test framework — never hand-roll `describe`/`it`/`expect`.** When the project ships a test runner as a devDependency (jest / vitest / pytest …), the qa spec uses it, invoked with the project config plus a discovery override pointing at the qa scripts dir (jest: `npx jest --config <project jest config> --roots <task_root>/qa/scripts --runInBand <spec-name>`) — the project config keeps module aliases resolving while the default sweep never collects the file; never widen the project's own test config to include qa paths. For TypeScript qa specs also write `<task_root>/qa/scripts/tsconfig.json` (`extends` the project tsconfig, adds the runner's `types` entry, `"include": ["**/*.ts"]`) so editors resolve path aliases and test globals — it is a qa artifact like the rest (untracked). **These qa artifacts stay untracked — never commit them.** `.okstra/**` is gitignored (the artifact-home rule); conformance scripts and their results are *executed* and recorded in the carry sidecar / verifier result, never written into git history. A committed `.okstra/qa` file is a stage-branch defect that leaks okstra internals into the eventual PR (see the `git add` rules below).
39
39
  - re-read the approved plan end-to-end and parse the `## 5.5 Stage Map`. Read the **Stage** injected in the launch prompt (`Stage for this implementation run`): the single stage number this run owns. The runtime already selected and reserved this stage (one run = one stage) — do NOT recompute the start stage from `consumers.jsonl`.
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.
@@ -42,7 +42,7 @@ Verifier obtains the QA command set from exactly two declared sources, in order
42
42
 
43
43
  Tier 1 commands run verbatim first. Then every Tier 2 entry runs once. Then the Tier 3 stage conformance script (below) runs once. Each command runs in the worktree cwd, and is recorded in the worker result with its exact command line, exit code, and the tail of stdout/stderr. Substituting or paraphrasing a Tier 1 command is forbidden (see Verifier-specific forbidden actions below).
44
44
 
45
- ### Tier 3 — stage conformance scripts (요구사항 부합 검증)
45
+ ### Tier 3 — stage conformance scripts (requirement-conformance verification)
46
46
 
47
47
  Tier 3 proves the stage actually *meets the upper-level requirement* it was scoped to, by running a declared conformance script against the running state — Tiers 1·2 only prove the diff *builds and passes*. This is a real gate: its result sidecar is the input the `validate-run.py` Tier 3 gate reads, so a missing or non-PASS result BLOCKS acceptance.
48
48
 
@@ -109,7 +109,7 @@ A mocked unit test cannot observe the SQL a query builder actually emits — `co
109
109
  - **Trigger.** Fires when `git diff <base>...HEAD` touches DB/IO/SQL: ORM / query-builder code (sequelize / typeorm / prisma / knex / raw SQL), `*.repository.*`, model/entity files, `migrations/**`, `*.sql`, or any changed query string.
110
110
  - **Requirement when fired.** The verifier MUST reproduce a real-DB execution: run the `db-test` tier (Tier 1 = plan `validation` db step; else Tier 2 = `project.json.qaCommands.db-test`) against a **local / replica** datastore (same engine + schema — never shared / staging / prod, consistent with the verifier forbidden-actions list) and record its exact command + exit code. A mock, an in-memory shim that does not parse real SQL, or static reasoning does NOT satisfy this.
111
111
  - **No `db-test` command available → blocking, not a passive skip.** If neither tier declares a `db-test` command, the verifier records the blocking finding `db-test not configured — DB change unverified (mock-only)` and sets the verdict to `FAIL`; it MUST NOT emit only the passive `qa-command not configured` note and pass. Recommended fix: declare a `db-test` command in `project.json.qaCommands` or the plan's validation set.
112
- - **Mock-only evidence → unverified.** If the diff's only DB coverage is mocked, the verifier labels the DB portion `정적 분석상 …, 미검증(실행 안 함)` (never `검증됨`), records it as a blocking finding, and sets `FAIL`. Never downplay the real run as "too heavy / static proof suffices".
112
+ - **Mock-only evidence → unverified.** If the diff's only DB coverage is mocked, the verifier labels the DB portion `static-analysis only …, unverified (not executed)` (never `verified`), records it as a blocking finding, and sets `FAIL`. Never downplay the real run as "too heavy / static proof suffices".
113
113
  - **Surface it at every layer.** The finding is copied verbatim into the verifier result and MUST survive into the final report's `## 6.` and Verdict Card, so the user sees the DB-unverified state continuously — it is the load-bearing reason a downstream `final-verification` cannot reach `accepted` and `release-handoff` cannot push.
114
114
 
115
115
  ## All-verifier-failure policy
@@ -12,7 +12,7 @@
12
12
  - Apply the shared reporter-confirmation precondition exactly as written. In this phase, unresolved `intent-check:` / `conversion-block:` rows use `Blocks=next-phase`; any unconfirmed inference may be used as a labelled hypothesis only.
13
13
  - the reporter's symptom description in `Source Material` is the ground truth for what to reproduce. Do not paraphrase it when stating the symptom in the report; quote it.
14
14
  - read `Related Task Graph` before forming root-cause candidates. `depends-on`, `blocks` / `blocked-by`, parent/child, follow-up, and split edges define upstream/downstream boundaries for the symptom: identify whether this task's failure is caused by, blocks, or merely relates to another task before merging causes.
15
- - any `intent-inference` augmentation that re-characterises the symptom (e.g. classifying "가끔 " as "intermittent failure on a specific code path") is a **hypothesis**, not a confirmed symptom. If `[CONFIRMED …]` appears on the matching `intent-check:` row, treat that confirmation as the symptom. Otherwise follow the precondition's `skipped` branch above and keep the inference labelled as a hypothesis in the root-cause analysis.
15
+ - any `intent-inference` augmentation that re-characterises the symptom (e.g. classifying a vague reporter phrase like "it sometimes doesn't work" as "intermittent failure on a specific code path") is a **hypothesis**, not a confirmed symptom. If `[CONFIRMED …]` appears on the matching `intent-check:` row, treat that confirmation as the symptom. Otherwise follow the precondition's `skipped` branch above and keep the inference labelled as a hypothesis in the root-cause analysis.
16
16
  - `conversion-block:` rows mean the brief could not map a reporter statement to project vocabulary; never invent the missing mapping in this phase.
17
17
  - Diagnosis loop:
18
18
  - **Symptom lock:** state the reporter's symptom verbatim, then translate it into one observable failure condition. If no observable condition can be derived from the brief, record that gap as the first blocker instead of guessing.
@@ -34,7 +34,7 @@
34
34
  - practical next diagnostic steps
35
35
  - Clarification request policy (phase-specific addenda — shared policy is in `_common-contract.md`):
36
36
  - if any blocking uncertainty remains at the time of writing the final report, populate `## 1. Clarification Items` in `final-report-template.md` (a single unified table; `Blocks=next-phase` for items the next run cannot start without)
37
- - prefer plain Korean over abbreviations (e.g. write "초당 평균 요청 " instead of "QPS", "재현 절차" instead of "repro")
37
+ - prefer plain Korean over abbreviations (e.g. write out the full Korean phrase for "requests per second" instead of "QPS", and for "reproduction steps" instead of "repro")
38
38
  {{INCLUDE:_clarification-recommendation.md}}
39
39
  - **Codebase-first ambiguity resolution (defect rule)**: any ambiguity about repro, file behavior, or symbol semantics that can be answered by `Read` / `Grep` / log inspection MUST be resolved that way and recorded with file:line (or log-line) evidence. Writing a clarification row for something the codebase or shipped logs already answer is a defect of this phase.
40
40
  - **Evidence note required inside `Statement`**: every clarification row includes `Evidence checked: <path:line>` or `Evidence checked: none — <reporter-only reason>` in the `Statement` cell. `none` is allowed ONLY when the row's nature is "only the reporter can answer this" (reporter-side data, business priority, environment they observed). A row with `none` that *could* have been answered by code or logs is a defect.
@@ -26,7 +26,7 @@
26
26
  - Pre-verification entry gate (resolved & enforced by `okstra render-bundle` prep — the lead does NOT recompute it):
27
27
  - the verification target (scope / worktree / base / stages / source reports / diff stat) is injected as the `VERIFICATION_TARGET` block. The lead MUST treat it as authoritative and MUST NOT re-pick a target from the brief.
28
28
  - **whole-task scope** (`--stage auto`, default): prep has already verified every Stage Map stage is `status:done` in `consumers.jsonl`, every done stage's `head_commit` is an ancestor of the task worktree HEAD (all stage branches merged), and the worktree is clean outside `.okstra/`. If any check failed the run never started (PrepareError); a started whole-task run is therefore a fully-merged, clean target.
29
- - **whole-task read-only 아니라 mutating phase 다.** whole-task 모드는 진입 아직 task 브랜치에 머지되지 않은 done stage 들을 `--no-ff` 자동 머지해 통합 커밋을 생성하고, 이어서 정리 가능한 stage worktree·registry stage-key·stage 브랜치를 제거한다. 머지 충돌이 발생하면 충돌 파일을 보고하고 중단한다(사용자가 수동 해소 재시도). 미커밋 변경이 남은 stage worktree 보존한다. 따라서 entry gate 말하는 "fully-merged, clean target" 자동 통합 단계가 끝난 뒤의 상태이며, whole-task final-verification 통합 커밋을 만드는 mutating phase 취급해야 한다.
29
+ - **whole-task is a mutating phase, not a read-only one.** On entry, whole-task mode auto-merges (with `--no-ff`) the done stages not yet merged into the task branch to create an integration commit, then removes the cleanupable stage worktrees, registry stage-keys, and stage branches. If a merge conflict occurs it reports the conflicting files and aborts (the user resolves them manually and retries). A stage worktree with uncommitted changes remaining is preserved. Therefore the "fully-merged, clean target" the entry gate above refers to is the state after this auto-integration step completes, and whole-task final-verification must be treated as a mutating phase that creates the integration commit.
30
30
  - **single-stage scope** (`--stage N`): prep verified stage N is `status:done` and its isolated stage worktree exists and is clean. Other stages' state is irrelevant. A single-stage run is a partial verification: it MUST NOT recommend plain `release-handoff`, but MAY recommend `release-handoff(stage-group)` when the verdict is `accepted` — the stage becomes PR-eligible for a stage-group handoff.
31
31
  - the lead still captures `git status --short` from the injected worktree to confirm the analysis ran against the delivered work-tree state; an unexpected divergence (dirty tree outside `.okstra/`, missing worktree) is a `tool-failure`, not a silent proceed.
32
32
  - Required deliverable shape (final report, in addition to the standard sections):
@@ -67,7 +67,7 @@
67
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.
68
68
  - Section heading contract (BLOCKING — validator scans for these literal English substrings):
69
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.
70
- - Korean translations are allowed in parentheses (e.g. `### Recommended Option (권장 옵션)`), but the English keyword must be present verbatim in the heading line.
70
+ - Korean translations are allowed in parentheses (e.g. `### Recommended Option (Korean gloss)`), but the English keyword must be present verbatim in the heading line.
71
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.
72
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.
73
73
  - Required deliverable shape (final report, in addition to the standard sections):
@@ -82,7 +82,7 @@
82
82
  - **Keep the table at exactly 5 columns** — do NOT add a column. `validators/validate-implementation-plan-stages.py` parses `stage | title | depends-on | step-count | exit-contract-summary` and silently skips any row that is not exactly 5 cells, so a 6th column would drop every stage and bypass S2–S11.
83
83
  - **Multi-project plans only** (the plan's work spans more than one project — see the Project-boundary partition rule below): prefix each stage's `title` cell with a `[<project>]` tag (e.g. `[okstra] Add X`) so the project each stage belongs to is readable at a glance, and add exactly one line directly under the Stage Map table — `Cross-project parallelism: <which per-project stages run in parallel, which are sequenced, and the cross-project dependency that forces each sequencing>`. Single-project plans omit both the tag and the line.
84
84
  - **Per-stage slice declaration (mandatory lines, directly under the `## 5.5.<i> Stage <i>:` heading, before `### Carry-In`):**
85
- - `Slice value: <the one user-observable increment this stage delivers, end-to-end>` — describe WHAT starts working from the consumer's view (e.g. "X 조회하면 Y 가 반환된다"), NOT a layer name ("repository 추가"). Validator S10a rejects a missing/empty value.
85
+ - `Slice value: <the one user-observable increment this stage delivers, end-to-end>` — describe WHAT starts working from the consumer's view (e.g. "querying X returns Y"), NOT a layer name ("add a repository"). Validator S10a rejects a missing/empty value.
86
86
  - `Acceptance: <the observable pass condition or the exact command>` — the signal that proves the slice is done; normally the same test command that the `RED:` step below flips to PASS. Validator S10b rejects a missing/empty value.
87
87
  - **Test-case design (mandatory three lines unless the stage carries a `TDD exemption:`):** the plan, not the executor, decides which cases the stage's tests must cover, so a stage cannot ship with only one happy-path assertion. Declare all three:
88
88
  - `Test case (success): <input → expected, the command/test name>` — the happy path: a valid input that proves the slice works end-to-end.
@@ -91,9 +91,9 @@
91
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.
92
92
  - **Per-stage subsections** (`## 5.5.<i> Stage <i>: <title>` for each `i`), each containing the four required subsections:
93
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.
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`).
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 (no lower time bound; it may span several files that change together); 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`).
95
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:
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.
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: <reason>` 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.
97
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.)
98
98
  The manifest lives at the **task level** (`<task_root>/qa/`, path token `TASK_QA_PATH`) and is shared across planning → implementation → final-verification. Layout split: executable scripts (conformance + any real-IO test) live under `<task_root>/qa/scripts/`; data sidecars (`conformance-manifest.json`, `result-*.json`) stay at the `qa/` root. This declaration is enforced at four layers: `validators/validate-implementation-plan-stages.py` check **S11** forces every stage to carry one of the two lines; at the planning boundary `validators/validate-run.py` `_validate_planning_conformance_declared` fails when a stage that declared `Conformance tests:` has no matching `-stage-<N>` entry in the shared manifest (a declaration that was never materialized); the manifest JSON structure — including each entry's `script` living under `qa/scripts/` — is enforced by `validate_conformance_manifest` (called from both the run path and validate-run); and the result gate (each script's `QA-RESULT`) is enforced by the verifier Tier3 + validate-run.
99
99
  - `### Stage Exit Contract` — predicted added/modified files, newly exposed identifiers/types/endpoints, downstream-usable resources.
@@ -104,14 +104,14 @@
104
104
  - **Different repos** — a single okstra task **cannot** span repos: every stage worktree is a `git worktree add` in one repo's main checkout (one `<project-id>`), the run-index / manifests / registry are keyed to that one project, and the edit allowlist only covers that project's tree plus `~/.okstra/worktrees/**`. This is a structural limit, not a style preference. Therefore cross-repo work MUST be split into **a separate okstra run per repo** — never modelled as stages of one task. State, in the Stage Map `Cross-project parallelism:` line, whether those per-repo runs can proceed in parallel. To avoid re-deriving shared analysis, the second repo's run should consume the first run's relevant plan/decision artifacts as brief Source Material (see the cross-project dependency rows below).
105
105
  - **Parallel-feasibility check (mandatory for every multi-project plan):** disjoint files (S9 below) is necessary but NOT sufficient for parallelism — a cross-project API/contract/schema/deploy-order dependency forces sequencing even when no file overlaps. For each pair of projects, explicitly determine and record (in the `Cross-project parallelism:` line) whether they are independent (run in parallel) or sequenced (and the exact dependency that forces the order).
106
106
  - **Parallel-safety invariant (BLOCKING):** any two stages that are both `depends-on (none)` MUST predict disjoint file sets in their `Stage Exit Contract`. Two parallel `implementation` runs would otherwise edit the same file concurrently. Work touching a shared file must either go in one stage or be ordered with `depends-on`. Enforced by `validators/validate-implementation-plan-stages.py` check S9.
107
- - **Cross-project dependency rows (`crossProjectDependencies` 배열 `## Cross-Repo Carry` 부록을 대체):** 프로젝트(다른 repo / 다른 top-level 독립 배포 모듈 / published 패키지) 대한 의존은 freeform `## Cross-Repo Carry` 부록이 아니라 **구조 필드 `crossProjectDependencies` 의 `XP-NNN` 행**으로 기록한다. 프로젝트 의존마다 XP 행을 두고, 양방향 해당하는 `direction` 채운다(렌더는 `### Cross-Project Dependencies` §5.4; 단일 프로젝트 계획은 배열). 필드는 subsection 다음으로 대체한다 — `requiredWork`(상대가 만들어야 구체 작업) / `verificationSignal`( run 관측할 신호) / `linkedWork`(신호 충족 막히는 계획의 stage·step) / `howToStart`(상대 repo 에서의 정확한 handoff).
108
- - `direction: upstream-precondition` — run 상대의 **선행 작업을 기다림(선행 필수)**: `requiredWork` = 상대가 먼저 구현해야 구체 작업, `verificationSignal` = run 진행 관측해야 할 신호(PR 머지 / 엔드포인트 live / 버전 publish), `linkedWork` = 신호 충족 막히는 계획의 stage·step, `howToStart` = 상대 repo 에서 `okstra-brief-gen`(**이 보고서의 절대경로를 Source Material 인용** 유일하게 허용된 cross-`<PROJECT_ROOT>` read) → `okstra-run`.
109
- - `direction: downstream-carry` — run 상대가 것을 **만들어 (기존 carry)**: `requiredWork` = 상대가 후속 구현할 self-contained B-portion(상대 관점의 신규 `R-NNN`·제안 stage·영향 파일), `verificationSignal` = 상대가 진행 확인할(이 run 인도한) 신호, `linkedWork` = 신호를 인도하는 계획의 stage·step, `howToStart` upstream 동일. run 이미 `done` stage 상대 stage 넘기지 않는다상대가 아직 만들어야 portion 담는다.
110
- - **cross-repo 의존은 `depends-on` 으로 표현 불가:** 게이트는 repo git graph 내부 커밋만 해소하므로(`scripts/okstra_ctl/run.py` `_resolve_stage_base_commit`) 다른 repo 커밋을 가리킬 없다. cross-repo 작업은 stage 아니라 별도 okstra run + XP 행으로 분리한다(Different-repos 규칙). 상대 run 구조적으로 독립이라 run 완료 stage `done` 으로 자동 인식하지 않으며(인식해서도 repo 의 작업), XP 행은 상대 planning seed 하는 narrative 입력일 뿐이다. run 상대 repo 트리·그 `.okstra/` 쓰지 않는다(이 보고서의 XP 행만 emit). "Recognition caveat" 문구는 렌더 노트(i18n `crossProjectRecognitionNote`) 이전돼 `### Cross-Project Dependencies` 섹션에 자동 출력된다.
107
+ - **Cross-project dependency rows (`crossProjectDependencies` arrayreplaces the old `## Cross-Repo Carry` appendix):** a dependency on another project (a different repo / a different top-level independently-deployable module / a published package) is recorded not as the freeform `## Cross-Repo Carry` appendix but as an **`XP-NNN` row of the structured field `crossProjectDependencies`**. Put one XP row per project dependency and fill in whichever `direction` applies (rendered as `### Cross-Project Dependencies` §5.4; a single-project plan uses an empty array). The row fields replace the old three subsections with — `requiredWork` (the concrete work the other side must build) / `verificationSignal` (the signal this run will observe) / `linkedWork` (the stage·step of this plan that is blocked until the signal is met) / `howToStart` (the exact handoff in the other repo).
108
+ - `direction: upstream-precondition` — this run **waits on the other side's prerequisite work (precondition required)**: `requiredWork` = the concrete work the other side must implement first, `verificationSignal` = the signal this run must observe before proceeding (PR merged / endpoint live / version published), `linkedWork` = the stage·step of this plan that is blocked until the signal is met, `howToStart` = in the other repo, `okstra-brief-gen` (**cite this report's absolute path as Source Material** the only permitted cross-`<PROJECT_ROOT>` read) → `okstra-run`.
109
+ - `direction: downstream-carry` — this run **produces what the other side will consume (the existing carry)**: `requiredWork` = the self-contained B-portion the other side will implement next (from the other side's perspective, a new `R-NNN`·proposed stages·affected files), `verificationSignal` = the (this-run-delivered) signal the other side confirms before proceeding, `linkedWork` = the stage·step of this plan that delivers that signal, `howToStart` is the same as upstream. Do not hand over this run's already-`done` stages as if they were the other side's stagesinclude only the portion the other side still has to build.
110
+ - **A cross-repo dependency cannot be expressed with `depends-on`:** that gate only resolves commits inside a single repo's git graph (`scripts/okstra_ctl/run.py` `_resolve_stage_base_commit`), so it cannot point at a commit in another repo. Cross-repo work is split into a separate okstra run + XP row rather than a stage (the Different-repos rule). The other run is structurally independent, so it does not automatically recognise this run's completed stages as `done` (nor should it that is this repo's work); the XP row is only a narrative input that seeds the other side's planning. This run does not write to the other repo's tree or its `.okstra/` (it emits only this report's XP rows). The old "Recognition caveat" wording has been moved into a render note (i18n `crossProjectRecognitionNote`) and is emitted automatically in the `### Cross-Project Dependencies` section.
111
111
  - **Stage exit contract is the carry surface:** keep it as narrow as possible. Wider surface = more downstream coupling.
112
112
  - dependency / migration risk assessment (ordering constraints, data backfills, feature-flag prerequisites, repo-internal sequencing)
113
- - **Cross-Project Dependencies (조건부 필수):** 계획이 다른 프로젝트 / repo / published 패키지의 작업에 의존하면 (a) `dependencyMigrationRisk` `kind: cross-project` DM 행을, (b) `crossProjectDependencies` 매칭 `XP-NNN` 행을 둔다. upstream-precondition 행은 `requiredWork`·`verificationSignal`·`howToStart` 가 구체적이어야 한다 — `validators/validate-run.py` DM `cross-project` ⇒ `direction: upstream-precondition` XP ≥1 을, 스키마가 필드 비-빈을 강제한다. cross-project 의존은 soft Recommended Next Step 아니라 구조화된 선행 필수로 기록한다. 단일 프로젝트 계획은 배열.
114
- - **recommendedNextSteps 정책:** cross-project 선행/후속의 substance `crossProjectDependencies` 두고, `§3 Recommended Next Steps` 에는 섹션(`§5.4 Cross-Project Dependencies`) 가리키는 포인터만 둔다 이중 기록 금지.
113
+ - **Cross-Project Dependencies (conditionally required):** when the plan depends on work in another project / repo / published package, add (a) a `kind: cross-project` DM row to `dependencyMigrationRisk`, and (b) a matching `XP-NNN` row to `crossProjectDependencies`. An upstream-precondition row must have concrete `requiredWork`·`verificationSignal`·`howToStart` — `validators/validate-run.py` enforces that a DM `cross-project` ⇒ at least one `direction: upstream-precondition` XP row, and the schema enforces non-empty row fields. A cross-project dependency is recorded as this structured precondition, not as a soft Recommended Next Step. A single-project plan uses an empty array.
114
+ - **recommendedNextSteps policy:** keep the substance of cross-project preconditions/carries in `crossProjectDependencies`, and put in `§3 Recommended Next Steps` only a pointer to that section (`§5.4 Cross-Project Dependencies`) — no double recording.
115
115
  - validation checklist (pre / mid / post) — each item is an exact command or observable outcome
116
116
  - rollback strategy — exact revert path (commits, flags, migrations) and the signal that triggers rollback
117
117
  - **Requirement Coverage (mandatory, §5.5.8):** one row per concrete requirement from the task brief / packet. Assign stable IDs `R-001`, `R-002`, ... in source order. Columns: `ID | Source | Requirement | Covered by option / stage / step | Status`. `Source` cites the brief heading or file/line where the requirement came from. `Covered by` must name the specific Option Candidate and Stage/Step that satisfies it, not just "recommended option". **Enforced:** `validators/validate-run.py` `_validate_requirement_coverage_covered_by` fails a `covered` row whose `coveredBy` is bare "recommended option", names no Option/Stage/Step anchor, or cites a Stage number absent from the Stage Map (whether the cited step *actually satisfies* the requirement remains a worker `DISAGREE(f)` judgment). `Status` is one of `covered`, `gap`, or `blocked C-NNN`. If any row is `gap` or `blocked C-NNN`, the Plan Body Verification gate MUST NOT be `passed` / `passed-with-dissent`; add a matching `Blocks=approval` row for the blocker and keep `approved: false`.
@@ -120,7 +120,7 @@
120
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`.
121
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.**
122
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)
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` 로 실패시킨다.
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"). Among the majority-disagree items, those that are majority-`planner-fixable` go through one report-writer self-fix pass before being promoted to a user clarification (`prompts/lead/plan-body-verification.md` "Self-fix round"). Only items not resolved by self-fix, or that are majority-`needs-user-input`, become `Blocks=approval` clarifications. `validators/validate-run.py` `_validate_self_fix_before_clarification` fails a planner-fixable majority item promoted without a self-fix as `contract-violated`.
124
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:
125
125
  1. **Hard to reverse** — would changing the decision later cost meaningfully more than deciding now?
126
126
  2. **Surprising without context** — would a future reader, seeing only the code, wonder "why was it built this way?"?
@@ -142,5 +142,5 @@
142
142
  6. **Review-rule preflight check** — if a project review rule pack exists, map each relevant rule to the recommended option. Reject the draft if it knowingly creates a violation that the later PR reviewer would flag, unless the plan records a specific rationale and follow-up. In particular, scan for repeated helper stacks across planned files, tests that assert delegation to the same calculator/helper they exercise, public names that hide side effects, domain rules placed in repositories/adapters, and APIs made dead by this change.
143
143
  7. **Plan-body verification reconciliation (BLOCKING for implementation-planning).** For every §5.5.9 `planItems[]` entry whose verdicts make it `majority-disagree`, set that item's `clarificationId` to a `C-<N>` row that MUST exist in `## 1. Clarification Items` with `Kind` chosen per the standard policy and `Blocks=approval`. **Enforced:** `validators/validate-run.py` `_validate_plan_body_clarification_matching` recomputes each item's class and fails when a majority-disagree item has no `clarificationId`, or its `clarificationId` is dangling / points at a non-`approval` row. For `partial-consensus` and `dissent-isolated` plan-items, the dissenting opinion lives in §5.5.9 `Dissent log` and is NOT promoted to §5.
144
144
  8. **Stage Map self-check** — for every stage, count the effective rows of its `Stepwise Execution Order` table by hand; reject the draft if any stage exceeds 8. Confirm each stage declares a non-empty `Slice value:` and `Acceptance:` line, the three `Test case (success|boundary|failure):` lines (or carries a `TDD exemption:` line), and that its first step `action` starts with `RED:` with a later `GREEN:` — this is what validator S10 enforces, including S10d on the test-case lines. Read each stage's three test-case lines as a reviewer: reject any that restates the happy path in all three slots, leaves `boundary` blank, or writes `N/A` where a real edge input exists. Walk the `depends-on` graph and confirm it is a DAG (no cycle, no self-reference). For each `depends-on` link, confirm it encodes a real data/contract dependency — do NOT add links to serialise unrelated work, and do NOT split a stage merely to create more parallel stages. **Parallel-safety:** for every pair of `depends-on (none)` stages, confirm their `Stage Exit Contract` predicted file sets are disjoint; if they share a file, merge them or add a `depends-on` link (validator S9 rejects overlap). **Project-boundary:** confirm no stage mixes edits from two projects (different repo/`PROJECT_ROOT` or different top-level deployable module); if any stage does, split it per project. For multi-project plans, confirm each stage's `title` carries its `[<project>]` tag and the `Cross-project parallelism:` line under the table records the parallel-vs-sequenced determination (with the forcing dependency) for every project pair; for cross-repo work, confirm it is split into separate per-repo runs (required — one run structurally cannot touch another repo) rather than crammed into one task's stages.
145
- 9. **Cross-project dependency check** — repo / 다른 top-level 배포 모듈 / published 패키지에 대한 의존을 빠뜨리지 않았는지 확인한다. `dependencyMigrationRisk` `kind: cross-project` 행이 있으면 매칭되는 `direction: upstream-precondition` `XP-NNN` 행이 `crossProjectDependencies` 있고, `requiredWork` 추상 표현("상대 작업 완료")이 아니라 상대가 실제로 만들어야 구체 작업인지 reviewer 로서 다시 읽는다(validator S 존재만 보므로 구체성은 self-review 가 책임짐). cross-repo 작업을 task stage 욱여넣지 않고 별도 run + XP 행으로 분리했는지, cross-project substance `§3 Recommended Next Steps` 중복되지 않고 `§5.4 Cross-Project Dependencies` 에만 있는지 확인한다.
146
- 10. **Decision-draft materialization check** — `decisionDrafts` 비어있지 않으면, 매칭 materialization step(`.okstra/decisions/<NNNN>-<slug>.md` 생성) 어느 stage stepwise 존재하는지, draft 개수와 materialization step 1:1 대응하는지 reviewer 로서 확인한다. validator step *존재*만 보므로 `<NNNN>-<slug>` 정확성·개수 대응은 self-review 가 책임진다.
145
+ 9. **Cross-project dependency check** — confirm you have not missed a dependency on another repo / another top-level deployable module / a published package. If `dependencyMigrationRisk` has a `kind: cross-project` row, confirm a matching `direction: upstream-precondition` `XP-NNN` row exists in `crossProjectDependencies`, and re-read as a reviewer whether its `requiredWork` is the concrete work the other side must actually build rather than an abstract phrase ("other side's work done") — validator S only checks existence, so concreteness is the self-review's responsibility. Confirm cross-repo work is split into a separate run + XP row instead of being crammed into one task's stages, and that the cross-project substance is not duplicated in `§3 Recommended Next Steps` but lives only in `§5.4 Cross-Project Dependencies`.
146
+ 10. **Decision-draft materialization check** — when `decisionDrafts` is non-empty, confirm as a reviewer which stage's stepwise order contains the matching materialization step (creating `.okstra/decisions/<NNNN>-<slug>.md`) and that the number of drafts corresponds 1:1 with the materialization steps. The validator only checks the *existence* of the step, so the `<NNNN>-<slug>` correctness and count correspondence are the self-review's responsibility.
@@ -46,4 +46,4 @@ The bulk of this profile's body is split into three sidecars so the lead's Phase
46
46
  | `prompts/profiles/_implementation-verifier.md` | Phase 5, between Executor stage completion and the first verifier dispatch | Verifier roles, Two-tier command lookup, deny-list, discrepancy rule, Read-only command log, verifier-specific forbidden actions |
47
47
  | `prompts/profiles/_implementation-deliverable.md` | Start of Phase 6 (after Phase 5.5 convergence completes, before report-writer dispatch prompt construction) | Required deliverable shape, Validation / TDD evidence rules, Verifier results structure, Self-review pass, Lead post-stage persistence |
48
48
 
49
- **Phase 5 / 6 진입 해당 sidecar lead context 없으면 BLOCKING — phase 진입 거부.** Lead sidecar read 1 turn 안에 phase 후속 action 으로 이어가야 한다 ( sidecar 룰은 read turn 부터 효력 발생).
49
+ **Entering Phase 5 / 6 while the relevant sidecar is not in the lead's context is BLOCKING — the phase entry is refused.** After reading a sidecar, the lead must continue into the phase's follow-up action within a single turn (i.e. the sidecar's rules take effect starting from the very turn it is read).
@@ -39,7 +39,7 @@
39
39
  - Expected output emphasis:
40
40
  - the `## 5.9 Improvement Candidates` table populated with rows that obey the 10-column schema from `validators/validate_improvement_report.py` (Cand ID `I-NNN`, Lens from whitelist, Title, Scope ⊆ scan-scope, Severity, Effort, Consensus, Source workers `<worker>:<id>` from {claude, codex, antigravity}, Recommended next-phase ∈ {requirements-discovery, implementation-planning, error-analysis}, Evidence as path:line list)
41
41
  - `Consensus` cells in `## 5.9 Improvement Candidates` use the table enum exactly: `full`, `partial`, `contested`, `worker-unique`. Map convergence's `full-consensus` / `partial-consensus` labels to `full` / `partial` before writing the table.
42
- - `## 7. Final Verdict` Verdict Token ∈ {`candidates-ready`, `no-candidates`, `blocked`}; Direction `routing`; Next Step "사용자에게 후보 K 선택 의뢰 (## 5.9 표 참조)"
42
+ - `## 7. Final Verdict` Verdict Token ∈ {`candidates-ready`, `no-candidates`, `blocked`}; Direction `routing`; Next Step "ask the user to select K candidates (see the ## 5.9 table)"
43
43
  - `## 3. Recommended Next Steps` first entry summarises per-candidate routing and proposes new task-key names of the form `<task-group>/imp-<Cand-ID>`
44
44
  - this report is authored free-form (improvement-discovery is not in the data.json schema enum); after the markdown is written, the report-writer runs `okstra inject-report-index <report.md> --report-language <en|ko>` to add the top-of-report Index + `I-NNN`/`C-NNN` scroll anchors. The run validator fails the report when the Index anchor is missing.
45
45
  - Clarification request policy (phase-specific addenda — shared policy is in `_common-contract.md`):
@@ -28,12 +28,12 @@
28
28
  `okstra handoff local-checkout --project-root <project root> --project-id <id> --task-group <g> --task-id <t>`
29
29
  Exit 1 means a precondition failed (MAIN worktree dirty, registry entry missing, or checkout failed): show the error verbatim and re-ask the action selection. On success the okstra task worktree no longer exists — the lead's cwd is gone, so EVERY subsequent step (final-report authoring included) MUST use absolute paths or run from the MAIN worktree. Then route to the final-report self-review pass.
30
30
  - **stage-group mode step order** (overrides the default Q1→Q3 sequence): after Q1 picks `push + PR`, run (1) base-branch selection first — identical to Q2 below, because the dependency-closure check needs `origin/<base>`; (2) G2 stage confirmation (step 1g); (3) assemble (step 2g); then Q2b and Q3 as usual, with the collector branch as the PR head.
31
- 1g. **G2 — stage confirmation**: the stage selection already happened before the run (wizard `handoff_stage_pick`, or the CLI `--stages` flag) and is fixed in `HANDOFF_STAGES`. Display it as a one-line confirmation (`PR 대상 stage: <csv> — 진행합니다`) and proceed; do NOT re-ask the multi-select. Only if `HANDOFF_MODE` is `stage-group` but `HANDOFF_STAGES` is empty (defensive, should not happen) run `okstra handoff eligible --plan-run-root <plan-run-root> --approved-plan <approved plan path>` and ask the user to pick from the eligible stages.
31
+ 1g. **G2 — stage confirmation**: the stage selection already happened before the run (wizard `handoff_stage_pick`, or the CLI `--stages` flag) and is fixed in `HANDOFF_STAGES`. Display it as a one-line confirmation (`PR target stage: <csv> — proceeding`) and proceed; do NOT re-ask the multi-select. Only if `HANDOFF_MODE` is `stage-group` but `HANDOFF_STAGES` is empty (defensive, should not happen) run `okstra handoff eligible --plan-run-root <plan-run-root> --approved-plan <approved plan path>` and ask the user to pick from the eligible stages.
32
32
  2g. **assemble**: run `okstra handoff assemble --plan-run-root <...> --approved-plan <...> --project-root <project root> --project-id <id> --task-group <g> --task-id <t> --work-category <c> --stages <csv> --base <chosen-base>`. Exit 2 means a stage-vs-stage merge conflict: show the `conflicts` paths and stop (route: reshape the group or resolve manually). Exit 1 means an eligibility/closure violation: show the error verbatim and re-ask G2. On success the returned `branch` is the PR head branch for every subsequent step.
33
33
  2. **PR base branch** (only when the user picked `push + PR`) — present four options and capture exactly one:
34
34
  - `preprod`
35
35
  - `main`
36
- - `직접 입력` (free-form branch name; lead validates the name exists on origin via `git ls-remote --heads origin <name>` and re-asks on failure)
36
+ - `direct input` (free-form branch name; lead validates the name exists on origin via `git ls-remote --heads origin <name>` and re-asks on failure)
37
37
  The chosen base MUST NOT equal the feature branch. If it does, re-ask.
38
38
  2b. **Pre-merge conflict probe** (only when the user picked `push + PR`) — before the push/PR step, the lead MUST refresh the base ref and probe for merge conflicts against it:
39
39
  - run `git fetch origin <chosen-base>` (read-only on the local working tree).
@@ -85,7 +85,7 @@
85
85
  - `- PR creation skipped: <reason>` for any user-driven cancellation
86
86
  - **Local Checkout Outcome**: one of
87
87
  - `- Not run (user picked push + PR or skip).`
88
- - `- Checked out <branch> into <main worktree path>; okstra task worktree <path> removed. Next: 로컬 테스트 PR 하려면 okstra-run 으로 release-handoff 재진입 → push + PR.`
88
+ - `- Checked out <branch> into <main worktree path>; okstra task worktree <path> removed. Next: to run a local test and then open a PR, re-enter release-handoff via okstra-run → push + PR.`
89
89
  - **Stage Group** (stage-group mode only): selected stages, each stage's single-stage verification report path + quoted `Verdict Token` row, collector branch name, merge commit SHAs from assemble, and the dependency-closure verdict (from the assemble output / error).
90
90
  - **Routing recommendation**: explicit `done` token, since release-handoff is the terminal lifecycle phase. If the run ended in `skip` or `cancel`, the recommendation MUST also state whether re-entry into release-handoff is appropriate.
91
91
  - Self-review pass before finalising the report (`Claude lead` runs this):
@@ -23,23 +23,23 @@
23
23
  - capture approval or confirmation points before the next phase starts
24
24
  - **domain alignment check**: read `<PROJECT_ROOT>/.okstra/glossary.md` and `<PROJECT_ROOT>/.okstra/decisions/` titles if present. Absent okstra memory files are normal — do not error. Validate that every `terminology:*` entry under the brief's `Open Questions` has a canonical resolution before routing. Fuzzy or overloaded terms in the brief MUST be resolved to a single canonical term in this phase.
25
25
  - Fan-out (multi-item / multi-domain requests only):
26
- - 단일 항목/단일 도메인 요청은 fan-out 하지 않는다(현행 단일 라우팅 보존).
27
- - 요청이 2개 이상 도메인에 걸치거나 독립 착수 가능한 작업 항목이 2개 이상이면,
28
- 항목을 `runs/requirements-discovery/fan-out/unit-<NNN>.md` packet 으로 발행한다.
29
- packet `templates/reports/fan-out-unit.template.md` 형식을 따르며 frontmatter
26
+ - A single-item / single-domain request is not fanned out (preserving the current single-routing behaviour).
27
+ - When a request spans two or more domains, or has two or more independently-startable work items,
28
+ publish each item as a `runs/requirements-discovery/fan-out/unit-<NNN>.md` packet.
29
+ The packet follows the `templates/reports/fan-out-unit.template.md` format, and its frontmatter
30
30
  `domain`(work-category 5-enum: bugfix / feature / refactor / ops / improvement),
31
- `depends-on`(같은 fan-out unit-id inline 리스트 `[unit-001]`, 없으면 `[]`),
32
- `recommended-next-phase`(error-analysis | implementation-planning) 채운다.
33
- - `runs/requirements-discovery/fan-out/index.md` packet depends-on 위상순서로
34
- 번호목록(`1. unit-001`)으로 나열한다(생성 뷰; 직접 편집 금지 명시). depends-on 그래프는
35
- DAG 여야 한다 — `validate_fanout` 순환을 검증 실패로 거부하므로, 순환이 생기면
36
- packet finalize 하기 전에 문제 의존을 끊어 DAG 만든다.
37
- - brief `Related Task Graph` 에서 seed ordering edge 는 각 packet `depends-on`
38
- final report routing 근거에 보존한다. `duplicates` / `related-to` edge
39
- fan-out 순서로 해석하지 말고 중복 작업 방지 / scope alignment 참고로만 사용한다.
40
- - 최종 리포트에는 분해 결과를 중복하지 말고 "fan-out: N packets → fan-out/index.md" 한 줄
41
- 포인터만 둔다. packet 실행은 별도다: 사용자가 `okstra-run --task-brief <packet 경로>` 로
42
- 단위를 새 task-key 시작한다( phase 다운스트림 run 직접 시작하지 않는다).
31
+ `depends-on`(an inline list of unit-ids within the same fan-out `[unit-001]`, or `[]` if none),
32
+ `recommended-next-phase`(error-analysis | implementation-planning) are filled in.
33
+ - in `runs/requirements-discovery/fan-out/index.md`, list the packets in depends-on topological order
34
+ as a numbered list (`1. unit-001`) (a generated view; explicitly do not hand-edit). The depends-on graph
35
+ must be a DAG — `validate_fanout` rejects a cycle as a validation failure, so if a cycle appears,
36
+ break the offending dependency to make it a DAG before finalizing the packet.
37
+ - an ordering edge seeded from the brief's `Related Task Graph` is preserved in each packet's `depends-on`
38
+ and in the final report's routing rationale. A `duplicates` / `related-to` edge is
39
+ not interpreted as fan-out ordering; use it only as a reference for avoiding duplicate work / scope alignment.
40
+ - in the final report, do not duplicate the decomposition result; keep only the one-line "fan-out: N packets → fan-out/index.md"
41
+ pointer. Packet execution is separate: the user starts each unit as a new task-key via
42
+ `okstra-run --task-brief <packet path>` (this phase does not directly start any downstream 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
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.
@@ -63,5 +63,5 @@
63
63
  - full implementation design unless it is required to decide the next phase
64
64
  - **source code edits, plan authoring, builds, or deployments** — this run only classifies the work and routes it; deeper analysis and planning belong to subsequent phases
65
65
  - **writes outside `<PROJECT_ROOT>/.okstra/`** — this phase only uses okstra's artifact root. Glossary additions land in `<PROJECT_ROOT>/.okstra/glossary.md` (via `okstra-brief-gen` Step 4.5); decision drafts land in `<PROJECT_ROOT>/.okstra/decisions/` (via `implementation-planning`).
66
- - 작업 단위 분해(fan-out) phase 의 in-scope 단, 단위의 *해법 설계*·소스
67
- 편집·plan 작성은 여전히 non-goal 이며 다운스트림 phase 담당한다
66
+ - work-unit decomposition (fan-out) is in-scope for this phase but each unit's *solution design*·source
67
+ edits·plan authoring remain non-goals and are handled by downstream phases
@@ -0,0 +1 @@
1
+ Run one Bash tool call, starting with the literal token `okstra` (never wrapped in `if`/`eval`/`export`/`$(...)`/`VAR=...`/`||`/`&&`/`npx` — a non-literal leading token defeats the `Bash(okstra:*)` permission match):
@@ -0,0 +1 @@
1
+ If the call fails with `unknown command: preflight`, the `okstra` binary on PATH predates this skill — tell the user to update it (`npm i -g okstra@latest`), then stop (`/okstra-setup` does not update the binary).
@@ -0,0 +1 @@
1
+ Every subsequent `okstra <subcmd>` call self-bootstraps its Python path, so this skill never needs `okstra paths --shell` / `export PYTHONPATH=...`.