okstra 0.28.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.kr.md +4 -0
- package/README.md +4 -0
- package/bin/okstra +1 -0
- package/docs/kr/architecture.md +74 -13
- package/docs/kr/cli.md +6 -1
- package/docs/superpowers/plans/2026-05-17-dual-format-final-report.md +167 -0
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/claude-worker.md +2 -2
- package/runtime/agents/workers/codex-worker.md +1 -1
- package/runtime/agents/workers/gemini-worker.md +1 -1
- package/runtime/agents/workers/report-writer-worker.md +3 -1
- package/runtime/bin/okstra-render-report-views.py +129 -0
- package/runtime/prompts/profiles/implementation-planning.md +1 -1
- package/runtime/python/okstra_ctl/report_views.py +701 -0
- package/runtime/python/okstra_ctl/wizard.py +220 -14
- package/runtime/skills/okstra-brief/SKILL.md +73 -35
- package/runtime/skills/okstra-report-writer/SKILL.md +19 -4
- package/runtime/skills/okstra-team-contract/SKILL.md +2 -5
- package/runtime/templates/reports/final-report.template.md +169 -2
- package/runtime/templates/reports/report.css +151 -0
- package/runtime/templates/reports/report.js +163 -0
- package/runtime/templates/reports/user-response.template.md +69 -0
- package/runtime/validators/lib/fixtures.sh +40 -3
- package/runtime/validators/validate-report-views.py +283 -0
- package/runtime/validators/validate-run.py +251 -3
- package/runtime/validators/validate-workflow.sh +4 -0
- package/src/install.mjs +1 -0
- package/src/render-views.mjs +67 -0
package/README.kr.md
CHANGED
|
@@ -185,6 +185,9 @@ Claude Code 세션 밖에서 task 를 시작하려면:
|
|
|
185
185
|
- **PR 본문 템플릿 설정** (release-handoff) — PR 본문은 마크다운 템플릿에서 채워집니다. 해석 우선순위: 1회성 override (`--pr-template-path` 또는 okstra-run Step 6 prompt) → `<project_root>/.project-docs/okstra/project.json` 의 `prTemplatePath` → `~/.okstra/config.json` 의 `prTemplatePath` → 스킬 디폴트 `~/.claude/skills/okstra-run/templates/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 가 주석을 제거합니다.
|
|
186
186
|
- **프로파일 워커 로스터 검증** — `--workers <csv>` 와 okstra-run Step 6 의 워커 prompt 는 해당 프로파일의 `Required workers:` 블록에 선언된 워커 ID 만 허용합니다. 프로파일에 없는 워커 (예: `release-handoff` 에서 `codex` / `gemini`) 를 요청하면 명확한 에러로 거절되고, 인터랙티브 prompt 도 프로파일이 실제로 받는 워커만 보여줍니다.
|
|
187
187
|
- **Phase 6 plan-body verification (implementation-planning 전용)** — Report writer worker 가 final-report draft 를 작성한 직후, User Approval gate 직전에 lead 가 1 라운드의 사후 검증을 추가로 돌립니다. 합성된 `## 4.5` plan 본문에서 `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` 중 하나. 앞 둘은 final-report 상단의 `- [ ] Approved` 마커를 렌더하고, 뒤 둘은 `majority-disagree` 항목을 `## 5. Clarification Items` 의 `Blocks=approval` row 로 변환합니다. 빠른 반복용 opt-out: `--no-plan-verification` (기본값: 활성). 자세한 라운드 프로토콜은 [`skills/okstra-convergence/SKILL.md`](skills/okstra-convergence/SKILL.md) 의 "Plan-body verification mode" 섹션과 [`docs/kr/cli.md#--no-plan-verification`](docs/kr/cli.md#--no-plan-verification).
|
|
188
|
+
- **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`).
|
|
189
|
+
- **Artifact-home rule (`.project-docs/okstra/`)** — okstra 가 사용자 프로젝트에 쓰는 모든 파일은 `<project>/.project-docs/okstra/` subtree 안에만 위치합니다. 외부 경로 (`CONTEXT.md`, `docs/adr/`, `.scratch/`, 소스 코드) 는 read-only reference 이며 부재해도 정상 상태입니다. okstra-internal 등가물: 용어집 `glossary.md`, 결정 기록 `decisions/<NNNN>-<slug>.md` (`implementation-planning` phase 에서 평가).
|
|
190
|
+
- **Dual-format final-report views** — Phase 7 가 `final-report-<task-type>-<seq>.md` 를 쓰면 `okstra render-views` 가 같은 `reports/` 폴더에 두 view 를 자동 생성합니다: AI 다음-phase 입력용 슬림 markdown, 사람 reviewer 용 self-contained HTML (CSS/JS 인라인, 외부 URL 0). HTML 의 `Export user response` 버튼은 `## 5. Clarification Items` 입력을 `runs/<task-type>/user-responses/user-response-<task-type>-<seq>.md` 사이드카로 직렬화해 다음 phase 가 소비합니다. 원본 MD 는 어떤 경우에도 view 생성으로 인해 수정되지 않습니다.
|
|
188
191
|
|
|
189
192
|
### 3.5 운영 명령
|
|
190
193
|
|
|
@@ -196,6 +199,7 @@ Claude Code 세션 밖에서 task 를 시작하려면:
|
|
|
196
199
|
| `npx -y okstra@latest setup --project-id <id>` | 현재 프로젝트를 등록 (`.project-docs/okstra/project.json`) |
|
|
197
200
|
| `npx -y okstra@latest check-project` | 현재 프로젝트가 `setup` 으로 등록됐는지 검증 |
|
|
198
201
|
| `npx -y okstra@latest config <get\|set\|unset\|show> [key] [value] [--scope project\|global\|all]` | okstra 설정 읽기/쓰기. 현재 지원 키: `pr-template-path` (project.json 또는 `~/.okstra/config.json` 의 `prTemplatePath` 갱신) |
|
|
202
|
+
| `npx -y okstra@latest render-views <final-report.md>` | final-report MD 한 본을 입력으로 슬림 MD + HTML 두 view 를 (재)생성 (Phase 7 step 1.5; 멱등) |
|
|
199
203
|
| `npx -y okstra@latest uninstall` | 런타임 + 스킬 제거; 사용자 데이터(`recent.jsonl`, `projects/`, …)는 보존 |
|
|
200
204
|
| `npx -y okstra@latest uninstall --purge -y` | 사용자 데이터까지 모두 제거 |
|
|
201
205
|
|
package/README.md
CHANGED
|
@@ -184,6 +184,9 @@ Recent workflow additions (post-0.8.0, on `main`):
|
|
|
184
184
|
- **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>/.project-docs/okstra/project.json` `prTemplatePath` → `~/.okstra/config.json` `prTemplatePath` → bundled skill default at `~/.claude/skills/okstra-run/templates/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.
|
|
185
185
|
- **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` / `gemini` 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.
|
|
186
186
|
- **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 now runs one additional verification round: it extracts `P-Opt-*` / `P-Step-*` / `P-Dep-*` / `P-Val-*` / `P-Rb-*` items from the consolidated `## 4.5` plan 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`; only the first two render the top-of-report `- [ ] Approved` marker, the other two convert `majority-disagree` items into `## 5. Clarification Items` rows with `Blocks=approval`. Disable for fast iteration with `--no-plan-verification` (default: enabled). Details: [`skills/okstra-convergence/SKILL.md`](skills/okstra-convergence/SKILL.md) "Plan-body verification mode" and [`docs/kr/cli.md#--no-plan-verification`](docs/kr/cli.md#--no-plan-verification).
|
|
187
|
+
- **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`).
|
|
188
|
+
- **Artifact-home rule (`.project-docs/okstra/`)** — okstra writes only inside `<project>/.project-docs/okstra/`. External paths (`CONTEXT.md`, `docs/adr/`, `.scratch/`, source code) are read-only references; their absence is normal. okstra-internal equivalents: `glossary.md` for terminology and `decisions/<NNNN>-<slug>.md` for decision records (evaluated in `implementation-planning`).
|
|
189
|
+
- **Dual-format final-report views** — after Phase 7 writes `final-report-<task-type>-<seq>.md`, `okstra render-views` automatically emits two sibling views in the same `reports/` directory: a slim Markdown for downstream AI input and a self-contained HTML (inline CSS/JS, no external URLs) for human review. The HTML lets a reviewer fill in `## 5. Clarification Items` decisions and export them to `runs/<task-type>/user-responses/user-response-<task-type>-<seq>.md`, which the next phase consumes as input. The original MD is never modified by view generation.
|
|
187
190
|
|
|
188
191
|
### 3.5 Ops commands
|
|
189
192
|
|
|
@@ -195,6 +198,7 @@ Recent workflow additions (post-0.8.0, on `main`):
|
|
|
195
198
|
| `npx -y okstra@latest setup --project-id <id>` | Register the current project (`.project-docs/okstra/project.json`) |
|
|
196
199
|
| `npx -y okstra@latest check-project` | Verify the current project has been registered with `setup` |
|
|
197
200
|
| `npx -y okstra@latest config <get\|set\|unset\|show> [key] [value] [--scope project\|global\|all]` | Read / write okstra settings; initial key `pr-template-path` (writes `prTemplatePath` to project.json or `~/.okstra/config.json`) |
|
|
201
|
+
| `npx -y okstra@latest render-views <final-report.md>` | Regenerate the slim-MD + HTML sibling views from a final-report MD (Phase 7 step 1.5; idempotent) |
|
|
198
202
|
| `npx -y okstra@latest uninstall` | Remove runtime + skills; preserves user data (`recent.jsonl`, `projects/`, …) |
|
|
199
203
|
| `npx -y okstra@latest uninstall --purge -y` | Remove everything including user data |
|
|
200
204
|
|
package/bin/okstra
CHANGED
|
@@ -15,6 +15,7 @@ const COMMANDS = new Map([
|
|
|
15
15
|
["worktree-lookup", () => import("../src/worktree-lookup.mjs").then((m) => m.run)],
|
|
16
16
|
["plan-validate", () => import("../src/plan-validate.mjs").then((m) => m.run)],
|
|
17
17
|
["render-bundle", () => import("../src/render-bundle.mjs").then((m) => m.run)],
|
|
18
|
+
["render-views", () => import("../src/render-views.mjs").then((m) => m.run)],
|
|
18
19
|
["wizard", () => import("../src/wizard.mjs").then((m) => m.run)],
|
|
19
20
|
]);
|
|
20
21
|
|
package/docs/kr/architecture.md
CHANGED
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
- [Required team contract](#required-team-contract)
|
|
36
36
|
- [Stable task identity](#stable-task-identity)
|
|
37
37
|
- [Project self-registration](#project-self-registration)
|
|
38
|
+
- [Artifact-home rule](#artifact-home-rule)
|
|
38
39
|
- [Task type](#task-type)
|
|
39
40
|
- [표준 task type](#표준-task-type)
|
|
40
41
|
- [Phase 간 정보 전달](#phase-간-정보-전달)
|
|
@@ -62,9 +63,11 @@
|
|
|
62
63
|
- [8. 구현 후 최종 검토](#8-구현-후-최종-검토)
|
|
63
64
|
- [9. 같은 task 재개](#9-같은-task-재개)
|
|
64
65
|
- [Lifecycle status and resume](#lifecycle-status-and-resume)
|
|
65
|
-
- [
|
|
66
|
+
- [Final report structure](#final-report-structure)
|
|
67
|
+
- [Final report views (slim MD + HTML)](#final-report-views-slim-md--html)
|
|
66
68
|
- [Worker error collection (optional sidecar)](#worker-error-collection-optional-sidecar)
|
|
67
69
|
- [Token usage and cost accounting](#token-usage-and-cost-accounting)
|
|
70
|
+
- [Validators](#validators)
|
|
68
71
|
- [Practical notes](#practical-notes)
|
|
69
72
|
- [Related documents](#related-documents)
|
|
70
73
|
|
|
@@ -307,6 +310,19 @@ Claude launch prompt 본문은 항상 `prompts/launch.template.md` 템플릿에
|
|
|
307
310
|
|
|
308
311
|
`okstra-ctl` 의 reindex/backfill 도 신규 모델에서 권위 소스를 변경했습니다. 과거에는 `examples/projects/*.conf.sh` 를 source 했지만, 지금은 `~/.okstra/projects/<projectId>/meta.json` (record_start 가 위 project.json 정보를 mirror 한 결과) 을 스캔하여 (projectId, projectRoot) 매핑을 복원합니다. `OKSTRA_PROJECT_DEFINITION_DIR_OVERRIDE` 환경변수도 함께 폐기되었습니다.
|
|
309
312
|
|
|
313
|
+
## Artifact-home rule
|
|
314
|
+
|
|
315
|
+
okstra 가 사용자 프로젝트에 생성·수정·삭제하는 모든 파일은 `<PROJECT_ROOT>/.project-docs/okstra/` subtree 안에만 위치합니다. 외부 경로 (예: `<PROJECT_ROOT>/CONTEXT.md`, `<PROJECT_ROOT>/docs/adr/`, `<PROJECT_ROOT>/.scratch/`, 소스 코드) 는 **read-only reference** 입니다. okstra phase 는 그 파일들이 존재하면 읽을 수 있지만 부재해도 정상 상태로 간주하며, 자체 판단으로 외부 경로에 쓰지 않습니다.
|
|
316
|
+
|
|
317
|
+
유일한 예외: brief 의 `Source Material` 또는 `Reporter Confirmations` 섹션에서 사용자가 **verbatim** 으로 특정 외부 파일 편집을 요청한 경우. 해당 편집을 수행하는 phase 는 자신의 final-report 에 사용자 원문 인용을 함께 남겨야 합니다.
|
|
318
|
+
|
|
319
|
+
okstra 는 자기 subtree 안에 자체 institutional memory 를 유지합니다.
|
|
320
|
+
|
|
321
|
+
- `<PROJECT_ROOT>/.project-docs/okstra/glossary.md` — run 을 가로지르며 누적되는 okstra 용어집. 외부 `CONTEXT.md` 류 skill 의 기능을 흡수합니다.
|
|
322
|
+
- `<PROJECT_ROOT>/.project-docs/okstra/decisions/<NNNN>-<slug>.md` — okstra 의 결정 기록. 외부 ADR 시스템의 기능을 흡수합니다. 평가 시점은 `implementation-planning` phase 이며 `okstra-brief` 단계에서는 후보만 표시합니다.
|
|
323
|
+
|
|
324
|
+
okstra phase 는 PRD / issue file 을 직접 쓰지 않습니다. 동등한 결정 산출물은 `requirements-discovery` 와 `implementation-planning` 이 `.project-docs/okstra/` 내부에 만듭니다.
|
|
325
|
+
|
|
310
326
|
## Task type
|
|
311
327
|
|
|
312
328
|
`task-type`은 이번 run의 목적과 profile 선택, 그리고 lifecycle phase 라우팅을 동시에 결정합니다.
|
|
@@ -417,9 +433,14 @@ task manifest, task index, instruction-set, runs, history가 이 루트 아래
|
|
|
417
433
|
그리고 `--render-only`가 아니면 handoff된 Claude session이 보통 아래 결과 파일을 현재 run에 추가합니다.
|
|
418
434
|
- `sessions/claude-resume-<task-type>-<seq>.sh`
|
|
419
435
|
- `reports/final-report-<task-type>-<seq>.md`
|
|
436
|
+
- `reports/final-report-<task-type>-<seq>.slim.md` *(Phase 7 결정론적 후처리: AI 다음-phase 입력용 슬림 markdown)*
|
|
437
|
+
- `reports/final-report-<task-type>-<seq>.html` *(Phase 7 결정론적 후처리: 사람 reviewer 용 self-contained HTML, CSS/JS 인라인)*
|
|
438
|
+
- `user-responses/user-response-<task-type>-<seq>.md` *(HTML 의 `Export user response` 버튼이 생성하는 사이드카; 사용자가 채워 저장하면 다음 phase 가 입력으로 소비)*
|
|
439
|
+
- `worker-results/<worker>-audit-<task-type>-<seq>.md` *(워커별 Reading Confirmation 사이드카; 본문이 아니라 audit 용)*
|
|
420
440
|
- `status/final-<task-type>-<seq>.status`
|
|
421
|
-
최종 결과 파일
|
|
441
|
+
최종 결과 파일 (`final-report` MD / status) 은 `okstra`가 stdout을 저장해서 만드는 파일이 아닙니다.
|
|
422
442
|
`okstra`가 준비한 task bundle을 바탕으로 Claude가 현재 run 안에 직접 작성하는 결과물입니다.
|
|
443
|
+
slim MD / HTML 두 view 는 `okstra render-views <final-report.md>` (Phase 7 step 1.5) 가 final-report MD 한 본을 입력으로 결정론적으로 생성합니다. 원본 MD 는 view 생성으로 인해 수정되지 않습니다.
|
|
423
444
|
반면 `sessions/claude-resume-<task-type>-<seq>.sh`는 `okstra`가 Claude launch 전에 미리 생성하는 interruption recovery helper입니다.
|
|
424
445
|
|
|
425
446
|
run directory는 task-type 단위로 task 실행 이력을 모으고, 내부를 `manifests/`, `state/`, `prompts/`, `reports/`, `status/`, `sessions/`, `worker-results/`처럼 유형별 하위 폴더로 나눈 뒤 각 run-level artifact와 result 파일을 `-<task-type>-<seq>` suffix(per-category 3-digit zero-padded counter, 예: `001`, `002`)로 구분합니다.
|
|
@@ -611,6 +632,8 @@ canonical metadata는 항상 `task-manifest.json`을 기준으로 확인합니
|
|
|
611
632
|
|
|
612
633
|
`okstra`는 brief-first 구조입니다. brief 가 분석의 정본 입력이며, 워커가 필요로 할 추가 자료(보고서, 코드 스니펫, 로그 등)는 brief 내부의 `Evidence and Source Materials` 섹션에 inline 또는 path 로 모두 포함시킵니다.
|
|
613
634
|
|
|
635
|
+
brief 는 **translation layer** 입니다 — 외부 입력 (이슈 트래커 ticket, 요구사항 문서, 사용자 메시지) 을 okstra-readable 형식으로 옮기되, 원문은 verbatim 으로 보존하고 okstra 가 추가한 부분은 labelled augmentation 으로 명확히 구분합니다. okstra-brief skill 의 산출이 정식 SSOT 이며, 분석 워커들이 phase 시작 전에 일률적으로 읽어들이는 단일 입력입니다.
|
|
636
|
+
|
|
614
637
|
brief에는 보통 아래를 포함합니다.
|
|
615
638
|
|
|
616
639
|
- 문제 설명
|
|
@@ -622,6 +645,10 @@ brief에는 보통 아래를 포함합니다.
|
|
|
622
645
|
- worker에게 줄 질문
|
|
623
646
|
- 기대 출력
|
|
624
647
|
- 이전 run 또는 연관 task 정보
|
|
648
|
+
- (선택) glossary 추가 후보 — okstra-brief Step 4.5 가 `<PROJECT_ROOT>/.project-docs/okstra/glossary.md` 에 직접 기록
|
|
649
|
+
- (선택) decisions 후보 — `implementation-planning` phase 에서 평가 후 `.project-docs/okstra/decisions/<NNNN>-<slug>.md` 로 승격
|
|
650
|
+
|
|
651
|
+
okstra-brief 의 Step 6.5 는 **reporter batch confirmation** 입니다. brief 가 외부 입력을 옮기는 도중 의미 변화가 발생했는지를 사용자에게 일괄 확인받고 그 결과를 `Reporter Confirmations` 섹션에 기록합니다. 모든 분석 profile 은 이 섹션의 존재를 phase 분석 진입의 precondition 으로 강제합니다 (validator: `validators/validate-brief.py`).
|
|
625
652
|
|
|
626
653
|
기본 템플릿:
|
|
627
654
|
|
|
@@ -796,22 +823,42 @@ resume 판단 기준:
|
|
|
796
823
|
- 다음 phase 시작: `workflow.nextRecommendedPhase`가 구체적인 phase면 그 값으로 다음 `okstra.sh` 실행을 준비합니다.
|
|
797
824
|
- 추가 자료 필요: `routingStatus=pending` 또는 `nextRecommendedPhase=pending-routing-decision`이면 brief 보강이 먼저입니다.
|
|
798
825
|
|
|
799
|
-
##
|
|
826
|
+
## Final report structure
|
|
800
827
|
|
|
801
828
|
기본 최종 보고서 템플릿은 `templates/reports/final-report.template.md`입니다.
|
|
802
|
-
Claude가 작성하는 최종 보고서는 brief
|
|
829
|
+
Claude가 작성하는 최종 보고서는 아래 구조를 우선 사용합니다 (brief 의 augmentation 이 더 구체적인 형식을 요구할 때만 그것을 따릅니다).
|
|
803
830
|
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
831
|
+
- `## Verdict Card` — **최상단 의무 섹션**. Final Conclusion / Verdict Token / Direction / Approval Required? / Next Step 5 행. Verdict Token / Direction / Next Step 셀은 본문 §2 (실행 현황) 와 §6 (다음 단계) 의 권위 셀과 byte-match 해야 합니다.
|
|
832
|
+
- (선택) `## 0. Clarification Response Carried In From Previous Run` — 직전 run 에서 응답이 carry-in 된 경우에만 렌더링. 빈 carry-in 일 때는 헤딩 자체를 출력하지 않습니다.
|
|
833
|
+
- `## 1. 문제 또는 검증 대상 요약` — §1.1 Consensus / §1.2 Differences 표 각각 `Source items (worker:item)` 컬럼 보존 (cross-worker traceability).
|
|
834
|
+
- `## 2. 에이전트별 실행 현황`
|
|
835
|
+
- `## 3. Cross Verification 결과` — §3.1 Primary Evidence 에 `Source items (worker:item)` + `Source (path:line / log)` 컬럼.
|
|
836
|
+
- `## 4. 최종 판단` — `implementation-planning` 의 §4.5.9 Plan Body Verification 은 두 표 (`Verdict summary` 4-열, `Verdict details` 5-열, plan item × worker) 로 분할 emit.
|
|
837
|
+
- `## 5. Clarification Items` — 통합 8-열 표 한 곳. 기존 §5.1 / §5.2 / §4.5.8 / §4.5.9 Open Questions 는 deprecated 되어 validator 가 등장 시 fail.
|
|
838
|
+
- `## 6. 권장 다음 단계`
|
|
839
|
+
- `## Token Usage Summary` — sentinel (`pending` / `N/A` / `--` / `?` / 빈 셀) 또는 zero (`0` / `$0.00`) 박제 시 validator 가 출고를 차단합니다. `Codex/Gemini CLI 추가 비용` 행만 "CLI 미사용" 의미로 `$0.00` 허용.
|
|
840
|
+
|
|
841
|
+
워커 출력의 `## 0. Reading Confirmation` 블록은 본문에 두지 않고 `runs/<task-type>/worker-results/<worker>-audit-<task-type>-<seq>.md` 사이드카에 작성합니다 (validator 강제).
|
|
811
842
|
|
|
812
843
|
차이점이 실질적으로 없으면 억지로 대비를 만들지 말고, 차이가 없음을 명시합니다.
|
|
813
844
|
저장 실패나 세션 제한에 대한 메타 설명 대신 실제 Markdown 보고서 본문을 파일에 작성해야 합니다.
|
|
814
845
|
|
|
846
|
+
## Final report views (slim MD + HTML)
|
|
847
|
+
|
|
848
|
+
Phase 7 step 1.5 가 final-report MD 한 본을 입력으로 두 view 를 결정론적으로 자동 생성합니다.
|
|
849
|
+
|
|
850
|
+
- `reports/final-report-<task-type>-<seq>.slim.md` — AI 다음-phase 입력용. 장식·캡션·sentinel 셀을 제거한 토큰-경제 버전. `validate-run.py` 의 phase substring 검사를 byte-identical 로 통과합니다.
|
|
851
|
+
- `reports/final-report-<task-type>-<seq>.html` — 사람 reviewer 용 self-contained HTML. CSS / JS 인라인 임베드 (외부 URL 0), system color 다크모드, sticky header, 인쇄 대응. §5 `C-*` 행의 의사결정 입력 (체크박스 / 셀렉트 / textarea) 을 화면에서 채우고 `Export user response` 버튼으로 사이드카 markdown 을 생성합니다.
|
|
852
|
+
|
|
853
|
+
진입점:
|
|
854
|
+
|
|
855
|
+
- Python 단일 reference: `scripts/okstra_ctl/report_views.py` (`slim_markdown(...)`, `render_html(..., css, js)`, `serialize_user_response(...)`). HTML 내 JS `buildUserResponseMarkdown` 은 Python `serialize_user_response` 와 **byte-identical** (Node `vm.runInThisContext` 단위 테스트로 자동 검증).
|
|
856
|
+
- CLI: `scripts/okstra-render-report-views.py <final-report.md>` 또는 Node 위임 wrapper `bin/okstra render-views <md>`.
|
|
857
|
+
- 검증: `validators/validate-report-views.py` — slim 의 phase substring 보존, HTML 내 form control 위치, 외부 URL 부재, Response ID parity (`C-*` ↔ HTML), 두 모듈 substring 상수 drift 모두 검사.
|
|
858
|
+
- 사용자 응답 사이드카 스키마 SSOT: `templates/reports/user-response.template.md`.
|
|
859
|
+
|
|
860
|
+
원본 final-report MD 는 어떤 경우에도 view 생성으로 인해 수정되지 않습니다.
|
|
861
|
+
|
|
815
862
|
## Worker error collection (optional sidecar)
|
|
816
863
|
|
|
817
864
|
워커(Claude/Codex/Gemini worker, Report writer, Claude lead) 실행 중 발생한 에러를 단일 시계열 로그로 수집해 사후 회고에 사용할 수 있습니다.
|
|
@@ -854,8 +901,19 @@ Claude가 작성하는 최종 보고서는 brief에 더 구체적인 형식이
|
|
|
854
901
|
- Claude lead/workers: `~/.claude/projects/<cwd-as-dashes>/<sessionId>.jsonl`의 per-message `message.usage`
|
|
855
902
|
- Codex CLI: `~/.codex/sessions/Y/M/D/rollout-*.jsonl`의 마지막 `total_token_usage.total_tokens`
|
|
856
903
|
- Gemini CLI: `~/.gemini/tmp/*/chats/session-*.json`의 per-message `tokens.total`
|
|
857
|
-
- billable-equivalent token math와 USD cost estimation을 함께 기록합니다. Anthropic billing ratio(`
|
|
858
|
-
- 가격표는
|
|
904
|
+
- billable-equivalent token math와 USD cost estimation을 함께 기록합니다. Anthropic billing ratio(`cache_creation_5m=1.25x`, `cache_creation_1h=2.0x`, `cache_read=0.1x`, `output=5x`)를 반영합니다. transcript 의 `usage.cache_creation.ephemeral_5m_input_tokens` / `ephemeral_1h_input_tokens` 분해가 있으면 분리 집계합니다.
|
|
905
|
+
- 가격표는 `scripts/okstra_token_usage/pricing.py` 에서 중앙 관리합니다. 모델 가격이 바뀌면 거기서 갱신합니다. 가격 매칭에 실패한 모델 id 는 `usageSummary.unmatchedModels` 필드로 사용자에게 노출됩니다 (silent zero 사고 방지).
|
|
906
|
+
|
|
907
|
+
## Validators
|
|
908
|
+
|
|
909
|
+
phase 산출물의 출고 가능 여부를 강제하는 진입점:
|
|
910
|
+
|
|
911
|
+
- `validators/validate-workflow.sh` — phase contract 통합 검증.
|
|
912
|
+
- `validators/validate-run.py` — run-level final-report 본문 contract (Verdict Card 존재, deprecated §5.1/§5.2/§4.5.8/§4.5.9 Open Questions 부재, Plan Body Verification gate × Approval 마커 cross-check, Token Usage sentinel/zero 차단, 워커-결과 audit 사이드카 존재).
|
|
913
|
+
- `validators/validate-report-views.py` — slim MD / HTML view 의 phase substring 보존 및 form-control 영역 검사.
|
|
914
|
+
- `validators/validate-brief.py` — brief schema (front-matter, `Reporter Confirmations` 섹션 존재, root parent-id self 규칙, slug 컨벤션 등) 강제. `bash validators/validate-brief.sh <brief.md>` 가 thin wrapper.
|
|
915
|
+
|
|
916
|
+
각 validator 는 contract 위반 시 `contract-violated` exit code 로 phase 를 차단합니다. 위반은 다음 phase 실행 시점에 적용되므로 이전 산출물은 그대로 둡니다.
|
|
859
917
|
|
|
860
918
|
## Practical notes
|
|
861
919
|
|
|
@@ -883,6 +941,9 @@ Claude가 작성하는 최종 보고서는 brief에 더 구체적인 형식이
|
|
|
883
941
|
- 워커 에러는 옵션 sidecar `runs/<task-type>/logs/errors-<task-type>-<seq>.jsonl`로 수집되며 lead가 단독 writer입니다. 진입점 helper는 `scripts/okstra-error-log.py`입니다.
|
|
884
942
|
- 토큰 사용 및 비용 집계는 `scripts/okstra-token-usage.py`가 담당하며.
|
|
885
943
|
- `okstra.sh`는 worker CLI 호출 anchoring을 위해 절대 projectRoot를 강제합니다.
|
|
944
|
+
- `okstra wizard step` 은 `--answer <val>` 을 **필수** 로 받습니다. 응답을 줄 차례가 아니라 다음 prompt 만 미리 보고 싶다면 `--no-submit` 으로 peek 합니다.
|
|
945
|
+
- `okstra history` 는 manifest fallback / 페이지네이션 / 필터를 지원하며, `--base-ref` 는 워크트리 registry 에서 해석합니다.
|
|
946
|
+
- 사용자 프로젝트에 대한 모든 쓰기는 `<PROJECT_ROOT>/.project-docs/okstra/` 안에만 발생합니다 (Artifact-home rule 참조).
|
|
886
947
|
|
|
887
948
|
## Related documents
|
|
888
949
|
|
package/docs/kr/cli.md
CHANGED
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
- [`--work-category`](#--work-category)
|
|
33
33
|
- [`--related-tasks`](#--related-tasks)
|
|
34
34
|
- [`--render-only`](#--render-only)
|
|
35
|
+
- [`--no-plan-verification`](#--no-plan-verification)
|
|
35
36
|
- [Interactive input flow](#interactive-input-flow)
|
|
36
37
|
- [Confirmation flow](#confirmation-flow)
|
|
37
38
|
- [okstra Control Center — 설치 / 자주 쓰는 명령](#okstra-control-center--설치--자주-쓰는-명령)
|
|
@@ -517,6 +518,7 @@ chmod +x ~/.local/bin/okstra-ctl
|
|
|
517
518
|
| 진행 중 run 보기 | `okstra-ctl tail active` |
|
|
518
519
|
| 단일 run 결과 메타 | `okstra-ctl show <runId-or-prefix>` |
|
|
519
520
|
| 결과 보고서 경로 | `okstra-ctl open <runId-or-prefix>` |
|
|
521
|
+
| final-report 두 view 재생성 | `okstra render-views <final-report.md>` |
|
|
520
522
|
| 단일 재실행 | `okstra-ctl rerun <runId-or-prefix> --yes` |
|
|
521
523
|
| 다중 재실행 | `okstra-ctl rerun --filter --project X --status failed --yes` |
|
|
522
524
|
| 가장 최근 재실행 | `okstra-ctl rerun last --project X --task-group Y --yes` |
|
|
@@ -535,7 +537,10 @@ chmod +x ~/.local/bin/okstra-ctl
|
|
|
535
537
|
| `okstra worktree-lookup <task-key>` | `worktree_registry.lookup` 결과 (예약된 path / branch / base ref / 현재 상태) |
|
|
536
538
|
| `okstra plan-validate <plan-path>` | `_validate_approved_plan` — approval marker 인식 결과와 sanitization 후 diff |
|
|
537
539
|
| `okstra render-bundle <args…>` | `prepare_task_bundle(render_only=True)` 의 thin shim — `python3 -m okstra_ctl.run --render-only` 와 동일 시그니처 |
|
|
538
|
-
| `okstra
|
|
540
|
+
| `okstra render-views <final-report.md>` | Phase 7 step 1.5 — 토큰 치환된 final-report MD 한 본을 입력으로 sibling `*.slim.md` (AI 입력용) + `*.html` (사람용 self-contained) 두 view 를 결정론적으로 생성. 원본 MD 는 수정하지 않음. Node 위임 wrapper는 `scripts/okstra-render-report-views.py` 를 호출. `validators/validate-report-views.py` 가 substring 보존 / form-control 위치 / Response ID parity 를 검사 |
|
|
541
|
+
| `okstra wizard <init\|step\|render-args\|confirmation> --state-file <path>` | okstra-run 인터랙티브 입력 상태머신 (`okstra_ctl.wizard`). `init` 으로 state file 을 시드한 뒤 skill 이 `step --answer <val>` 을 반복 호출하면 다음 `Prompt` JSON 을 받음. `--answer` 는 **필수**. 응답을 주지 않고 다음 prompt 만 미리 보고 싶다면 `--no-submit` 으로 peek. `render-args` 는 최종 `render-bundle` 인자 맵, `confirmation` 은 사용자 echo 블록을 반환 |
|
|
542
|
+
| `okstra history [--limit N] [--offset M] [--project <id>] [--status <enum>]` | run history 페이지네이션 / 필터 조회. 중앙 인덱스가 비어 있으면 프로젝트별 task-manifest 들을 스캔해 fallback 으로 채움. `--base-ref` 는 워크트리 registry 에서 해석 |
|
|
543
|
+
| `okstra config <get\|set\|unset\|show> [key] [value] [--scope project\|global\|all]` | 영구 설정 관리 (예: `pr-template-path`). 원자적 JSON 쓰기. global scope 의 상대경로는 거절 |
|
|
539
544
|
|
|
540
545
|
> 모든 subcommand 는 `bin/okstra` 가 spawn 하는 python 헬퍼 (`src/_python-helper.mjs`) 가 `PYTHONPATH` 와 `~/.okstra/lib/python` 을 wire 합니다. 직접 `python3 -m okstra_ctl.*` 으로 호출하면 `PYTHONPATH` 를 사용자가 직접 셋업해야 합니다.
|
|
541
546
|
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Dual-Format Final Report (AI MD slim + Human HTML) Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
4
|
+
|
|
5
|
+
**Goal:** Phase 6 의 final-report 산출물에 두 가지 파생 view(AI 용 토큰-절약형 `*.slim.md`, 사람 용 self-contained `*.html`)를 추가한다. HTML 안에서 사용자가 의사결정 입력을 채우면 “Export to MD” 버튼이 그 입력을 AI 가 다음 phase 입력으로 바로 쓸 수 있는 user-response markdown 으로 직렬화한다. 원본 final-report MD 는 단일 source-of-truth 로 유지되며 사용자가 손으로 머지하지 않는다.
|
|
6
|
+
|
|
7
|
+
**Architecture:**
|
|
8
|
+
- **Source of truth:** 기존 `runs/<task-type>/reports/final-report-<task-type>-<seq>.md`. 변경 없음. report-writer-worker 의 작성 계약은 그대로.
|
|
9
|
+
- **파생 산출물:**
|
|
10
|
+
- `final-report-<task-type>-<seq>.slim.md` — 결정론적 stripper 가 원본 MD 에서 생성. 토큰 부담이 큰 섹션(장식 헤더, sentinel/placeholder 셀, verdict-detail 중복, 캡션, 구분선)을 규칙 기반으로 제거.
|
|
11
|
+
- `final-report-<task-type>-<seq>.html` — 결정론적 renderer 가 원본 MD 에서 생성. 단일 파일, 인라인 CSS, vanilla JS 만 사용(외부 CDN 금지). Section 5(Clarification Items) / Section 6(Recommended Next Steps) / Section 7(Follow-up Tasks) 의 “user-actionable” 행에 자동으로 `<form>` 컨트롤이 부착된다.
|
|
12
|
+
- **사용자 응답 경로:** HTML 안의 “Export user response” 버튼은 폼 값을 `.md` 텍스트(고정 스키마)로 직렬화하여 페이지 하단 `<pre>` 에 출력하고 클립보드 복사 버튼을 제공한다. 사용자는 그 텍스트를 `runs/<task-type>/user-responses/user-response-<task-type>-<seq>.md` 경로에 붙여넣어 저장한다(Phase 7 후속 단계 또는 다음 phase 의 lead 가 그 파일을 입력으로 소비). **원본 final-report MD 는 절대 수정하지 않는다.**
|
|
13
|
+
- **용어 충돌 회피:** 2026-05-17 머지된 변경에서 worker-results audit 파일은 "audit sidecar"로, Section 0 Reading Confirmation 은 그 audit sidecar 전용으로 단일화되었다. 따라서 본 plan 의 "decision sidecar" 용어는 **사용 금지**. 사용자 입력 산출물은 `user response` / `user-response-*.md` 로 일관되게 부른다. 경로도 `decisions/` 가 아닌 `user-responses/`.
|
|
14
|
+
- **호출 경로 single reference:** 두 변환은 모두 새 Python 모듈 `scripts/okstra_ctl/report_views.py` 한 곳에서 처리한다. 다음 세 entrypoint 가 같은 함수를 호출:
|
|
15
|
+
1. `scripts/okstra-render-report-views.py` (CLI, Phase 7 step 0 에서 호출)
|
|
16
|
+
2. `bin/okstra render-views <task-key>` (node CLI 래퍼)
|
|
17
|
+
3. report-writer-worker SKILL 의 Persistence Checklist 항목 (실패 시 lead fallback)
|
|
18
|
+
|
|
19
|
+
**Tech Stack:** Python 3 (markdown stripper + HTML renderer, 표준 라이브러리만 — `markdown` 의존성 추가 금지), pytest fixtures, HTML5 + vanilla JS, JSON Schema(hand-rolled) for decision sidecar.
|
|
20
|
+
|
|
21
|
+
> 참고: 본 plan 은 **Phase 6 → Phase 7 실행 순서(BLOCKING order)** 의 step 2(token substitution) 직후, step 3(follow-up spawner) 전에 “step 2.5 — render report views” 를 삽입한다. token placeholder 가 치환된 MD 가 두 view 의 입력이어야 슬림 MD/HTML 에도 실제 토큰 숫자가 들어간다. 이 순서는 BLOCKING.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## File Structure
|
|
26
|
+
|
|
27
|
+
| 경로 | 책임 | 변경 종류 |
|
|
28
|
+
|---|---|---|
|
|
29
|
+
| `scripts/okstra_ctl/report_views.py` | `slim_markdown(src_md) -> str`, `render_html(src_md, *, run_meta) -> str`, `serialize_user_response(form_payload) -> str` 의 단일 reference 구현 | Create |
|
|
30
|
+
| `scripts/okstra-render-report-views.py` | 위 모듈을 호출하는 CLI entrypoint. 입력: 원본 final-report 경로. 출력: `*.slim.md`, `*.html` | Create |
|
|
31
|
+
| `bin/okstra` (또는 `src/commands/render-views.mjs`) | node CLI `okstra render-views` 서브커맨드 — 단순 위임 | Modify (or Create one file) |
|
|
32
|
+
| `skills/okstra-report-writer/SKILL.md` | Phase 6→7 sequence 에 step 2.5 추가, Persistence Checklist 에 두 산출물 항목 추가 | Modify |
|
|
33
|
+
| `agents/workers/report-writer-worker.md` | required-reading 에 본 plan / 결정 sidecar 스키마 링크 추가 | Modify |
|
|
34
|
+
| `templates/reports/final-report.template.md` | 변경 없음 (source of truth 유지). 단 “user-actionable 행” 인식 마커(예: 행 ID `D-*` for decision) 가 이미 존재하는지 확인하고 없으면 Section 5 / 6 / 7 의 row 스키마에 `Response ID` 컬럼만 옵션으로 추가 | Modify (좁은 범위) |
|
|
35
|
+
| `templates/reports/user-response.template.md` | 사용자 응답 직렬화 포맷의 single reference (예: 각 Response ID 별 한 블록, frontmatter 포함) | Create |
|
|
36
|
+
| `templates/reports/report.css` | HTML view 의 인라인 임포트 대상 (build 시 인라인 됨). 외부 CDN 없음 | Create |
|
|
37
|
+
| `templates/reports/report.js` | HTML view 의 인라인 임포트 대상. form → MD 직렬화 + 복사 로직 | Create |
|
|
38
|
+
| `validators/validate-report-views.py` | 원본 MD 의 결정 행 수와 HTML/slim/sidecar 스키마 일관성 검사. Phase 7 의 validator 체인에 추가 | Create |
|
|
39
|
+
| `tests/fixtures/reports/golden-original.md` | 결정/비결정 행을 모두 포함한 합성 final-report | Create |
|
|
40
|
+
| `tests/fixtures/reports/golden-original.slim.md` | 위 입력의 기대 slim 산출물 | Create |
|
|
41
|
+
| `tests/fixtures/reports/golden-original.html` | 위 입력의 기대 HTML 산출물(테스트는 normalize 후 diff) | Create |
|
|
42
|
+
| `tests/test_report_views.py` | golden fixture round-trip + sidecar 직렬화 단위 테스트 | Create |
|
|
43
|
+
| `CHANGES.md` | 사용자 영향 한 줄 추가 | Modify |
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Convention Notes (모든 task 공통)
|
|
48
|
+
|
|
49
|
+
- 모든 변경은 **end-user seed 경로**(repo 안 `scripts/`, `skills/`, `agents/`, `templates/`, `validators/`)에 들어가며, 빌드 후 `runtime/` 에 동기화된다. 개인 `~/.claude/` 직접 편집 금지(MEMORY: `feedback_okstra_fixes_target_end_users.md`).
|
|
50
|
+
- HTML 은 반드시 **단일 `.html` 파일**. `<script src=>` / `<link href=>` 의 외부 URL 금지. 차트는 인라인 SVG 로 직접 그린다(필요 시 추후 plan 에서 작은 sparkline 모듈 추가). 이 제약은 self-contained 정책의 BLOCKING 요건.
|
|
51
|
+
- Slim MD 가 제거하는 항목은 **결정론적**이어야 한다. “LLM 이 보기에 안 중요해 보이는 문장”을 제거하지 않는다. 제거 규칙은 module docstring + `templates/reports/user-response.template.md` 헤더에 명시.
|
|
52
|
+
- 사용자가 만든 user-response 파일은 `runs/<task-type>/user-responses/` 아래에 둔다. 이 경로는 새로 추가. validator 는 파일이 없어도 OK(사용자 의사결정이 필요 없는 run 일 수 있다); 있을 때만 스키마 검사.
|
|
53
|
+
- **Slim/HTML 양쪽 모두에 대한 “absolutely preserve” invariant** (validator hard-fail 방지 목적, BLOCKING):
|
|
54
|
+
- `## Verdict Card` 블록 전체 (셀 byte-identical 유지 — whitespace 정규화 금지)
|
|
55
|
+
- `## 2. Final Verdict` 표의 `Verdict Token` / `Direction` / `Next Step` 행
|
|
56
|
+
- `## 0. Clarification Response Carried In` (존재 시)
|
|
57
|
+
- `implementation-planning` 의 9개 substring (`Option Candidates` / `Trade-off` / `Recommended Option` / `Stepwise Execution Order` / `Dependency` / `Validation Checklist` / `Rollback` / `User Approval Request` / `Plan Body Verification` + `Gate result:`)
|
|
58
|
+
- `implementation` 의 §4.7 8개 sub-section substring (Approved Plan Reference / Commit List / Diff Summary / Out-of-plan Edits / Validation Evidence / Verifier Results / Rollback Verification / Routing Recommendation)
|
|
59
|
+
- `final-verification` 의 §4.8 6개 sub-section substring (Source Implementation Report / Acceptance Blockers / Residual Risk / Validation Evidence / Read-only Command Log / Routing Recommendation)
|
|
60
|
+
- `release-handoff` 의 §4.6 모든 sub-section (4.6.1–4.6.7) **포함 §4.6.6 Merge Conflict Probe**
|
|
61
|
+
Slim stripper 는 이 substring/블록이 포함된 행 또는 그 행에서 직접 참조하는 표/리스트 cell 을 제거하지 않는다. HTML renderer 도 같다(다만 `<details>` 접힘은 허용).
|
|
62
|
+
- Pre-1.0 정책(MEMORY: `feedback_pre_v1_no_compat.md`): 기존 final-report 와 호환되지 않는 행 스키마 변경이 필요하면 즉시 도입한다. compat shim 만들지 않는다.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Tasks
|
|
67
|
+
|
|
68
|
+
### Task 1 — Stripper + Renderer 모듈 (`report_views.py`) 작성
|
|
69
|
+
|
|
70
|
+
- [ ] 1.1 입력/출력 spec 을 module docstring 에 fix. slim 의 제거 규칙(아래)을 enum 으로 명시:
|
|
71
|
+
- `STRIP_TOKEN_PLACEHOLDER_ZEROS` (`$0.00` 행 — `Codex/Gemini CLI 추가 비용` 만 예외로 keep)
|
|
72
|
+
- `STRIP_DECORATIVE_HR` (3개 이상 `---` 연속 구분선)
|
|
73
|
+
- `STRIP_VERDICT_DETAIL` (`§4.5.9 Verdict details` 의 wide matrix — `Verdict summary` 카드만 keep)
|
|
74
|
+
- `STRIP_INTRO_RECIPE` (“> **읽는 법**:” 인용 단락 — 정의 라인은 keep)
|
|
75
|
+
- `COLLAPSE_EMPTY_SECTIONS` (`- 후속 작업 없음.` / `- 합의 미달 항목 없음.` 류 한 줄 placeholder 는 keep, 그러나 그 위 빈 줄 2개 이상은 1개로 정규화)
|
|
76
|
+
- [ ] 1.2 `slim_markdown` 구현 — line-based scanner. 정규식은 module top-level 에 컴파일.
|
|
77
|
+
- [ ] 1.3 `render_html` 구현 — 원본 MD 를 자체 mini-parser(테이블 / 헤딩 / 코드블록 / 인용 / 리스트 / 인라인 코드 / link 만 지원)로 토큰화 후 HTML emit. 외부 markdown 라이브러리 import 금지(제로 의존성). 헤딩 ID 는 slugify. `<a class="toc">` 자동 생성.
|
|
78
|
+
- [ ] 1.4 “User-response row” 검출 — Section 5/6/7 의 표 안에서 `Response ID` 컬럼이 비어 있지 않은 행을 만나면, 그 셀들을 `<form data-response-id="...">` 안에 wrap. 각 행 타입별 컨트롤 매핑:
|
|
79
|
+
- 자유 텍스트 응답 → `<textarea>`
|
|
80
|
+
- 단일 선택(예: accept / reject / hold) → `<select>` 또는 `<input type=radio>`
|
|
81
|
+
- 다중 선택 → `<input type=checkbox>` 그룹
|
|
82
|
+
- 승인 게이트 → `<input type=checkbox> I approve`
|
|
83
|
+
컨트롤 종류는 행의 `Response Type` 옵션 컬럼(또는 `templates/reports/user-response.template.md` 의 enum)으로 결정. 알 수 없으면 textarea fallback.
|
|
84
|
+
**제외 대상(폼 부착 금지):** §4.6 sub-sections(release-handoff deliverables — H1/H2/H3 메뉴로 이미 처리됨, §4.6.6 Merge Conflict Probe 포함), §4.7 sub-sections(implementation deliverables — read-only 결과 보고), §4.8 sub-sections(final-verification deliverables — 동일). 이들 섹션은 Response ID 가 있더라도 무시하고 raw 텍스트로 렌더한다.
|
|
85
|
+
- [ ] 1.5 `serialize_user_response(form_payload)` 구현 — 입력은 JS 측에서 보낼 dict. 출력은 `user-response.template.md` 포맷의 문자열. Python 측에서도 호출 가능(server-side fallback 용)하지만 1차 구현은 JS 가 클라이언트에서 직접 같은 포맷을 만든다 — Python 의 이 함수는 **그 직렬화 결과가 스키마에 맞는지 검증**하는 reference (validator 가 호출).
|
|
86
|
+
|
|
87
|
+
### Task 2 — `templates/reports/user-response.template.md` 작성
|
|
88
|
+
|
|
89
|
+
- [ ] 2.1 frontmatter 스키마 정의: `task-key`, `task-type`, `seq`, `source-report`, `decisions[].id`, `decisions[].type`, `decisions[].value`, `decisions[].rationale?`, `created-by: user`, `created-at: <ISO>`.
|
|
90
|
+
- [ ] 2.2 본문 포맷: Response ID 별로 `### D-001 — <title>` 헤딩 + `Type: <select|radio|checkbox|textarea|approval>` 라인 + `Value:` 블록 + 선택적 `Rationale:`.
|
|
91
|
+
- [ ] 2.3 “Why” 주석 한 줄(`<!-- single source of truth: scripts/okstra_ctl/report_views.py serialize_user_response -->`).
|
|
92
|
+
|
|
93
|
+
### Task 3 — HTML 자산 (`templates/reports/report.css`, `report.js`)
|
|
94
|
+
|
|
95
|
+
- [ ] 3.1 `report.css` — 읽기 폭 80ch 최대, 테이블 sticky header, `details` 토글, 인쇄 대응(`@media print`). 색은 시스템 색(`Canvas` / `CanvasText`) 기반으로 다크모드 자동.
|
|
96
|
+
- [ ] 3.2 `report.js` —
|
|
97
|
+
- `collectFormValues()` 함수: 모든 `[data-decision-id]` form 의 현재 값을 수집.
|
|
98
|
+
- `buildSidecarMarkdown(values)` 함수: `templates/reports/user-response.template.md` 스키마와 **byte-identical** 출력을 만들도록 작성. (Task 4 의 golden fixture 가 Python ↔ JS 결과를 동시 검증.)
|
|
99
|
+
- 상단/하단에 각각 `[Export decision sidecar]` 버튼, 출력 `<pre id="sidecar-output">`, `[Copy]` 버튼. Copy 는 `navigator.clipboard.writeText`, 실패 시 selectRange fallback.
|
|
100
|
+
- [ ] 3.3 HTML renderer 는 빌드 시 두 파일을 `<style>` / `<script>` 로 인라인. 외부 참조 0.
|
|
101
|
+
|
|
102
|
+
### Task 4 — Golden fixtures + 테스트
|
|
103
|
+
|
|
104
|
+
- [ ] 4.1 `tests/fixtures/reports/golden-original.md` 작성 — 다음을 모두 포함: token 치환 후의 비용 행(`$26.55` 등), §4.5.9 Verdict details, §0 Clarification Response Carried In, §5 Clarification Items 표(Response ID 2개), §6 Recommended Next Steps(Response ID 1개 — approval), §7 Follow-up Tasks(자동 생성 1행). **추가로 phase-별 fixture 3개**: `golden-implementation.md`(§4.7 8 sub-section 모두 포함), `golden-final-verification.md`(§4.8 6 sub-section + Verdict Token=`accepted|conditional-accept|blocked` 한 케이스씩), `golden-release-handoff.md`(§4.6.1–4.6.7 모두 포함, §4.6.6 Merge Conflict Probe 포함). 각 fixture 의 slim/html 기대 산출물을 동봉.
|
|
105
|
+
- [ ] 4.2 기대 산출물 작성 — `.slim.md`, `.html`. HTML 비교는 (a) DOCTYPE + 인라인 자산 strip, (b) whitespace normalize 후 byte diff.
|
|
106
|
+
- [ ] 4.3 `tests/test_report_views.py` — slim/HTML round-trip + `serialize_user_response` 가 example payload 로 스키마 검증 통과 + JS 직렬화 결과(Node 로 `templates/reports/report.js` 의 `buildSidecarMarkdown` 호출)와 Python 결과가 동일한지 확인하는 cross-check.
|
|
107
|
+
|
|
108
|
+
### Task 5 — Phase 6→7 sequence 통합
|
|
109
|
+
|
|
110
|
+
- [ ] 5.1 `skills/okstra-report-writer/SKILL.md` — “Phase 6 → Phase 7 execution sequence (BLOCKING order)” 섹션에 **step 2.5 — Render report views (BLOCKING)** 를 추가. 명령:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
python3 scripts/okstra-render-report-views.py \
|
|
114
|
+
<runDirectoryPath>/reports/final-report-<task-type>-<seq>.md
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
step 2 이후 step 3 이전. 실패 시 lead 가 자체 호출 후 fallback. 두 산출물(`*.slim.md`, `*.html`) 부재 시 validator 가 run 을 실패시킨다(아래 Task 6).
|
|
118
|
+
- [ ] 5.2 Persistence Checklist 에 두 항목 추가:
|
|
119
|
+
- `[ ] Slim AI report: runs/<task-type>/reports/final-report-<task-type>-<seq>.slim.md`
|
|
120
|
+
- `[ ] Human HTML report: runs/<task-type>/reports/final-report-<task-type>-<seq>.html`
|
|
121
|
+
- [ ] 5.3 `agents/workers/report-writer-worker.md` 의 required-reading 에 본 plan + `user-response.template.md` 추가. 단, **report-writer worker 자체는 HTML/slim 을 만들지 않는다** — 그건 phase 7 의 결정론적 스크립트의 책임. worker 는 원본 MD 만 쓴다(현재와 동일).
|
|
122
|
+
- [ ] 5.4 `skills/okstra-report-writer/SKILL.md` 의 작성자 표기는 2026-05-17 머지의 **Report Owner: Claude lead / Report Author: `<Report writer worker | Claude lead (release-handoff or fallback)>`** 용어를 그대로 따른다(별도 신규 용어 도입 금지).
|
|
123
|
+
- [ ] 5.5 Analysis worker(`claude/codex/gemini-worker.md`) 의 required-reading 은 **건드리지 않는다** — 2026-05-17 정정에서 final-report template 을 의도적으로 제외했다. slim/HTML renderer 는 그 worker 들의 입력이 아니다.
|
|
124
|
+
|
|
125
|
+
### Task 6 — Validator
|
|
126
|
+
|
|
127
|
+
- [ ] 6.1 `validators/validate-report-views.py` 작성 — 원본 MD 가 있는 run 폴더에서:
|
|
128
|
+
- 두 파생 파일이 존재하는가
|
|
129
|
+
- slim 의 헤딩 집합이 원본의 헤딩 집합의 부분집합인가
|
|
130
|
+
- **slim 이 `validators/validate-run.py` 가 검사하는 모든 substring(Verdict Card 셀, §2 Verdict Token, implementation-planning 9개, implementation §4.7 8개, final-verification §4.8 6개, release-handoff §4.6 + §4.6.6)을 원본과 byte-identical 로 보존하는가** — 신규 strip 규칙이 future validator 와 충돌하는 회귀를 차단.
|
|
131
|
+
- HTML 에서 검출된 Response ID 집합이 원본 MD 의 Response ID 집합과 동일한가
|
|
132
|
+
- HTML 의 §4.6 / §4.7 / §4.8 안에 `<form>` 또는 `<input>` 가 **없는가** (deliverable section 에 폼 부착 금지 규칙)
|
|
133
|
+
- 외부 URL(`http(s)://`) 이 HTML 의 `<script src>` / `<link href>` / `<img src>` 에 등장하지 않는가 (self-contained 보장)
|
|
134
|
+
- [ ] 6.2 `validators/validate-run.py` 의 기존 phase-별 substring 검사 직후에 위 호출을 hook. 실패 시 `exit 1`. 2026-05-17 머지된 Verdict Card byte-match / §4.6.6 / verdict vocabulary / §4.7 / §4.8 검사와 같은 단계에서 실행되도록 한다.
|
|
135
|
+
|
|
136
|
+
### Task 7 — Node CLI 위임 + 문서
|
|
137
|
+
|
|
138
|
+
- [ ] 7.1 `src/commands/render-views.mjs` (또는 기존 command 디렉토리 규약에 맞춰) 추가. 단순히 `~/.okstra/lib/python/.../okstra-render-report-views.py` 를 spawn. 인자 파싱만 JS.
|
|
139
|
+
- [ ] 7.2 `bin/okstra` 의 서브커맨드 라우팅 테이블에 등록.
|
|
140
|
+
- [ ] 7.3 `node bin/okstra doctor` 가 새 스크립트의 존재 확인 항목을 출력하는지 확인(있으면 추가, 없으면 보류).
|
|
141
|
+
- [ ] 7.4 `CHANGES.md` 한 줄 추가:
|
|
142
|
+
- `feat(report-views): Phase 7 이 final-report 외에 *.slim.md(AI용 토큰절약) + *.html(self-contained, 결정폼 포함) 두 view 를 자동 생성. 사용자 결정은 HTML 의 [Export decision sidecar] 버튼으로 markdown 직렬화 후 runs/<task-type>/decisions/ 에 저장. 사용자 영향: 보고서 디렉토리에 두 파일 추가, 원본 MD 형식 변경 없음.`
|
|
143
|
+
|
|
144
|
+
### Task 8 — End-to-end smoke
|
|
145
|
+
|
|
146
|
+
- [ ] 8.1 `tests-e2e/` 아래에 새 시나리오 추가(또는 기존 scenario-01 에 후속 step 추가): 작은 fake run 의 phase 6 산출물에 대해 render-views 를 호출하고, 두 파일이 생성되며 validator 가 통과하는지.
|
|
147
|
+
- [ ] 8.2 실제 브라우저에서 HTML 을 열고 (a) form 선택, (b) Export 버튼 클릭, (c) `<pre>` 출력이 `serialize_user_response` Python 출력과 byte-match 하는지 수동 확인. (CLAUDE.md: UI 변경은 브라우저에서 직접 확인.)
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Out of scope (본 plan 에서 하지 않음)
|
|
152
|
+
|
|
153
|
+
- 사용자가 만든 decision sidecar 를 **다음 phase 의 lead 가 어떻게 소비하는지** 의 계약 변경. 그건 별도 plan 으로 다룬다 (phase profile 의 required-reading 에 sidecar 경로 추가, lead 가 sidecar 의 Response ID 별 응답을 prompt 에 어떻게 인용하는지 등).
|
|
154
|
+
- 차트 라이브러리 도입. 현재는 인라인 SVG 의 sparkline 정도만. 본격적인 시각화는 후속 plan.
|
|
155
|
+
- 원본 final-report 의 한국어 본문 자체를 줄이는 prompt-diet 작업(이건 v2 plan 의 P2 범위).
|
|
156
|
+
- `release-handoff` 단독 lead 분기에서의 동작 차이. 일단 같은 스크립트를 호출하되, release-handoff 의 Section 4.6 은 사용자 결정 행이 이미 H1/H2/H3 메뉴로 처리되므로 form 부착 대상에서 제외하는 special-case 만 Task 1.4 단계에서 추가.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Open questions for approval
|
|
161
|
+
|
|
162
|
+
다음 항목에 대해 사용자 응답을 기다린다 (구현 시작 전 BLOCKING):
|
|
163
|
+
|
|
164
|
+
1. Response ID 컬럼을 Section 5/6/7 의 표 스키마에 **신설**해도 되는가? 또는 §5 의 기존 `C-*`(Clarification) ID 를 그대로 user-response 트리거로 재사용해야 하는가? — 후자라면 `templates/reports/final-report.template.md` 수정이 거의 0 이고, 8-column SSOT(`_common-contract.md §Clarification request policy`)와도 충돌하지 않는다. **권장: 재사용**.
|
|
165
|
+
2. user-response 파일 위치를 `runs/<task-type>/user-responses/` 로 신설할까, 아니면 audit sidecar 와 같은 `runs/<task-type>/worker-results/` 디렉토리에 다른 prefix(`user-response-*.md`)로 둘까? 후자는 디렉토리 신설 없이 끝나지만 author 가 사람이라 audit 파일과 섞이는 부담이 있다.
|
|
166
|
+
3. HTML 의 차트 표현은 1차에서는 “표 그대로 + 작은 인라인 SVG 진행바” 정도로 충분한가? (본격 차트는 후속 plan)
|
|
167
|
+
4. 2026-05-17 머지로 추가된 §4.7 / §4.8 / §4.6.6 / Verdict Card 검사는 모두 substring 기반이다. slim stripper 가 “보존 invariant” 를 지키는지 검증하는 방법으로 **substring 검사를 그대로 재실행**하는 게 가장 안전한가, 아니면 별도 “preserved heading” 화이트리스트를 두는 게 맞나? **권장: 전자 — `validate-run.py` 의 substring 목록을 import 하여 동일 함수로 검사**하면 단일 reference point 가 유지된다.
|
package/package.json
CHANGED
package/runtime/BUILD.json
CHANGED
|
@@ -54,7 +54,7 @@ Unlike the Codex / Gemini workers, you are an in-process Claude subagent — you
|
|
|
54
54
|
|
|
55
55
|
## Required Reading Before Any Analysis
|
|
56
56
|
|
|
57
|
-
Before producing any output, you MUST read every input file enumerated in the `[Required reading]` block of the lead's prompt from the very first character to the very last character.
|
|
57
|
+
Before producing any output, you MUST read every input file enumerated in the `[Required reading]` block of the lead's prompt from the very first character to the very last character. For analysis workers this includes the task brief, analysis profile, analysis material (if present), reference expectations, and the carry-in clarification response (if present). Analysis workers do NOT read `final-report-template.md` — that file is for the Report writer worker only (see `okstra-team-contract` "Audience-scoped enumeration"). Producing findings without the template is the intended contract; the report writer in Phase 6 owns final-report structure.
|
|
58
58
|
|
|
59
59
|
- Use a single `Read` call per file with no `offset` and no `limit`. If a file is genuinely too large for one read, page through it with explicit `offset` / `limit` calls that together cover the entire file, and record the page boundaries in your Findings.
|
|
60
60
|
- For the carry-in clarification response, walk every row of `## 5. Clarification Items` (`C-001`, `C-002`, ...) in full, including rows whose `User input` cell is blank — a blank `User input` with `Status=open` is itself a signal you must surface, not skip. Skimming these rows is the most common failure mode here; the fact that the file you will eventually contribute to has a structurally similar section 5 is NOT a license to skim.
|
|
@@ -88,7 +88,7 @@ You are an in-process Claude subagent — Lead's `Agent()` call blocks until you
|
|
|
88
88
|
After your `Write` to the assigned worker-results file (path provided by Lead as `**Worker Result Path:**` or derived under `runs/<task-type>/worker-results/claude-worker-<task-type>-<seq>.md`) succeeds:
|
|
89
89
|
|
|
90
90
|
1. Return your final assistant message **immediately**, in this format:
|
|
91
|
-
`Worker results written to <abs path>. Sections
|
|
91
|
+
`Worker results written to <abs path>. Sections 1–5 complete. Findings: <n>.`
|
|
92
92
|
2. Do NOT perform additional `Read`, `Grep`, `Glob`, MCP, or self-review tool calls after the file is written.
|
|
93
93
|
3. Do NOT rewrite the worker-results file with `Write` more than once. If a correction is genuinely required, perform a single `Edit` and then return immediately.
|
|
94
94
|
4. The only exception is recording a `tool-failure` in the errors sidecar when a post-Write failure is itself the failure being reported — return immediately after that single sidecar append.
|
|
@@ -122,7 +122,7 @@ This wrapper does NOT invoke MCP tools directly. MCP availability inside the Cod
|
|
|
122
122
|
|
|
123
123
|
## Required Reading Before Any Analysis
|
|
124
124
|
|
|
125
|
-
Before producing any output, you MUST ensure the underlying Codex CLI run reads every input file enumerated in the `[Required reading]` block of the lead's prompt from the very first character to the very last character.
|
|
125
|
+
Before producing any output, you MUST ensure the underlying Codex CLI run reads every input file enumerated in the `[Required reading]` block of the lead's prompt from the very first character to the very last character. For analysis workers this includes the task brief, analysis profile, analysis material (if present), reference expectations, and the carry-in clarification response (if present). Analysis workers do NOT read `final-report-template.md` — that file is for the Report writer worker only (see `okstra-team-contract` "Audience-scoped enumeration"). Producing findings without the template is the intended contract; the report writer in Phase 6 owns final-report structure.
|
|
126
126
|
|
|
127
127
|
- The lead's prompt body, which you persist verbatim and feed into Codex via stdin, already contains the explicit list of files and the end-to-end reading rule. Do not strip or summarize that block before passing it to the CLI.
|
|
128
128
|
- For the carry-in clarification response, the CLI must walk every row of `## 5. Clarification Items` (`C-001`, `C-002`, ...) in full, including rows whose `User input` cell is blank — a blank `User input` with `Status=open` is itself a signal you must surface. The fact that the prior run's final report and the upcoming output share section 5 structure is NOT a license to skim.
|
|
@@ -122,7 +122,7 @@ This wrapper does NOT invoke MCP tools directly. MCP availability inside the Gem
|
|
|
122
122
|
|
|
123
123
|
## Required Reading Before Any Analysis
|
|
124
124
|
|
|
125
|
-
Before producing any output, you MUST ensure the underlying Gemini CLI run reads every input file enumerated in the `[Required reading]` block of the lead's prompt from the very first character to the very last character.
|
|
125
|
+
Before producing any output, you MUST ensure the underlying Gemini CLI run reads every input file enumerated in the `[Required reading]` block of the lead's prompt from the very first character to the very last character. For analysis workers this includes the task brief, analysis profile, analysis material (if present), reference expectations, and the carry-in clarification response (if present). Analysis workers do NOT read `final-report-template.md` — that file is for the Report writer worker only (see `okstra-team-contract` "Audience-scoped enumeration"). Producing findings without the template is the intended contract; the report writer in Phase 6 owns final-report structure.
|
|
126
126
|
|
|
127
127
|
- The lead's prompt body, which you persist verbatim and feed into Gemini via stdin, already contains the explicit list of files and the end-to-end reading rule. Do not strip or summarize that block before passing it to the CLI.
|
|
128
128
|
- For the carry-in clarification response, the CLI must walk every row of `## 5. Clarification Items` (`C-001`, `C-002`, ...) in full, including rows whose `User input` cell is blank — a blank `User input` with `Status=open` is itself a signal you must surface. The structural similarity between the prior final report and the upcoming output is the most common reason this step gets skipped — do not repeat that.
|
|
@@ -55,9 +55,11 @@ Before writing the final report, you MUST read every input file enumerated in th
|
|
|
55
55
|
|
|
56
56
|
The final-report file MUST follow `instruction-set/final-report-template.md` if present; otherwise the structure defined in the `okstra-report-writer` skill.
|
|
57
57
|
|
|
58
|
+
You author the final-report **markdown only**. The slim AI copy (`*.slim.md`) and the self-contained human HTML view (`*.html`) are produced deterministically by Phase 7 step 1.5 (`scripts/okstra-render-report-views.py`) from the markdown you wrote — do NOT generate or paste HTML/slim content yourself. The original final-report MD is the single source of truth; user input collected via the HTML form goes into a separate `runs/<task-type>/user-responses/user-response-<task-type>-<seq>.md` sidecar (schema in [`templates/reports/user-response.template.md`](../../templates/reports/user-response.template.md)) and never overwrites your report.
|
|
59
|
+
|
|
58
60
|
Hard rules:
|
|
59
61
|
|
|
60
|
-
- The file's `Author:` header line is `Report writer worker` (your role)
|
|
62
|
+
- The file's `Report Author:` header line is `Report writer worker` (your role); `Report Owner:` remains `Claude lead`. Do NOT set `Report Author:` to `Claude lead` unless this run is `release-handoff` (which is single-lead by design) or a recorded report-writer dispatch failure forced the fallback.
|
|
61
63
|
- **Source items (worker:item) preservation.** When synthesising `## 1.1 Consensus` / `## 1.2 Differences` / `## 3.1 Primary Evidence` rows from worker outputs, the `Source items` / `Supporting workers` / `Workers (position)` / `Source` column MUST list each contributing worker's item ID as `worker:item-id` (e.g. `claude:F-001, codex:1.1, gemini:F-3`). Bare worker-name lists (e.g. `claude, codex, gemini`) are deprecated — they break traceability back to the original worker-results files. See `prompts/profiles/_common-contract.md` "Cross-worker traceability" SSOT.
|
|
62
64
|
- **Verdict Card (top)** is mandatory in every final-report. Its `Verdict Token` / `Direction` / `Next Step` cells MUST byte-match the corresponding cells in `## 2. Final Verdict` and the first item of `## 6. Recommended Next Steps`. The validator treats the card as a non-authoritative index — divergence is `contract-violated`.
|
|
63
65
|
- **No deprecated sections.** Do NOT emit `4.5.8 User Approval Request` (the body stub is deleted; the top-of-report Approval block is the only one), `4.5.9 Open Questions`, `5.1 추가 자료 요청`, or `5.2 사용자 확인 질문`. The validator fails reports that contain any of these headings.
|