okstra 0.87.2 → 0.88.1
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.kr.md +6 -6
- package/README.md +6 -6
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/prompts/profiles/_implementation-deliverable.md +1 -0
- package/runtime/prompts/profiles/_implementation-executor.md +1 -0
- package/runtime/prompts/profiles/implementation-planning.md +9 -4
- package/runtime/python/okstra_ctl/clarification_items.py +23 -8
- package/runtime/python/okstra_ctl/report_views.py +10 -3
- package/runtime/python/okstra_ctl/run.py +16 -2
- package/runtime/schemas/final-report-v1.0.schema.json +19 -0
- package/runtime/templates/reports/final-report.template.md +5 -0
- package/runtime/templates/reports/implementation-planning-input.template.md +1 -1
- package/runtime/validators/validate-implementation-plan-stages.py +21 -0
package/README.kr.md
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
## 1. 용도
|
|
23
23
|
|
|
24
|
-
`okstra` 는 **Claude Code 안에서 lead + worker 모델로 작업을 cross-verify 하기 위한 정형화된 task 실행 러너**입니다. Claude lead 가 phase 진행을 주도하고, 독립된 분석 worker — **기본 Claude · Codex** (
|
|
24
|
+
`okstra` 는 **Claude Code 안에서 lead + worker 모델로 작업을 cross-verify 하기 위한 정형화된 task 실행 러너**입니다. Claude lead 가 phase 진행을 주도하고, 독립된 분석 worker — **기본 Claude · Codex** (Antigravity 는 옵션으로 명시할 때만 추가) — 와 최종 보고서 작성을 전담하는 report-writer 를 dispatch 합니다.
|
|
25
25
|
|
|
26
26
|
설계의 세 가지 원칙:
|
|
27
27
|
|
|
@@ -61,7 +61,7 @@ okstra/ npm 패키지 = repo 루트
|
|
|
61
61
|
~/.okstra/ 런타임 홈, `okstra install` 이 생성
|
|
62
62
|
├── version 패키지 버전 stamp
|
|
63
63
|
├── lib/python/ okstra_project/, okstra_ctl/, okstra_token_usage/, lib/
|
|
64
|
-
├── bin/ okstra.sh, codex-exec,
|
|
64
|
+
├── bin/ okstra.sh, codex-exec, antigravity-exec, ...
|
|
65
65
|
├── templates/ report asset, settings template
|
|
66
66
|
├── prompts/ lead 운영 계약(prompts/lead/*) + coding-preflight 리소스 팩
|
|
67
67
|
├── installed-runtimes.json 설치된 runtime adapter 매니페스트
|
|
@@ -81,7 +81,7 @@ okstra/ npm 패키지 = repo 루트
|
|
|
81
81
|
└── okstra-*/SKILL.md 사용자 노출 스킬 6종만 (setup/brief/run/memory/inspect/schedule)
|
|
82
82
|
|
|
83
83
|
~/.claude/agents/ Claude Code 가 자동 인식 (`~/.claude` 가 있을 때)
|
|
84
|
-
└── {claude,codex,
|
|
84
|
+
└── {claude,codex,antigravity,report-writer}-worker.md worker subagent 정의
|
|
85
85
|
(Claude Code multi-agent dispatch 필수)
|
|
86
86
|
|
|
87
87
|
<프로젝트 루트>/.okstra/
|
|
@@ -185,7 +185,7 @@ Claude Code 세션 밖에서 task 를 시작하려면:
|
|
|
185
185
|
|
|
186
186
|
0.7.0 / 0.8.0 에서 추가된 주요 플래그:
|
|
187
187
|
|
|
188
|
-
- `--executor claude|codex|
|
|
188
|
+
- `--executor claude|codex|antigravity` — `--task-type implementation` 에서 파일을 mutate 할 provider 를 선택합니다. 나머지 두 provider 는 같은 run 에서 strict read-only verifier 로 dispatch 됩니다 ([`docs/kr/cli.md`](docs/kr/cli.md#--executor)).
|
|
189
189
|
- `--work-category bugfix|feature|refactor|ops|improvement` — `requirements-discovery` phase 를 건너뛰는 경우 작업 분류를 직접 지정합니다.
|
|
190
190
|
- `--approve` — `--approved-plan` 과 함께 사용하면 plan 의 YAML frontmatter `approved` field 를 `false` → `true` 로 toggle 합니다 (제거된 `--ack-approved` alias 와 구 `[ ] Approved` 체크박스 마커 대체).
|
|
191
191
|
|
|
@@ -194,8 +194,8 @@ Claude Code 세션 밖에서 task 를 시작하려면:
|
|
|
194
194
|
- **모든 task-type 격리 worktree 자동 provisioning** — prepare 단계에서 `okstra-ctl` 이 task-key 당 한 번 `git worktree add ~/.okstra/worktrees/<project-id>/<task-group-segment>/<task-id-segment>` 를 수행해 격리된 working tree 와 브랜치 `<work-category-prefix>-<task-id-segment>` (예: `feat-dev-9436`, `fix-dev-7311`) 를 만듭니다. base ref 는 사용자가 `--base-ref` 로 지정 (release-handoff PR base picker 와 동일한 메뉴: `main` / `dev` / `staging` / `preprod` / `prod` / 직접 입력). 첫 phase 에서는 필수이며, okstra-run skill 이 `AskUserQuestion` 으로 수집합니다 — 비대화형 호출자는 `--base-ref` 플래그를 직접 전달해야 prepare 가 통과합니다. 같은 task-key 의 후속 **비-`implementation`** phase(`requirements-discovery` → `error-analysis` → `implementation-planning` → `final-verification` → `release-handoff`)는 같은 path/branch를 재사용합니다. 반면 `implementation` run 은 **stage 격리** 로 동작합니다 — 각 run 이 자신의 `.../<task>/stage-<N>/` worktree(브랜치 `<prefix>-<task>-s<N>`)에서 한 stage 만 실행하므로, 독립(`depends-on (none)`) stage 를 별도 run 으로 **동시에 병렬 구현** 할 수 있습니다(트리 공유 없음). registry 는 task-key 와 **stage-key** 를 함께 flock 예약합니다. caller 가 이미 다른 worktree 안에 있거나 project_root 가 git repo 가 아니면 provisioning 은 skip 됩니다(stage 격리도 평면 경로로 degrade). 수동 cleanup: `git worktree remove <path>` → `git branch -D <branch>` + registry 항목 release/remove. 상세: [`docs/kr/architecture.md`](docs/kr/architecture.md) *Task type* 섹션, [`docs/superpowers/specs/2026-06-06-stage-worktree-isolation-design.md`](docs/superpowers/specs/2026-06-06-stage-worktree-isolation-design.md), [`docs/kr/cli.md#--executor`](docs/kr/cli.md#--executor).
|
|
195
195
|
- **`release-handoff` lifecycle phase** — `final-verification` 이 `verdict=accepted` 를 반환한 직후에 실행되는 신규 phase. lead 가 Claude worker (drafter) 를 통해 commit message · PR body 후보를 만들고, `AskUserQuestion` 으로 사용자에게 (1) action (`commit only` / `commit + PR` / `skip`), (2) PR base branch (`staging` / `preprod` / `prod` / `main` / `dev` / 직접 입력), (3) message handling (`use as-is` / `edit then proceed` / `cancel`) 세 가지를 순서대로 묻습니다. 사용자가 메뉴로 선택한 git / gh 명령만 실행되고, force-push, base 브랜치 직접 push, hook bypass (`--no-verify`), release publish (`gh release`, `npm publish`, ...) 는 금지됩니다. 이 phase 에서는 소스 코드를 수정하지 않습니다. profile: [`prompts/profiles/release-handoff.md`](prompts/profiles/release-handoff.md).
|
|
196
196
|
- **PR 본문 템플릿 설정** (release-handoff) — PR 본문은 마크다운 템플릿에서 채워집니다. 해석 우선순위: 1회성 override (`--pr-template-path` 또는 okstra-run Step 6 prompt) → `<project_root>/.okstra/project.json` 의 `prTemplatePath` → `~/.okstra/config.json` 의 `prTemplatePath` → 스킬 디폴트 `~/.claude/skills/templates/prd/pr-body.template.md`. 템플릿 등록 명령: `okstra config set pr-template-path <path> [--scope project|global]` (project 스코프는 project root 기준 상대경로 허용, global 스코프는 절대경로 또는 `~/` 시작 경로만 허용). 현재 설정 확인: `okstra config get pr-template-path --scope all` 은 각 스코프 값 + 실제로 우승하는 경로(effective) 까지 보여줍니다. 디폴트 템플릿은 `## Summary` / `## Changes` / `## Test plan` / `## Linked issues` 4 섹션 + HTML 주석으로 lead 작성 가이드를 포함하며, PR 생성 직전에 lead 가 주석을 제거합니다.
|
|
197
|
-
- **프로파일 워커 로스터 검증** — `--workers <csv>` 와 okstra-run Step 6 의 워커 prompt 는 해당 프로파일의 `Required workers:` 블록에 선언된 워커 ID 만 허용합니다. 프로파일에 없는 워커 (예: `release-handoff` 에서 `codex` / `
|
|
198
|
-
- **실험적 Codex lead adapter** — `okstra codex-run <render-bundle args...>` 가 Claude Code 를 띄우지 않고 `leadRuntime=codex` task bundle 을 준비합니다. 이어서 `okstra codex-dispatch --project-root <dir> --run-manifest <path>` 로 roster 중 Codex-side 지원 subset 을 실행합니다(Codex/
|
|
197
|
+
- **프로파일 워커 로스터 검증** — `--workers <csv>` 와 okstra-run Step 6 의 워커 prompt 는 해당 프로파일의 `Required workers:` 블록에 선언된 워커 ID 만 허용합니다. 프로파일에 없는 워커 (예: `release-handoff` 에서 `codex` / `antigravity`) 를 요청하면 명확한 에러로 거절되고, 인터랙티브 prompt 도 프로파일이 실제로 받는 워커만 보여줍니다.
|
|
198
|
+
- **실험적 Codex lead adapter** — `okstra codex-run <render-bundle args...>` 가 Claude Code 를 띄우지 않고 `leadRuntime=codex` task bundle 을 준비합니다. 이어서 `okstra codex-dispatch --project-root <dir> --run-manifest <path>` 로 roster 중 Codex-side 지원 subset 을 실행합니다(Codex/Antigravity CLI worker 기본, Codex report-writer 는 `--enable-codex-report-writer --report-writer-codex-model <model>` opt-in 필요). 성공한 Codex report-writer dispatch 는 token/cost substitution, HTML view 렌더, follow-up stub 생성, run validation 을 순서대로 자동 실행합니다. Claude lead 경로와 같은 manifest/schema 를 공유하며, 프로젝트를 Codex 전용 fork 로 복제하지 않습니다.
|
|
199
199
|
- **다단계 `implementation-planning` / `implementation`** — `implementation-planning` 은 항상 Stage Map + N 개 stage 섹션으로 산출합니다. 각 stage 의 step 은 ≤ 6 이며 `depends-on (none)` 인 stage 들은 별도 `implementation` run 으로 병렬 실행할 수 있습니다. 각 `implementation` 호출은 한 stage 만 실행하고 (`--stage <auto|N>`), 자동 생성되는 evidence sidecar (`carry/stage-<N>.json`) 가 다음 stage 의 carry-in 으로 흡수됩니다. `implementation-planning` run 디렉터리에 `consumers.jsonl` 역링크가 누적되어 어느 run 이 어느 stage 를 소비했는지 추적됩니다.
|
|
200
200
|
- **Phase 6 plan-body verification (implementation-planning 전용)** — Report writer worker 가 final-report draft 를 작성한 직후, 사용자 승인 gate 직전에 lead 가 1 라운드의 사후 검증을 추가로 돌립니다. 합성된 `## 5.5` implementation plan deliverables 본문에서 `P-Opt-*` / `P-Step-*` / `P-Dep-*` / `P-Val-*` / `P-Rb-*` plan-item 을 추출해 모든 analyser 워커에게 `AGREE` / `DISAGREE(a-e)` / `SUPPLEMENT` 평결을 요청합니다. 집계된 gate 결과는 `passed` / `passed-with-dissent` / `blocked-by-disagreement` / `aborted-non-result` 중 하나입니다. frontmatter `approved` 필드는 항상 `false` 로 발행되며, blocking gate 결과는 이를 false 로 유지하고 `## 1. Clarification Items` row 로 변환합니다. 빠른 반복용 opt-out 은 `--no-plan-verification` 입니다. 세부 계약: [`prompts/lead/convergence.md`](prompts/lead/convergence.md) "Plan-body verification mode", [`docs/kr/cli.md#--no-plan-verification`](docs/kr/cli.md#--no-plan-verification).
|
|
201
201
|
- **Brief = translation layer + Step 6.5 reporter batch confirmation** — `okstra-brief` 가 외부 입력 (이슈 ticket, 요구사항 문서, 사용자 메시지) 을 verbatim 으로 옮기되 okstra 가 추가한 부분은 labelled augmentation 으로 구분하는 translation layer 가 됐습니다. Step 6.5 가 brief 가 옮기는 과정에서 의미 변화가 발생했는지 사용자에게 일괄 확인받아 `Reporter Confirmations` 섹션에 기록하고, 모든 분석 profile 은 이 섹션의 존재를 phase 분석 진입 precondition 으로 강제합니다 (validator: `validators/validate-brief.py`).
|
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
## 1. Purpose
|
|
23
23
|
|
|
24
|
-
`okstra` is a **structured task-execution runner for Claude Code that cross-verifies work with a lead + worker model**. The Claude lead drives phase progression and dispatches independent analysis workers — **Claude and Codex by default** (with **
|
|
24
|
+
`okstra` is a **structured task-execution runner for Claude Code that cross-verifies work with a lead + worker model**. The Claude lead drives phase progression and dispatches independent analysis workers — **Claude and Codex by default** (with **Antigravity** available as an opt-in extra) — plus a dedicated report-writer for the final synthesis.
|
|
25
25
|
|
|
26
26
|
The design rests on three principles:
|
|
27
27
|
|
|
@@ -60,7 +60,7 @@ okstra/ npm package = repo root
|
|
|
60
60
|
~/.okstra/ runtime home, populated by `okstra install`
|
|
61
61
|
├── version package version stamp
|
|
62
62
|
├── lib/python/ okstra_project/, okstra_ctl/, okstra_token_usage/, lib/
|
|
63
|
-
├── bin/ okstra.sh, codex-exec,
|
|
63
|
+
├── bin/ okstra.sh, codex-exec, antigravity-exec, ...
|
|
64
64
|
├── templates/ report assets, settings template
|
|
65
65
|
├── installed-runtimes.json manifest of installed runtime adapters
|
|
66
66
|
├── installed-skills.json manifest of installed skills (used by uninstall)
|
|
@@ -79,7 +79,7 @@ okstra/ npm package = repo root
|
|
|
79
79
|
└── okstra-*/SKILL.md user-facing skills only (setup/brief/run/memory/inspect/schedule)
|
|
80
80
|
|
|
81
81
|
~/.claude/agents/ discovered automatically by Claude Code (if ~/.claude exists)
|
|
82
|
-
└── {claude,codex,
|
|
82
|
+
└── {claude,codex,antigravity,report-writer}-worker.md subagent definitions
|
|
83
83
|
(required for Claude Code multi-agent dispatch)
|
|
84
84
|
|
|
85
85
|
<project-root>/.okstra/
|
|
@@ -183,7 +183,7 @@ Spawns a fresh `claude` process and hands it the lead role. Full argument list:
|
|
|
183
183
|
|
|
184
184
|
Notable flags added in 0.7.0 / 0.8.0:
|
|
185
185
|
|
|
186
|
-
- `--executor claude|codex|
|
|
186
|
+
- `--executor claude|codex|antigravity` — pick the provider that mutates files during `--task-type implementation`. The other two providers are still dispatched as read-only verifiers (see [`docs/kr/cli.md`](docs/kr/cli.md#--executor)).
|
|
187
187
|
- `--work-category bugfix|feature|refactor|ops|improvement` — classify a task when the lifecycle skips `requirements-discovery`.
|
|
188
188
|
- `--approve` — combined with `--approved-plan`, flips the plan's YAML frontmatter `approved` field from `false` to `true` (replaces the removed `--ack-approved` alias and the older `[ ] Approved` checkbox marker).
|
|
189
189
|
|
|
@@ -192,8 +192,8 @@ Recent workflow additions (post-0.8.0, on `main`):
|
|
|
192
192
|
- **Isolated task worktree for every task-type** — prepare automatically runs `git worktree add ~/.okstra/worktrees/<project>/<group>/<task>/` on a fresh branch `<work-category-prefix>-<task-id-segment>` branched from the **user-chosen base ref** (`--base-ref`, mirroring the `release-handoff` PR-base picker: `main` / `dev` / `staging` / `preprod` / `prod` / any local ref) the first time a task-key is seen. `--base-ref` is required on first phase; the okstra-run skill collects it via `AskUserQuestion`, non-interactive callers must pass the flag explicitly. Every subsequent **non-`implementation`** phase of the same task-key (`requirements-discovery` → `error-analysis` → `implementation-planning` → `final-verification` → `release-handoff`) reuses the same path and branch, so phase N inherits the working-tree state phase N-1 left behind. `implementation` runs are **stage-isolated** instead — each run owns exactly one stage in its own `.../<task>/stage-<N>/` worktree on branch `<prefix>-<task>-s<N>`, so independent (`depends-on (none)`) stages can be implemented in parallel across simultaneous runs without sharing a tree. A global registry at `~/.okstra/worktrees/registry.json` (flock-guarded) reserves task-keys **and stage-keys** across concurrent runs; all path/branch segments are sanitised (`/`, `:`, etc. → `-`). The worktree is preserved after every run for follow-up phases, PR authoring, and rollback. Skip paths: when the caller is already inside another worktree or `project_root` is not a git repo, provisioning no-ops (stage isolation degrades to the flat path too). Manual cleanup: `git worktree remove <path>` → `git branch -D <branch>` plus releasing/removing the key from the registry. Details: [`docs/kr/architecture.md`](docs/kr/architecture.md) (*Task type* section), [`docs/superpowers/specs/2026-06-06-stage-worktree-isolation-design.md`](docs/superpowers/specs/2026-06-06-stage-worktree-isolation-design.md), and [`docs/kr/cli.md#--executor`](docs/kr/cli.md#--executor).
|
|
193
193
|
- **`release-handoff` lifecycle phase** — runs after `final-verification` returns `verdict=accepted`. The lead drafts a commit message and PR body via a Claude worker, then prompts the user with `AskUserQuestion` for three choices: action (`commit only` / `commit + PR` / `skip`), PR base branch (`staging` / `preprod` / `prod` / `main` / `dev` / free-form), and message handling (`use as-is` / `edit then proceed` / `cancel`). Only user-selected mutating git/gh commands run. Force-push, base-branch direct push, hook bypass (`--no-verify`), and release publishing (`gh release`, `npm publish`, ...) are forbidden. Source code is not edited in this phase. Profile: [`prompts/profiles/release-handoff.md`](prompts/profiles/release-handoff.md).
|
|
194
194
|
- **Configurable PR body template** (release-handoff) — the PR body is filled from a markdown template chosen in priority order: per-run override (`--pr-template-path` or the okstra-run Step 6 prompt) → `<project_root>/.okstra/project.json` `prTemplatePath` → `~/.okstra/config.json` `prTemplatePath` → bundled skill default at `~/.claude/skills/templates/prd/pr-body.template.md`. Register a template with `okstra config set pr-template-path <path> [--scope project|global]` (project scope accepts paths relative to the project root; global scope requires absolute or `~/`-prefixed). `okstra config get pr-template-path --scope all` reports every scope plus the effective winner. The bundled default ships `## Summary` / `## Changes` / `## Test plan` / `## Linked issues` with HTML comment guidance that the lead strips before opening the PR.
|
|
195
|
-
- **Profile-roster worker validation** — `--workers <csv>` (and the okstra-run Step 6 worker prompt) are now restricted to the worker IDs declared by the chosen profile's `Required workers:` block. Asking for `codex` / `
|
|
196
|
-
- **Experimental Codex lead adapter** — `okstra codex-run <render-bundle args...>` prepares a `leadRuntime=codex` task bundle without launching Claude Code. `okstra codex-dispatch --project-root <dir> --run-manifest <path>` can then run the supported Codex-side subset of the roster (Codex/
|
|
195
|
+
- **Profile-roster worker validation** — `--workers <csv>` (and the okstra-run Step 6 worker prompt) are now restricted to the worker IDs declared by the chosen profile's `Required workers:` block. Asking for `codex` / `antigravity` on a profile that does not list them (e.g. `release-handoff`) is rejected with a clear error, and the interactive prompt only offers workers the profile actually accepts.
|
|
196
|
+
- **Experimental Codex lead adapter** — `okstra codex-run <render-bundle args...>` prepares a `leadRuntime=codex` task bundle without launching Claude Code. `okstra codex-dispatch --project-root <dir> --run-manifest <path>` can then run the supported Codex-side subset of the roster (Codex/Antigravity CLI workers by default; Codex report-writer only with `--enable-codex-report-writer --report-writer-codex-model <model>`). Successful Codex report-writer dispatch runs token/cost substitution, HTML view rendering, follow-up stub generation, and run validation in order. This shares the same manifests/schemas as the Claude lead path; it does not clone the project into a separate Codex-specific fork.
|
|
197
197
|
- **Multi-stage `implementation-planning` / `implementation`** — `implementation-planning` always produces a Stage Map plus N stage sections; each stage has ≤6 steps and stages whose `depends-on (none)` can be executed in parallel by separate `implementation` runs. Each `implementation` invocation picks one stage (via `--stage <auto|N>`) and emits an evidence sidecar (`carry/stage-<N>.json`) that the next stage automatically inherits. The `implementation-planning` run directory accumulates a `consumers.jsonl` reverse-link showing which `implementation` runs consumed which stage.
|
|
198
198
|
- **Phase 6 plan-body verification (implementation-planning only)** — after the Report writer worker authors the final-report draft and before the user approval gate, the lead runs one additional verification round: it extracts `P-Opt-*` / `P-Step-*` / `P-Dep-*` / `P-Val-*` / `P-Rb-*` items from the consolidated `## 5.5` implementation plan deliverables body and dispatches them to every analyser worker as `AGREE` / `DISAGREE(a-e)` / `SUPPLEMENT`. The aggregated gate result is one of `passed` / `passed-with-dissent` / `blocked-by-disagreement` / `aborted-non-result`. The frontmatter `approved` flag is always emitted as `false`; blocking gate results keep it false and become `## 1. Clarification Items` rows. Details: [`prompts/lead/convergence.md`](prompts/lead/convergence.md) "Plan-body verification mode" and [`docs/kr/cli.md#--no-plan-verification`](docs/kr/cli.md#--no-plan-verification).
|
|
199
199
|
- **Brief as translation layer + reporter batch confirmation (Step 6.5)** — `okstra-brief` now produces the brief as a translation layer that preserves external inputs (issue ticket, requirements doc, user message) verbatim while labelling okstra augmentations. A new Step 6.5 walks the user through a single batch confirmation of any rewordings, recorded in a `Reporter Confirmations` section. Every analysis profile blocks phase entry until this section exists (validator: `validators/validate-brief.py`).
|
package/package.json
CHANGED
package/runtime/BUILD.json
CHANGED
|
@@ -14,6 +14,7 @@ are collected and convergence finished. Phase 1-5 do not need it.
|
|
|
14
14
|
- **Commit list**: each commit's SHA (or short SHA), message, and the plan step it satisfies
|
|
15
15
|
- **Diff summary**: `git diff --stat <base>..HEAD` output, plus a per-file one-line summary of changes
|
|
16
16
|
- **Out-of-plan edits block**: every file edited that was not in the approved plan's file list, with rationale (empty block is acceptable and preferred)
|
|
17
|
+
- **Clarification answers carried in**: when `instruction-set/clarification-response.md` exists, it holds the user's answers to the approved plan's `## 1. Clarification Items` rows (the `# Attached User Responses` the planning HTML form exported as `user-responses/` sidecars). The report MUST render the `## 0. Clarification Response Carried In From Previous Run` section (set `clarificationCarryIn.sourceFile` to that path) and, for every carried-over `## 1.` row whose answer appears there, fold the answer into the row (record it in the `User input` cell and flip `Status` to `resolved`). A row left `open`/`answered` despite a matching user answer is a contract violation; an answer that materially changes scope beyond the approved plan is routed to a new `implementation-planning` run, not silently executed.
|
|
17
18
|
- **Stage sidecar evidence**: the JSON payload of `runs/<impl-task-key>/carry/stage-<N>.json` is embedded verbatim in a fenced ```json``` block, AND the `consumers.jsonl` rows this run appended are quoted line-by-line, so reviewers can audit the carry surface without grepping artifact directories.
|
|
18
19
|
- **Validation evidence**: actual command output (stdout/stderr) for every `pre / mid / post` validation command from the plan. Truncated output is acceptable but the command line and exit code MUST be exact. No paraphrasing of test results.
|
|
19
20
|
- **TDD evidence (when applicable)**: for steps that should be TDD-ordered, show the failing-test output BEFORE the implementation commit and the passing-test output AFTER, with commit SHAs framing the transition.
|
|
@@ -33,6 +33,7 @@ until Phase 5 ends, then drop from active context for Phase 6/7.
|
|
|
33
33
|
- 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`.
|
|
34
34
|
- 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.
|
|
35
35
|
- 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.
|
|
36
|
+
- **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.
|
|
36
37
|
- 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
|
|
37
38
|
- "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.
|
|
38
39
|
- distinguish the two file-scope rules (they are not in conflict):
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
- 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`, `Validation Checklist`, `Rollback`, `Requirement Coverage`. (Approval is no longer a body section — it is the YAML frontmatter `approved` field.)
|
|
58
58
|
- Korean translations are allowed in parentheses (e.g. `### Recommended Option (권장 옵션)`), but the English keyword must be present verbatim in the heading line.
|
|
59
59
|
- The shape and ordering follow `final-report-template.md` sections 5.4 (`Implementation Plan Deliverables`) + 5.5 (`Stage Map`). Do NOT translate the heading keywords — `validators/validate-run.py` does substring matching on the raw report text and missing English strings are a real, repeatedly observed failure mode (root cause: writer translated the headings to Korean).
|
|
60
|
-
- 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 — 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 (≤6), the `depends-on` DAG, and the per-stage vertical-slice contract (S10) are all enforced here, not deferred to the `implementation` entry gate. S10 scans for the literal in-section strings `Slice value:`, `Acceptance:`, and the Stepwise `action`-cell prefixes `RED:` / `GREEN:` (or a `TDD exemption:` line) — keep these tokens verbatim for the same reason as the heading keywords above.
|
|
60
|
+
- 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 — 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 (≤6), the `depends-on` DAG, and the per-stage vertical-slice contract (S10) are all enforced here, not deferred to the `implementation` entry gate. 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.
|
|
61
61
|
- Required deliverable shape (final report, in addition to the standard sections):
|
|
62
62
|
- at least two implementation options. **Each option must include**:
|
|
63
63
|
- **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`.
|
|
@@ -66,12 +66,17 @@
|
|
|
66
66
|
- trade-off matrix across options (rows = options, columns at minimum: complexity, risk, reversibility, test coverage cost, rollout cost)
|
|
67
67
|
- recommended option with rationale tied to the design principles above
|
|
68
68
|
- **Stage Map (mandatory — always emitted, even when N=1):** a table of all stages with `stage | title | depends-on | step-count | exit-contract-summary`. `depends-on` is `(none)` or a comma-separated stage number list. Stages with `depends-on (none)` can be implemented in parallel by two simultaneous `implementation` runs.
|
|
69
|
-
- **Per-stage slice declaration (mandatory
|
|
69
|
+
- **Per-stage slice declaration (mandatory lines, directly under the `## 5.5.<i> Stage <i>:` heading, before `### Carry-In`):**
|
|
70
70
|
- `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.
|
|
71
71
|
- `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.
|
|
72
|
+
- **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:
|
|
73
|
+
- `Test case (success): <input → expected, the command/test name>` — the happy path: a valid input that proves the slice works end-to-end.
|
|
74
|
+
- `Test case (boundary): <edge input → expected, the command/test name>` — an edge/boundary input (empty, min/max, missing, first/last, off-by-one). When the slice genuinely has no boundary, write `N/A — <reason>` so the value is non-empty and the omission is a conscious, reviewable decision — never leave it blank.
|
|
75
|
+
- `Test case (failure): <invalid input → error/rejection, the command/test name>` — a negative/failure path (invalid input, unauthorized, error propagation).
|
|
76
|
+
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.
|
|
72
77
|
- **Per-stage subsections** (`## 5.5.<i> Stage <i>: <title>` for each `i`), each containing the four required subsections:
|
|
73
78
|
- `### 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.
|
|
74
|
-
- `### Stepwise Execution Order` — bite-sized table with `step | action | files | command | expected`. **Effective row count ≤ 6** (excluding header / divider / blank). Each step is one action completable in 2–5 minutes; 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 that
|
|
79
|
+
- `### Stepwise Execution Order` — bite-sized table with `step | action | files | command | expected`. **Effective row count ≤ 6** (excluding header / divider / blank). Each step is one action completable in 2–5 minutes; 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, or the exemption line.
|
|
75
80
|
- **Per-stage conformance declaration (mandatory one line, in the stage section — same placement freedom as `TDD exemption:`):** the stage MUST carry exactly one of:
|
|
76
81
|
- `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.
|
|
77
82
|
- `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.)
|
|
@@ -111,4 +116,4 @@
|
|
|
111
116
|
5. **Scope check** — if the recommended plan now spans multiple independent subsystems, recommend splitting into separate planning runs rather than shipping an oversized plan.
|
|
112
117
|
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.
|
|
113
118
|
7. **Plan-body verification reconciliation (BLOCKING for implementation-planning).** Inspect the `### 5.5.9 Plan Body Verification` verdict table. For every plan-item row classified as `majority-disagree → C-<N>`, the corresponding `C-<N>` row MUST exist in `## 1. Clarification Items` with `Kind` chosen per the standard policy and `Blocks=approval`. Do NOT create a parallel `Open Questions` block under the implementation plan body — the unified table is the single home. Conversely, the `Classification` column's `C-<N>` reference and the `## 1. Clarification Items` `ID` column MUST match 1:1; an orphan on either side is a contract violation. For `partial-consensus` and `worker-unique` plan-items, the dissenting opinion lives in §5.5.9 `Dissent log` and is NOT promoted to §5.
|
|
114
|
-
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 6. Confirm each stage declares a non-empty `Slice value:` and `Acceptance:` line, and that its first step `action` starts with `RED:` with a later `GREEN:`
|
|
119
|
+
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 6. 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).
|
|
@@ -302,20 +302,35 @@ def user_response_sidecars(source: Path) -> list[Path]:
|
|
|
302
302
|
)
|
|
303
303
|
|
|
304
304
|
|
|
305
|
-
def
|
|
306
|
-
"""
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
305
|
+
def attached_user_responses_section(source: Path) -> str:
|
|
306
|
+
"""`source` 형제 `user-responses/` 사이드카만 모은 `# Attached User Responses`
|
|
307
|
+
섹션 본문. 사이드카 부재 시 빈 문자열.
|
|
308
|
+
|
|
309
|
+
plan 본문이 이미 별도 경로(`--approved-plan`)로 참조되는 implementation
|
|
310
|
+
carry-in 에서, 원문을 중복 복사하지 않고 사용자 답변만 instruction-set 에
|
|
311
|
+
첨부할 때 쓴다. `clarification_response_with_sidecars` 와 같은 직렬화 포맷을
|
|
312
|
+
한 곳에서 만들어 두 carry-in 경로가 갈라지지 않게 한다.
|
|
310
313
|
"""
|
|
311
|
-
text = source.read_text(encoding="utf-8")
|
|
312
314
|
sidecars = user_response_sidecars(source)
|
|
313
315
|
if not sidecars:
|
|
314
|
-
return
|
|
315
|
-
parts = [
|
|
316
|
+
return ""
|
|
317
|
+
parts = ["# Attached User Responses\n"]
|
|
316
318
|
for sidecar in sidecars:
|
|
317
319
|
parts.append(
|
|
318
320
|
f"\n## {sidecar.name}\n\n"
|
|
319
321
|
f"{sidecar.read_text(encoding='utf-8').strip()}\n"
|
|
320
322
|
)
|
|
321
323
|
return "".join(parts)
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def clarification_response_with_sidecars(source: Path) -> str:
|
|
327
|
+
"""clarification-response 원문 뒤에 `user-responses/` 사이드카를 덧붙인 본문.
|
|
328
|
+
|
|
329
|
+
사이드카 부재 시 원문 그대로 — 호출자는 항상 이 함수를 거쳐 instruction-set
|
|
330
|
+
사본을 쓰면 된다.
|
|
331
|
+
"""
|
|
332
|
+
text = source.read_text(encoding="utf-8")
|
|
333
|
+
section = attached_user_responses_section(source)
|
|
334
|
+
if not section:
|
|
335
|
+
return text
|
|
336
|
+
return text.rstrip("\n") + "\n\n---\n\n" + section
|
|
@@ -73,7 +73,10 @@ from .md_table import is_separator_row as _is_separator_row
|
|
|
73
73
|
_BLANK_PATTERN = re.compile(r"^\s*$")
|
|
74
74
|
|
|
75
75
|
_HEADING_PATTERN = re.compile(r"^(#{1,6})\s+(.*?)\s*$")
|
|
76
|
-
|
|
76
|
+
# Leading whitespace is captured so fences nested in a list item (e.g.
|
|
77
|
+
# §5.7.5's carry sidecar JSON, indented 2 spaces) are recognised and the
|
|
78
|
+
# code lines can be dedented before rendering.
|
|
79
|
+
_CODEFENCE_PATTERN = re.compile(r"^(\s*)```(.*)$")
|
|
77
80
|
_LIST_BULLET_PATTERN = re.compile(r"^(\s*)[-*]\s+(.*)$")
|
|
78
81
|
_LIST_NUMBERED_PATTERN = re.compile(r"^(\s*)(\d+)\.\s+(.*)$")
|
|
79
82
|
_INLINE_CODE_PATTERN = re.compile(r"`([^`]+)`")
|
|
@@ -198,11 +201,15 @@ def _markdown_to_html(
|
|
|
198
201
|
|
|
199
202
|
m_code = _CODEFENCE_PATTERN.match(line)
|
|
200
203
|
if m_code:
|
|
201
|
-
|
|
204
|
+
indent = m_code.group(1)
|
|
205
|
+
lang = m_code.group(2).strip()
|
|
202
206
|
code_lines: list[str] = []
|
|
203
207
|
i += 1
|
|
204
208
|
while i < n and not _CODEFENCE_PATTERN.match(lines[i]):
|
|
205
|
-
|
|
209
|
+
raw = lines[i]
|
|
210
|
+
if indent and raw.startswith(indent):
|
|
211
|
+
raw = raw[len(indent):]
|
|
212
|
+
code_lines.append(raw)
|
|
206
213
|
i += 1
|
|
207
214
|
if i < n:
|
|
208
215
|
i += 1
|
|
@@ -30,7 +30,11 @@ from okstra_project import project_json_path, upsert_project_json
|
|
|
30
30
|
from okstra_project.state import slugify
|
|
31
31
|
from . import fix_cycles
|
|
32
32
|
from .analysis_packet import build_analysis_packet
|
|
33
|
-
from .clarification_items import
|
|
33
|
+
from .clarification_items import (
|
|
34
|
+
attached_user_responses_section,
|
|
35
|
+
clarification_response_with_sidecars,
|
|
36
|
+
scan_approval_gate,
|
|
37
|
+
)
|
|
34
38
|
from .qa_commands import format_errors as _format_qa_errors, validate_qa_commands
|
|
35
39
|
from .material import (
|
|
36
40
|
build_analysis_material,
|
|
@@ -1823,6 +1827,16 @@ def _write_instruction_set_sources(
|
|
|
1823
1827
|
clarification_response_with_sidecars(Path(inp.clarification_response_path)),
|
|
1824
1828
|
encoding="utf-8",
|
|
1825
1829
|
)
|
|
1830
|
+
elif inp.task_type == "implementation" and inp.approved_plan_path:
|
|
1831
|
+
# implementation carry-in: the approved plan reaches this run by path
|
|
1832
|
+
# (executor re-reads it), so attach ONLY the planning HTML form answers
|
|
1833
|
+
# (`runs/implementation-planning/.../user-responses/`) — without these
|
|
1834
|
+
# the user's clarification answers never reach the implementation run.
|
|
1835
|
+
plan_responses = attached_user_responses_section(Path(inp.approved_plan_path))
|
|
1836
|
+
if plan_responses:
|
|
1837
|
+
(instruction_set / "clarification-response.md").write_text(
|
|
1838
|
+
plan_responses, encoding="utf-8",
|
|
1839
|
+
)
|
|
1826
1840
|
if inp.directive:
|
|
1827
1841
|
(instruction_set / "directive.txt").write_text(inp.directive + "\n", encoding="utf-8")
|
|
1828
1842
|
render_reference_expectations(
|
|
@@ -1836,7 +1850,7 @@ def _write_instruction_set_sources(
|
|
|
1836
1850
|
reference_expectations_path=instruction_set / "reference-expectations.md",
|
|
1837
1851
|
clarification_response_path=(
|
|
1838
1852
|
instruction_set / "clarification-response.md"
|
|
1839
|
-
if
|
|
1853
|
+
if (instruction_set / "clarification-response.md").is_file() else None
|
|
1840
1854
|
),
|
|
1841
1855
|
directive=inp.directive,
|
|
1842
1856
|
instruction_set_relative_path=ctx["INSTRUCTION_SET_RELATIVE_PATH"],
|
|
@@ -1153,11 +1153,30 @@
|
|
|
1153
1153
|
"not": { "required": ["conformanceTests"] }
|
|
1154
1154
|
}
|
|
1155
1155
|
],
|
|
1156
|
+
"if": { "not": { "required": ["tddExemption"] } },
|
|
1157
|
+
"then": {
|
|
1158
|
+
"required": ["testCaseSuccess", "testCaseBoundary", "testCaseFailure"]
|
|
1159
|
+
},
|
|
1156
1160
|
"properties": {
|
|
1157
1161
|
"stage": { "type": "integer", "minimum": 1 },
|
|
1158
1162
|
"title": { "type": "string", "minLength": 1 },
|
|
1159
1163
|
"sliceValue": { "type": "string", "minLength": 1 },
|
|
1160
1164
|
"acceptance": { "type": "string", "minLength": 1 },
|
|
1165
|
+
"testCaseSuccess": {
|
|
1166
|
+
"type": "string",
|
|
1167
|
+
"minLength": 1,
|
|
1168
|
+
"description": "Happy-path test case proving the slice works for valid input. Text after the `Test case (success):` prefix."
|
|
1169
|
+
},
|
|
1170
|
+
"testCaseBoundary": {
|
|
1171
|
+
"type": "string",
|
|
1172
|
+
"minLength": 1,
|
|
1173
|
+
"description": "Boundary/edge test case (empty, min/max, missing). Text after the `Test case (boundary):` prefix. Use `N/A — <reason>` only when no boundary genuinely exists."
|
|
1174
|
+
},
|
|
1175
|
+
"testCaseFailure": {
|
|
1176
|
+
"type": "string",
|
|
1177
|
+
"minLength": 1,
|
|
1178
|
+
"description": "Failure/negative test case (invalid input, error path). Text after the `Test case (failure):` prefix."
|
|
1179
|
+
},
|
|
1161
1180
|
"conformanceTests": {
|
|
1162
1181
|
"type": "string",
|
|
1163
1182
|
"minLength": 1,
|
|
@@ -242,6 +242,11 @@ implementation-option: {{ frontmatter.implementationOption | yaml_scalar }}
|
|
|
242
242
|
|
|
243
243
|
- **Slice value:** {{ stage.sliceValue }}
|
|
244
244
|
- **Acceptance:** {{ stage.acceptance }}
|
|
245
|
+
{% if not stage.tddExemption %}
|
|
246
|
+
- **Test case (success):** {{ stage.testCaseSuccess }}
|
|
247
|
+
- **Test case (boundary):** {{ stage.testCaseBoundary }}
|
|
248
|
+
- **Test case (failure):** {{ stage.testCaseFailure }}
|
|
249
|
+
{% endif %}
|
|
245
250
|
{% if stage.conformanceTests %}
|
|
246
251
|
- **Conformance tests:** stage-{{ stage.stage }} — {{ stage.conformanceTests }}
|
|
247
252
|
{% else %}
|
|
@@ -89,7 +89,7 @@ The final report of an `implementation-planning` run MUST contain every section
|
|
|
89
89
|
1. **Option Candidates** — at least two viable options, each with the exact list of files to create or modify and the principal change per file.
|
|
90
90
|
2. **Trade-off Matrix** — comparison of the candidates across complexity, risk, reversibility, performance impact, scope, and required test surface.
|
|
91
91
|
3. **Recommended Option** — selected option with explicit rationale referencing the trade-off matrix.
|
|
92
|
-
4. **Stage Map** — `## 5.5 Stage Map` plus one `## 5.5.<i> Stage <i>:` section per stage. Each stage is a thin vertical slice with `Slice value:`, `Acceptance:`, `Conformance tests:` or `Conformance exemption:`, the four required subsections, and a RED/GREEN step order unless a `TDD exemption:` line applies.
|
|
92
|
+
4. **Stage Map** — `## 5.5 Stage Map` plus one `## 5.5.<i> Stage <i>:` section per stage. Each stage is a thin vertical slice with `Slice value:`, `Acceptance:`, the three `Test case (success|boundary|failure):` lines, `Conformance tests:` or `Conformance exemption:`, the four required subsections, and a RED/GREEN step order unless a `TDD exemption:` line applies (which also waives the test-case lines).
|
|
93
93
|
5. **Dependency and Migration Risk** — schema, data, ordering, feature-flag, and cross-service risks that the recommended option introduces.
|
|
94
94
|
6. **Validation Checklist** — pre-execution, mid-execution, and post-execution checks (commands, expected outputs, observability points).
|
|
95
95
|
7. **Rollback Strategy** — exact reverse procedure or compensating action for each significant step.
|
|
@@ -177,6 +177,13 @@ _LABEL_PREFIX = r"^\s*(?:[-*]\s+)?(?:\*\*)?"
|
|
|
177
177
|
SLICE_VALUE = re.compile(_LABEL_PREFIX + r"Slice value\s*:\s*(?:\*\*)?\s*(.+?)\s*$", re.M)
|
|
178
178
|
ACCEPTANCE = re.compile(_LABEL_PREFIX + r"Acceptance\s*:\s*(?:\*\*)?\s*(.+?)\s*$", re.M)
|
|
179
179
|
TDD_EXEMPTION = re.compile(_LABEL_PREFIX + r"TDD exemption\s*:\s*(?:\*\*)?\s*\S", re.M)
|
|
180
|
+
TEST_CASE_CATEGORIES = ("success", "boundary", "failure")
|
|
181
|
+
TEST_CASE = {
|
|
182
|
+
cat: re.compile(
|
|
183
|
+
_LABEL_PREFIX + rf"Test case\s*\({cat}\)\s*:\s*(?:\*\*)?\s*\S", re.M
|
|
184
|
+
)
|
|
185
|
+
for cat in TEST_CASE_CATEGORIES
|
|
186
|
+
}
|
|
180
187
|
CONFORMANCE_TESTS = re.compile(_LABEL_PREFIX + r"Conformance tests\s*:\s*(?:\*\*)?\s*\S", re.M)
|
|
181
188
|
CONFORMANCE_EXEMPTION = re.compile(_LABEL_PREFIX + r"Conformance exemption\s*:\s*(?:\*\*)?\s*\S", re.M)
|
|
182
189
|
|
|
@@ -188,6 +195,10 @@ def _check_slice_tdd(text: str, stages: List[StageMeta]) -> List[ValidationError
|
|
|
188
195
|
S10b — `Acceptance:` line with a non-empty value.
|
|
189
196
|
S10c — first effective Stepwise step's action starts with `RED:` AND some
|
|
190
197
|
action starts with `GREEN:`, OR a `TDD exemption:` line is present.
|
|
198
|
+
S10d — stage declares all three `Test case (success|boundary|failure):`
|
|
199
|
+
lines with non-empty values, OR a `TDD exemption:` line is present.
|
|
200
|
+
Forces the plan to address the happy path, edge/boundary inputs, and
|
|
201
|
+
failure/negative inputs instead of a single acceptance assertion.
|
|
191
202
|
"""
|
|
192
203
|
errs: List[ValidationError] = []
|
|
193
204
|
for s in stages:
|
|
@@ -204,6 +215,16 @@ def _check_slice_tdd(text: str, stages: List[StageMeta]) -> List[ValidationError
|
|
|
204
215
|
|
|
205
216
|
if TDD_EXEMPTION.search(section):
|
|
206
217
|
continue
|
|
218
|
+
|
|
219
|
+
missing_cases = [
|
|
220
|
+
cat for cat in TEST_CASE_CATEGORIES if not TEST_CASE[cat].search(section)
|
|
221
|
+
]
|
|
222
|
+
if missing_cases:
|
|
223
|
+
errs.append(ValidationError("S10", s.stage_number,
|
|
224
|
+
"S10d: missing 'Test case (" + "|".join(missing_cases) + "):' "
|
|
225
|
+
"line(s) — declare a non-empty success, boundary, and failure "
|
|
226
|
+
"case each, or add a 'TDD exemption:' line"))
|
|
227
|
+
|
|
207
228
|
rows = _effective_step_rows(section)
|
|
208
229
|
actions = [r[1] for r in rows if len(r) > 1]
|
|
209
230
|
first_is_red = bool(actions) and actions[0].startswith("RED:")
|