okstra 0.102.1 → 0.102.3
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 +5 -6
- package/README.md +5 -6
- package/docs/kr/architecture/storage-model.md +1 -1
- package/docs/kr/architecture.md +8 -12
- package/docs/kr/cli.md +6 -6
- package/docs/kr/container.md +1 -1
- package/docs/kr/performance-improvement-plan-v2.md +2 -2
- package/docs/project-structure-overview.md +2 -2
- package/package.json +7 -2
- package/runtime/BUILD.json +2 -2
- package/runtime/bin/okstra-antigravity-exec.sh +1 -2
- package/runtime/bin/okstra-codex-exec.sh +1 -2
- package/runtime/bin/okstra-render-final-report.py +2 -9
- package/runtime/bin/okstra-spawn-followups.py +4 -6
- package/runtime/bin/okstra-trace-cleanup.sh +24 -4
- package/runtime/prompts/lead/okstra-lead-contract.md +2 -2
- package/runtime/prompts/lead/report-writer.md +1 -1
- package/runtime/prompts/profiles/_common-contract.md +9 -11
- package/runtime/python/okstra_ctl/codex_dispatch.py +4 -12
- package/runtime/python/okstra_ctl/consumers.py +35 -0
- package/runtime/python/okstra_ctl/container.py +4 -6
- package/runtime/python/okstra_ctl/dispatch_core.py +4 -12
- package/runtime/python/okstra_ctl/final_report_paths.py +24 -0
- package/runtime/python/okstra_ctl/handoff.py +2 -1
- package/runtime/python/okstra_ctl/implementation_stage.py +7 -11
- package/runtime/python/okstra_ctl/report_view_artifacts.py +14 -0
- package/runtime/python/okstra_ctl/report_views.py +7 -4
- package/runtime/python/okstra_ctl/run.py +3 -10
- package/runtime/python/okstra_ctl/stage_targets.py +18 -0
- package/runtime/python/okstra_ctl/wizard.py +24 -25
- package/runtime/python/okstra_ctl/wizard_stage_intent.py +54 -0
- package/runtime/python/okstra_token_usage/report.py +2 -5
- package/runtime/validators/validate-report-views.py +2 -1
- package/runtime/validators/validate-run.py +1 -11
- package/src/cli-registry.mjs +1 -1
- package/src/commands/lifecycle/install.mjs +10 -20
- package/src/commands/lifecycle/uninstall.mjs +7 -10
- package/docs/superpowers/plans/2026-05-12-ticket-id-in-reports.md +0 -638
- package/docs/superpowers/plans/2026-05-14-convergence-queue-pruning.md +0 -1568
- package/docs/superpowers/plans/2026-05-17-dual-format-final-report.md +0 -167
- package/docs/superpowers/plans/2026-05-20-final-report-language.md +0 -1501
- package/docs/superpowers/plans/2026-05-20-implementation-planning-multi-stage.md +0 -1267
- package/docs/superpowers/plans/2026-05-20-okstra-run-prompt-sot-b1.md +0 -1007
- package/docs/superpowers/plans/2026-05-20-wizard-messages-json-sot.md +0 -720
- package/docs/superpowers/plans/2026-05-20-wizard-prompt-json-sot-a1.md +0 -681
- package/docs/superpowers/plans/2026-05-21-improvement-discovery-task-type.md +0 -1691
- package/docs/superpowers/plans/2026-05-24-implementation-lead-context-slimming.md +0 -1700
- package/docs/superpowers/plans/2026-05-25-okstra-project-root-rename.md +0 -158
- package/docs/superpowers/plans/2026-05-26-wizard-3-option-picker.md +0 -860
- package/docs/superpowers/plans/2026-06-02-final-verification-protocol-hardening.md +0 -326
- package/docs/superpowers/plans/2026-06-02-okstra-run-branch-confirm-step.md +0 -337
- package/docs/superpowers/plans/2026-06-02-okstra-run-phase-pane-cleanup.md +0 -410
- package/docs/superpowers/plans/2026-06-02-requirements-discovery-fanout.md +0 -728
- package/docs/superpowers/plans/2026-06-04-adversarial-implementation-planning.md +0 -294
- package/docs/superpowers/plans/2026-06-04-adversarial-verification.md +0 -570
- package/docs/superpowers/plans/2026-06-04-coverage-critic.md +0 -516
- package/docs/superpowers/plans/2026-06-04-stage-cohesion-planner.md +0 -351
- package/docs/superpowers/plans/2026-06-04-stage-run-batching.md +0 -457
- package/docs/superpowers/plans/2026-06-05-acceptance-critic.md +0 -251
- package/docs/superpowers/plans/2026-06-05-compact-markdown-report-tables.md +0 -323
- package/docs/superpowers/plans/2026-06-05-wizard-batch-prompts.md +0 -559
- package/docs/superpowers/plans/2026-06-06-final-verification-whole-task-gate.md +0 -993
- package/docs/superpowers/plans/2026-06-06-stage-parallel-and-pending-fixes.md +0 -93
- package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p1.md +0 -447
- package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p2.md +0 -289
- package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p3.md +0 -774
- package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p4.md +0 -303
- package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p5-multidep-base.md +0 -387
- package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase2.md +0 -275
- package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase3.md +0 -282
- package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4a.md +0 -147
- package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4b.md +0 -262
- package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4c.md +0 -184
- package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4d.md +0 -88
- package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4e.md +0 -250
- package/docs/superpowers/plans/2026-06-07-stage-conformance-qa.md +0 -409
- package/docs/superpowers/plans/2026-06-09-implementation-run-artifact-stage-isolation.md +0 -320
- package/docs/superpowers/plans/2026-06-10-concurrent-run-team-guard.md +0 -456
- package/docs/superpowers/plans/2026-06-10-git-reconcile-stale-sha-recovery.md +0 -1408
- package/docs/superpowers/plans/2026-06-10-lead-worker-completion-polling-PROBE.md +0 -42
- package/docs/superpowers/plans/2026-06-10-lead-worker-completion-polling.md +0 -337
- package/docs/superpowers/plans/2026-06-10-p6-token-usage-incremental.md +0 -1029
- package/docs/superpowers/plans/2026-06-10-stage-group-handoff.md +0 -1572
- package/docs/superpowers/plans/2026-06-11-fix-cycle.md +0 -1290
- package/docs/superpowers/plans/2026-06-11-wizard-whole-task-final-verification.md +0 -526
- package/docs/superpowers/plans/2026-06-12-html-plan-approval.md +0 -1000
- package/docs/superpowers/plans/2026-06-13-repo-risk-hardening.md +0 -493
- package/docs/superpowers/plans/2026-06-14-host-runtime-auto-execution.md +0 -1775
- package/docs/superpowers/plans/2026-06-15-coding-preflight-pack-dispatch-path.md +0 -504
- package/docs/superpowers/plans/2026-06-15-internal-skill-migration-final-fixups.md +0 -342
- package/docs/superpowers/plans/2026-06-15-internal-skill-migration-fixups.md +0 -258
- package/docs/superpowers/plans/2026-06-15-internal-skill-migration-remaining-fixups.md +0 -387
- package/docs/superpowers/plans/2026-06-15-internal-skill-resource-migration.md +0 -749
- package/docs/superpowers/plans/2026-06-15-worker-prompt-anchor-final-fixups.md +0 -828
- package/docs/superpowers/plans/2026-06-15-worker-prompt-header-error-contract.md +0 -490
- package/docs/superpowers/plans/2026-06-17-okstra-error-report.md +0 -724
- package/docs/superpowers/plans/2026-06-18-subagent-pane-reclaim.md +0 -483
- package/docs/superpowers/plans/2026-06-19-agent-operating-standard.md +0 -476
- package/docs/superpowers/plans/2026-06-19-okstra-inspect-recap-facet.md +0 -647
- package/docs/superpowers/plans/2026-06-20-error-feedback-loop.md +0 -1019
- package/docs/superpowers/plans/2026-06-20-run-index-row-normalization.md +0 -583
- package/docs/superpowers/plans/2026-06-20-stage-auto-integrate-teardown.md +0 -819
- package/docs/superpowers/plans/2026-06-21-okstra-container-local-user-test.md +0 -714
- package/docs/superpowers/plans/2026-06-21-release-handoff-local-checkout.md +0 -348
- package/docs/superpowers/plans/2026-06-23-implementation-stage-multiselect-chain.md +0 -630
- package/docs/superpowers/plans/2026-06-23-implementation-step-commit-granularity.md +0 -274
- package/docs/superpowers/plans/2026-06-23-phase-batch-cleanup-enforcement.md +0 -409
- package/docs/superpowers/plans/2026-06-24-cross-project-precondition.md +0 -542
- package/docs/superpowers/plans/2026-06-24-decision-drafts-render-gap.md +0 -568
- package/docs/superpowers/plans/2026-06-24-manual-user-test-section.md +0 -203
- package/docs/superpowers/plans/2026-06-24-okstra-container-build-rename.md +0 -525
- package/docs/superpowers/specs/2026-05-12-ticket-id-in-reports-design.md +0 -131
- package/docs/superpowers/specs/2026-05-15-implementation-plan-verification-design.md +0 -254
- package/docs/superpowers/specs/2026-05-20-final-report-language-design.md +0 -383
- package/docs/superpowers/specs/2026-05-20-implementation-planning-multi-stage-design.md +0 -322
- package/docs/superpowers/specs/2026-05-20-okstra-run-prompt-sot-design.md +0 -299
- package/docs/superpowers/specs/2026-05-21-improvement-discovery-task-type-design.md +0 -335
- package/docs/superpowers/specs/2026-06-02-okstra-run-branch-confirm-step-design.md +0 -113
- package/docs/superpowers/specs/2026-06-02-okstra-run-phase-pane-cleanup-design.md +0 -173
- package/docs/superpowers/specs/2026-06-02-requirements-discovery-fanout-design.md +0 -154
- package/docs/superpowers/specs/2026-06-04-adversarial-implementation-planning-design.md +0 -90
- package/docs/superpowers/specs/2026-06-04-adversarial-verification-design.md +0 -176
- package/docs/superpowers/specs/2026-06-04-coverage-critic-design.md +0 -99
- package/docs/superpowers/specs/2026-06-04-stage-splitting-cost-aware-design.md +0 -98
- package/docs/superpowers/specs/2026-06-05-acceptance-critic-design.md +0 -90
- package/docs/superpowers/specs/2026-06-05-compact-markdown-report-tables-design.md +0 -87
- package/docs/superpowers/specs/2026-06-05-wizard-batch-prompts-design.md +0 -121
- package/docs/superpowers/specs/2026-06-06-final-verification-whole-task-gate-design.md +0 -126
- package/docs/superpowers/specs/2026-06-06-stage-worktree-isolation-design.md +0 -180
- package/docs/superpowers/specs/2026-06-06-vertical-slice-tdd-planning-design.md +0 -179
- package/docs/superpowers/specs/2026-06-07-stage-conformance-qa-design.md +0 -169
- package/docs/superpowers/specs/2026-06-09-executor-model-custom-id-cascade-design.md +0 -66
- package/docs/superpowers/specs/2026-06-09-implementation-run-artifact-stage-isolation-design.md +0 -87
- package/docs/superpowers/specs/2026-06-10-blocking-contract-posthoc-conformance-design.md +0 -168
- package/docs/superpowers/specs/2026-06-10-concurrent-run-team-guard-design.md +0 -107
- package/docs/superpowers/specs/2026-06-10-git-reconcile-stale-sha-recovery-design.md +0 -105
- package/docs/superpowers/specs/2026-06-10-lead-worker-completion-polling-design.md +0 -113
- package/docs/superpowers/specs/2026-06-10-stage-group-handoff-design.md +0 -156
- package/docs/superpowers/specs/2026-06-11-brief-entry-only-handoff-stage-entry-design.md +0 -158
- package/docs/superpowers/specs/2026-06-11-fix-cycle-design.md +0 -94
- package/docs/superpowers/specs/2026-06-11-wizard-whole-task-final-verification-design.md +0 -89
- package/docs/superpowers/specs/2026-06-12-codex-lead-adapter-design.md +0 -358
- package/docs/superpowers/specs/2026-06-12-html-plan-approval-design.md +0 -85
- package/docs/superpowers/specs/2026-06-12-stage-discipline-rule-design.md +0 -108
- package/docs/superpowers/specs/2026-06-13-forbidden-actions-ssot-design.md +0 -134
- package/docs/superpowers/specs/2026-06-13-neutral-tmux-lead-adapter-design.md +0 -284
- package/docs/superpowers/specs/2026-06-14-host-runtime-auto-execution-design.md +0 -404
- package/docs/superpowers/specs/2026-06-17-okstra-error-report-design.md +0 -123
- package/docs/superpowers/specs/2026-06-18-subagent-pane-reclaim-design.md +0 -150
- package/docs/superpowers/specs/2026-06-19-agent-operating-standard-design.md +0 -120
- package/docs/superpowers/specs/2026-06-19-okstra-inspect-recap-facet-design.md +0 -96
- package/docs/superpowers/specs/2026-06-20-error-feedback-loop-design.md +0 -171
- package/docs/superpowers/specs/2026-06-20-run-index-row-normalization-design.md +0 -112
- package/docs/superpowers/specs/2026-06-20-stage-auto-integrate-teardown-design.md +0 -145
- package/docs/superpowers/specs/2026-06-21-okstra-container-local-user-test-design.md +0 -125
- package/docs/superpowers/specs/2026-06-21-release-handoff-local-checkout-design.md +0 -113
- package/docs/superpowers/specs/2026-06-23-implementation-stage-multiselect-chain-design.md +0 -138
- package/docs/superpowers/specs/2026-06-23-implementation-step-commit-granularity-design.md +0 -120
- package/docs/superpowers/specs/2026-06-24-cross-project-precondition-design.md +0 -129
- package/docs/superpowers/specs/2026-06-24-decision-drafts-render-gap-design.md +0 -185
- package/docs/superpowers/specs/2026-06-24-manual-user-test-section-design.md +0 -121
- package/docs/superpowers/specs/2026-06-24-okstra-container-build-rename-design.md +0 -110
|
@@ -1,326 +0,0 @@
|
|
|
1
|
-
# final-verification 검증 프로토콜 강화 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:** final-verification 을 "리뷰 의견 수집"에서 **target 일치성 → 요구사항 커버리지 → read-only validation → 구조화된 verdict** 로 이어지는 검증 프로토콜로 강화한다.
|
|
6
|
-
|
|
7
|
-
**Architecture:** lead 의 강한 entry gate 와 동일한 기준을 (1) 워커 dispatch contract, (2) 입력 템플릿, (3) report schema/template, (4) validator 에 구조화해 전달·강제한다. 변경은 저위험 prose/contract(PR1)와 고위험 schema/validator(PR2) 둘로 나눈다.
|
|
8
|
-
|
|
9
|
-
**Tech Stack:** Markdown 프로파일/템플릿, JSON Schema, Python(validate-run.py + pytest), Jinja2 렌더 + i18n(en/ko json), okstra 빌드(`npm run build`).
|
|
10
|
-
|
|
11
|
-
근거: 본 계획은 두 출처를 병합한다 — (A) 검증 초점 분석(이 세션), (B) 다른 에이전트의 final-verification contract 분석. 아래 모든 항목은 소스 직접 확인으로 검증됨.
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## 범위 결정 (먼저 확인)
|
|
16
|
-
|
|
17
|
-
- **PR1 (저위험, schema 무변경):** 프로파일 prose 정정 + 검증 초점 재설계 + 워커 dispatch target snapshot + 입력 템플릿. 단독으로 가치 있음.
|
|
18
|
-
- **PR2 (고위험, breaking — pre-1.0 라 compat 불필요):** report schema/template/i18n + validator 강제 + golden fixture. PR1 위에 쌓는다.
|
|
19
|
-
- **범위 밖 (별도):** `analysis-material` 이 brief 전체를 복사하는 중복([material.py](../../../scripts/okstra_ctl/material.py)). **모든 task-type 에 영향을 주는 cross-cutting** 이라 이 PR 들에 섞지 않고 별도 후속 작업으로 분리.
|
|
20
|
-
|
|
21
|
-
브랜치: PR1/PR2 각각 `main` 기준 새 브랜치 (pane-cleanup PR 과 무관).
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
## File Structure
|
|
26
|
-
|
|
27
|
-
**PR1**
|
|
28
|
-
- Modify: `prompts/profiles/final-verification.md` — 검증 초점 재설계, no-mutation audit 범위 축소, routing vocab, section-name 호환, conditional-accept 참조, deliverable target-snapshot.
|
|
29
|
-
- Modify: `templates/worker-prompt-preamble.md` — `implementation` 전용 Worktree 블록을 `final-verification` 까지 확장(+ base ref / head SHA / diff stat anchor).
|
|
30
|
-
- Modify: `templates/reports/final-verification-input.template.md` — `## Requirement Coverage Source` 섹션 + target/requirement 질문.
|
|
31
|
-
|
|
32
|
-
**PR2**
|
|
33
|
-
- Modify: `schemas/final-report-v1.0.schema.json` — `sourceImplementationReport`(diffSummaryQuote/implementationBaseRef/gitDiffStat), `finalVerdict`(conditionalAcceptanceConditions), `ReadonlyCommandRow`(status/nullable exitCode/rejectionReason).
|
|
34
|
-
- Modify: `templates/reports/final-report.template.md` — §4.8.1 새 필드 렌더, §4.8.x Conditional Acceptance Conditions, Read-only Command Log status 렌더.
|
|
35
|
-
- Modify: `templates/reports/i18n/en.json` + `ko.json` — 신규 `evidenceMeta`/라벨 키.
|
|
36
|
-
- Modify: `validators/validate-run.py` — verdict↔blocker/condition/routing 일관성 강제 + 섹션 목록.
|
|
37
|
-
- Modify: `tests/test_validate_run.py`(또는 해당 파일) — 강제 로직 회귀 테스트.
|
|
38
|
-
- Modify: `tests/fixtures/reports/golden-final-verification.md`, `tests/fixtures/final-report-data/final-verification-001.data.json` — 새 필드 반영.
|
|
39
|
-
- Modify: `CHANGES.md` — 사용자 영향 엔트리(PR2 에서, 또는 양쪽).
|
|
40
|
-
|
|
41
|
-
`runtime/` 는 gitignored build output — 커밋에 포함 안 함. profile/template/preamble/schema/i18n 변경 후 `npm run build` 로 동기화.
|
|
42
|
-
|
|
43
|
-
---
|
|
44
|
-
|
|
45
|
-
# PR1 — 저위험 prose / contract
|
|
46
|
-
|
|
47
|
-
## Task 1: 검증 초점 재설계 + Expected output emphasis 제거
|
|
48
|
-
|
|
49
|
-
**Files:** Modify `prompts/profiles/final-verification.md:11-21`
|
|
50
|
-
|
|
51
|
-
- [ ] **Step 1:** `Primary focus areas` + `Expected output emphasis` 블록(11-21행)을 아래로 교체.
|
|
52
|
-
|
|
53
|
-
```markdown
|
|
54
|
-
- Primary focus areas (each maps to a deliverable section below):
|
|
55
|
-
- Acceptance-gating — a failure here pushes the verdict toward `blocked` / `conditional-accept`:
|
|
56
|
-
- requirement & acceptance coverage — every must-pass point in the brief's `## Acceptance Criteria` (and the approved plan's requirements) is covered with a cited artifact or raised as an Acceptance Blocker; no silent omissions
|
|
57
|
-
- delivered artifacts match recorded expected values in `reference-expectations` (config files, deployment manifests, other recorded expected states); when reference-expectations are absent, record it as missing information rather than assuming a match
|
|
58
|
-
- test & validation suite pass status — independently re-run the read-only two-tier command set (Tier 1 = brief/approved-plan `validation`, Tier 2 = `project.json` `qaCommands`) and confirm each passes on the verified head, citing exact command + exit code
|
|
59
|
-
- test correctness — delivered tests actually assert the intended behaviour: no gutted/weakened assertions, no tautological or always-passing tests, no tests exercising only mocks; new behaviour has matching coverage
|
|
60
|
-
- no new defects introduced — the diff does not break previously-working behaviour and adds no new bug (logic/off-by-one, null/empty handling, resource leaks, broken error paths)
|
|
61
|
-
- scope conformance — the delivered diff stays within the approved plan's scope; flag out-of-scope edits, unrelated file changes, leftover debug/commented-out code, and unintended deletions
|
|
62
|
-
- Residual-tracked — note as Residual Risk unless severe enough to block:
|
|
63
|
-
- unresolved edge cases
|
|
64
|
-
- regression risk in adjacent code paths not directly changed
|
|
65
|
-
- documentation or rollout gaps
|
|
66
|
-
- production-specific failure modes not caught by tests (env/config drift across stages, secrets & permission/auth changes, migration ordering & rollback executability, observability gaps)
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
- [ ] **Step 2:** `grep -n "Expected output emphasis" prompts/profiles/final-verification.md` → 0건(제거 확인). `grep -rn "Expected output emphasis" tests/ validators/` → 0건(참조 없음, 이미 확인됨).
|
|
70
|
-
- [ ] **Step 3:** `npm run build && bash validators/validate-workflow.sh` → OK.
|
|
71
|
-
- [ ] **Step 4:** commit `feat(profiles/final-verification): 검증 초점 재설계 — gating/residual 2계층 + 테스트정확성·범위·신규버그 추가`.
|
|
72
|
-
|
|
73
|
-
## Task 2: no-mutation audit 범위 축소 (자기모순 제거)
|
|
74
|
-
|
|
75
|
-
**Files:** Modify `prompts/profiles/final-verification.md:43`
|
|
76
|
-
|
|
77
|
-
- [ ] **Step 1:** self-review 5번 항목을 교체.
|
|
78
|
-
|
|
79
|
-
old:
|
|
80
|
-
```
|
|
81
|
-
5. **No-mutation audit** — scan the run's session transcripts for any Edit / Write / mutating Bash command. Any occurrence means the run has crossed into implementation and MUST be re-routed; do NOT silently strip the evidence.
|
|
82
|
-
```
|
|
83
|
-
new:
|
|
84
|
-
```
|
|
85
|
-
5. **No source-mutation audit** — scan the run's session transcripts for Edit / Write or state-mutating Bash commands that touch paths OUTSIDE `<PROJECT_ROOT>/.okstra/**` and outside the assigned run-artifact paths. Writes to worker prompts, audit sidecars, team-state, the final-report `data.json`, and rendered reports under the run directory are allowed okstra artifacts. Any source/schema/deployment mutation means the run has crossed into implementation and MUST be re-routed; do NOT silently strip the evidence.
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
- [ ] **Step 2:** `npm run build` → OK. commit `fix(profiles/final-verification): no-mutation audit 를 source-mutation 으로 한정 (.okstra artifact 허용)`.
|
|
89
|
-
|
|
90
|
-
## Task 3: routing vocabulary + section-name 호환 + conditional-accept 참조
|
|
91
|
-
|
|
92
|
-
**Files:** Modify `prompts/profiles/final-verification.md` (23, 29, 35행)
|
|
93
|
-
|
|
94
|
-
- [ ] **Step 1 (routing, 35행):** `Routing recommendation` deliverable 줄 교체.
|
|
95
|
-
|
|
96
|
-
old:
|
|
97
|
-
```
|
|
98
|
-
- **Routing recommendation**: brief note on the next safe phase (`done`, `error-analysis`, `implementation-planning`) tied to the verdict and blocker list.
|
|
99
|
-
```
|
|
100
|
-
new:
|
|
101
|
-
```
|
|
102
|
-
- **Routing recommendation**: the next safe phase — one of `release-handoff`, `done`, `error-analysis`, `implementation-planning` — tied to the verdict and blocker list. `release-handoff` is allowed ONLY when the Verdict Token is `accepted`.
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
- [ ] **Step 2 (section-name 호환, 23행):** entry-gate 줄에서 implementation report 필수 섹션 인용을 양쪽 표기 허용으로.
|
|
106
|
-
|
|
107
|
-
old fragment: ``includes `Plan link & approval evidence`, `Commit list`, ``
|
|
108
|
-
new fragment: ``includes the approved-plan reference (heading `Approved Plan Reference` or `Plan link & approval evidence`), `Commit list`, ``
|
|
109
|
-
|
|
110
|
-
- [ ] **Step 3 (conditional-accept 참조, 29행):** `conditional-accept` 설명에 구조화 deliverable 참조 추가(현 문장 끝에 append).
|
|
111
|
-
|
|
112
|
-
append: ` Each condition MUST be recorded as a row in the **Conditional Acceptance Conditions** deliverable (id, condition, evidence required, blocks-release-handoff).`
|
|
113
|
-
|
|
114
|
-
> 주의: 이 줄은 PR2 의 §4.8 Conditional Acceptance Conditions 섹션·schema 와 짝이다. PR1 만 단독 머지할 경우 이 Step 3 는 PR2 와 함께 가도록 보류 가능 — 실행 시점에 결정.
|
|
115
|
-
|
|
116
|
-
- [ ] **Step 4:** `npm run build && bash validators/validate-workflow.sh` → OK. commit `fix(profiles/final-verification): routing 에 release-handoff 추가 + approved-plan 섹션명 호환`.
|
|
117
|
-
|
|
118
|
-
## Task 4: 워커 dispatch 에 verification target snapshot 전달
|
|
119
|
-
|
|
120
|
-
**Files:** Modify `templates/worker-prompt-preamble.md:84-88`, `prompts/profiles/final-verification.md`(deliverable)
|
|
121
|
-
|
|
122
|
-
- [ ] **Step 1 (preamble):** `For the implementation phase specifically...` 블록(84-88)을 implementation + final-verification 둘 다 커버하도록 교체.
|
|
123
|
-
|
|
124
|
-
old:
|
|
125
|
-
```
|
|
126
|
-
For the **implementation phase** specifically, the dispatched prompt MUST also include:
|
|
127
|
-
|
|
128
|
-
- `**Worktree:** <absolute-path>` — the task worktree path.
|
|
129
|
-
- `cwd for every mutating command: <absolute-path>` — same as Worktree path; used by codex / gemini wrappers as `--add-dir` / `--include-directories`.
|
|
130
|
-
```
|
|
131
|
-
new:
|
|
132
|
-
```
|
|
133
|
-
For the **implementation phase** specifically, the dispatched prompt MUST also include:
|
|
134
|
-
|
|
135
|
-
- `**Worktree:** <absolute-path>` — the task worktree path.
|
|
136
|
-
- `cwd for every mutating command: <absolute-path>` — same as Worktree path; used by codex / gemini wrappers as `--add-dir` / `--include-directories`.
|
|
137
|
-
|
|
138
|
-
For the **final-verification phase** specifically, the dispatched prompt MUST also include the verification target snapshot so every analyser verifies the SAME target the lead captured at the entry gate:
|
|
139
|
-
|
|
140
|
-
- `**Worktree:** <absolute-path>` — the checkout under verification (read-only).
|
|
141
|
-
- `**Verification base ref:** <base-ref>` — the implementation base for the diff.
|
|
142
|
-
- `**Verification head SHA:** <sha>` — head SHA captured at run start.
|
|
143
|
-
- `**Verification diff stat:** <git diff --stat output>` — the captured diff-stat that bounds the verification scope.
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
- [ ] **Step 2 (profile deliverable, final-verification.md "Source Implementation Report" deliverable 28행 근처):** 워커가 이 snapshot 을 기준으로 검증하고 보고서가 cite 하도록, deliverable 의 Source Implementation Report 항목에 한 줄 추가:
|
|
147
|
-
|
|
148
|
-
append: ` The lead injects this same target snapshot into every analyser prompt (`**Worktree:** / **Verification base ref:** / **Verification head SHA:** / **Verification diff stat:**`); a worker that cannot confirm its analysis ran against that exact head MUST record a `tool-failure` rather than verify an ambiguous target.`
|
|
149
|
-
|
|
150
|
-
- [ ] **Step 3:** `npm run build && bash validators/validate-workflow.sh` → OK. commit `feat(worker-preamble,final-verification): 워커 dispatch 에 verification target snapshot 전달`.
|
|
151
|
-
|
|
152
|
-
## Task 5: 입력 템플릿에 Requirement Coverage Source 추가
|
|
153
|
-
|
|
154
|
-
**Files:** Modify `templates/reports/final-verification-input.template.md` (`## Source Implementation Report` 다음)
|
|
155
|
-
|
|
156
|
-
- [ ] **Step 1:** `## Source Implementation Report` 블록 종료(40행 인용구) 다음에 신규 섹션 삽입.
|
|
157
|
-
|
|
158
|
-
```markdown
|
|
159
|
-
|
|
160
|
-
## Requirement Coverage Source
|
|
161
|
-
|
|
162
|
-
- Approved implementation-planning report path:
|
|
163
|
-
- Requirement source used for coverage (plan section / brief Acceptance Criteria):
|
|
164
|
-
- Requirement IDs / acceptance IDs to verify:
|
|
165
|
-
- Requirements intentionally excluded from this verification:
|
|
166
|
-
|
|
167
|
-
> final-verification 은 위 source 의 각 requirement / acceptance id 마다 Validation Evidence 에 artifact 를 cite 해야 한다. source 가 비면 brief 의 `## Acceptance Criteria` 를 기본 source 로 사용한다.
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
- [ ] **Step 2:** 입력 템플릿의 analyser 질문 목록(85행 근처) 맨 앞에 target-integrity 질문 2개 추가:
|
|
171
|
-
|
|
172
|
-
```markdown
|
|
173
|
-
1. Does the verification target (head SHA / diff stat) match the implementation report's commit list and diff summary?
|
|
174
|
-
2. For each requirement / acceptance criterion, what exact artifact (commit SHA, test output, log line, config value) proves coverage?
|
|
175
|
-
```
|
|
176
|
-
(기존 번호 질문들은 뒤로 밀린다.)
|
|
177
|
-
|
|
178
|
-
- [ ] **Step 3:** `npm run build`. 렌더 검증: `python3 -m pytest tests/test_template_full_render_both_langs.py -q` → PASS. commit `feat(final-verification-input): Requirement Coverage Source + target-integrity 질문`.
|
|
179
|
-
|
|
180
|
-
## Task 6: PR1 검증 + PR
|
|
181
|
-
|
|
182
|
-
- [ ] **Step 1:** `python3 -m pytest tests/ -q` → 전부 PASS(또는 tmux skip). `bash validators/validate-workflow.sh` → OK. `node bin/okstra --version`.
|
|
183
|
-
- [ ] **Step 2:** diff critique — 새 토큰 grep(`grep -rn "Verification base ref\|Requirement Coverage Source\|No source-mutation audit" prompts/ templates/`), runtime parity.
|
|
184
|
-
- [ ] **Step 3:** push + `gh pr create --base main` (제목 `feat(final-verification): 검증 프로토콜 강화 — 초점/target snapshot/입력 (PR1)`).
|
|
185
|
-
|
|
186
|
-
---
|
|
187
|
-
|
|
188
|
-
# PR2 — report contract (schema / template / i18n / validator)
|
|
189
|
-
|
|
190
|
-
> PR1 머지 후 `main` 기준 새 브랜치에서 진행. breaking schema 변경(pre-1.0, compat 불필요).
|
|
191
|
-
|
|
192
|
-
## Task 7: schema — sourceImplementationReport diff-stat 분리
|
|
193
|
-
|
|
194
|
-
**Files:** Modify `schemas/final-report-v1.0.schema.json` (`sourceImplementationReport`, 현 ~547행)
|
|
195
|
-
|
|
196
|
-
- [ ] **Step 1 (test first):** schema 검증 테스트 추가 — diff-stat/diffSummaryQuote 누락 시 invalid. (해당 schema 검증 테스트 파일은 `tests/test_validate_run*.py` 또는 schema 단위 테스트; 실행 시 위치 확인 후 케이스 추가.)
|
|
197
|
-
- [ ] **Step 2:** `sourceImplementationReport` 를 교체:
|
|
198
|
-
|
|
199
|
-
```json
|
|
200
|
-
"sourceImplementationReport": {
|
|
201
|
-
"type": "object",
|
|
202
|
-
"required": ["path", "commitListQuote", "diffSummaryQuote", "worktreePath", "implementationBaseRef", "capturedHeadSha", "gitStatusShort", "gitDiffStat"],
|
|
203
|
-
"additionalProperties": false,
|
|
204
|
-
"properties": {
|
|
205
|
-
"path": { "type": "string" },
|
|
206
|
-
"commitListQuote": { "type": "string" },
|
|
207
|
-
"diffSummaryQuote": { "type": "string" },
|
|
208
|
-
"worktreePath": { "type": "string" },
|
|
209
|
-
"implementationBaseRef": { "type": "string" },
|
|
210
|
-
"capturedHeadSha": { "type": "string" },
|
|
211
|
-
"gitStatusShort": { "type": "string" },
|
|
212
|
-
"gitDiffStat": { "type": "string" }
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
```
|
|
216
|
-
(주의: 기존 `baseHeadSha` → `implementationBaseRef` + `capturedHeadSha` 분리. template/i18n/fixture 동반 수정 필요 — Task 10/11.)
|
|
217
|
-
|
|
218
|
-
- [ ] **Step 3:** schema 테스트 PASS. commit.
|
|
219
|
-
|
|
220
|
-
## Task 8: schema — conditionalAcceptanceConditions
|
|
221
|
-
|
|
222
|
-
**Files:** Modify `schemas/final-report-v1.0.schema.json` (`finalVerdict` + `$defs`)
|
|
223
|
-
|
|
224
|
-
- [ ] **Step 1 (test first):** verdict=`conditional-accept` 인데 conditions 비면 invalid 케이스.
|
|
225
|
-
- [ ] **Step 2:** `finalVerdict.properties` 에 추가 + `$defs` 에 row 정의:
|
|
226
|
-
|
|
227
|
-
```json
|
|
228
|
-
"conditionalAcceptanceConditions": {
|
|
229
|
-
"type": "array",
|
|
230
|
-
"items": { "$ref": "#/$defs/ConditionalAcceptanceConditionRow" }
|
|
231
|
-
}
|
|
232
|
-
```
|
|
233
|
-
```json
|
|
234
|
-
"ConditionalAcceptanceConditionRow": {
|
|
235
|
-
"type": "object",
|
|
236
|
-
"required": ["id", "condition", "evidenceRequired", "blocksReleaseHandoff"],
|
|
237
|
-
"additionalProperties": false,
|
|
238
|
-
"properties": {
|
|
239
|
-
"id": { "type": "string", "pattern": "^CA-\\d{3,}$" },
|
|
240
|
-
"condition": { "type": "string", "minLength": 1 },
|
|
241
|
-
"evidenceRequired": { "type": "string", "minLength": 1 },
|
|
242
|
-
"blocksReleaseHandoff": { "type": "boolean" }
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
```
|
|
246
|
-
(`finalVerdict.required` 에는 넣지 않음 — accepted/blocked 에선 빈 배열 허용; 강제는 validator 에서 verdict 조건부로.)
|
|
247
|
-
|
|
248
|
-
- [ ] **Step 3:** 테스트 PASS. commit.
|
|
249
|
-
|
|
250
|
-
## Task 9: schema — ReadonlyCommandRow status / nullable exitCode
|
|
251
|
-
|
|
252
|
-
**Files:** Modify `schemas/final-report-v1.0.schema.json` (`ReadonlyCommandRow`, 현 ~1306행)
|
|
253
|
-
|
|
254
|
-
- [ ] **Step 1 (test first):** status=`rejected`, exitCode=null 인 row 가 valid 케이스 + status=`executed` 인데 exitCode=null 이면 invalid(아래 Step 2 의 조건).
|
|
255
|
-
- [ ] **Step 2:** `ReadonlyCommandRow` 교체:
|
|
256
|
-
|
|
257
|
-
```json
|
|
258
|
-
"ReadonlyCommandRow": {
|
|
259
|
-
"type": "object",
|
|
260
|
-
"required": ["number", "tier", "command", "status", "exitCode", "outputTail"],
|
|
261
|
-
"additionalProperties": false,
|
|
262
|
-
"properties": {
|
|
263
|
-
"number": { "type": "integer", "minimum": 1 },
|
|
264
|
-
"tier": { "enum": [1, 2] },
|
|
265
|
-
"command": { "type": "string", "minLength": 1 },
|
|
266
|
-
"status": { "enum": ["executed", "rejected", "not-configured"] },
|
|
267
|
-
"exitCode": { "type": ["integer", "null"] },
|
|
268
|
-
"rejectionReason": { "type": ["string", "null"] },
|
|
269
|
-
"outputTail": { "type": "string" }
|
|
270
|
-
},
|
|
271
|
-
"allOf": [
|
|
272
|
-
{ "if": { "properties": { "status": { "const": "executed" } } },
|
|
273
|
-
"then": { "properties": { "exitCode": { "type": "integer" } } } },
|
|
274
|
-
{ "if": { "properties": { "status": { "const": "rejected" } } },
|
|
275
|
-
"then": { "required": ["rejectionReason"] } }
|
|
276
|
-
]
|
|
277
|
-
}
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
- [ ] **Step 3:** 테스트 PASS. commit.
|
|
281
|
-
|
|
282
|
-
## Task 10: template §4.8 — 새 필드 렌더
|
|
283
|
-
|
|
284
|
-
**Files:** Modify `templates/reports/final-report.template.md` (§4.8.1, + 신규 conditions 섹션, Read-only Command Log)
|
|
285
|
-
|
|
286
|
-
- [ ] **Step 1:** §4.8.1 Source Implementation Report 렌더에 diffSummaryQuote / implementationBaseRef / gitDiffStat 추가, baseHeadSha → capturedHeadSha 로 변경 (i18n 키는 Task 11).
|
|
287
|
-
- [ ] **Step 2:** §4.8.x `Conditional Acceptance Conditions` 섹션 추가 — verdict=`conditional-accept` 일 때 행 렌더, 아니면 `- Not applicable (verdict is not conditional-accept).`.
|
|
288
|
-
- [ ] **Step 3:** Read-only Command Log 렌더에 `status` 열 + rejected 행의 `rejectionReason`, exitCode null 처리.
|
|
289
|
-
- [ ] **Step 4:** `npm run build`. `python3 -m pytest tests/test_template_full_render_both_langs.py tests/test_render_phase_blocks.py -q` → PASS(또는 fixture 갱신 후). commit.
|
|
290
|
-
|
|
291
|
-
## Task 11: i18n 키 + golden fixture
|
|
292
|
-
|
|
293
|
-
**Files:** Modify `templates/reports/i18n/en.json`, `ko.json`, `tests/fixtures/reports/golden-final-verification.md`, `tests/fixtures/final-report-data/final-verification-001.data.json`
|
|
294
|
-
|
|
295
|
-
- [ ] **Step 1:** `en.json` + `ko.json` 의 `evidenceMeta` 에 키 추가: `diffSummaryAtRunStart`, `implementationBaseRef`, `gitDiffStatAtRunStart` (+ conditions/command-status 라벨). 기존 `capturedHeadBaseSha` → `capturedHeadSha` 의미로 정리.
|
|
296
|
-
- [ ] **Step 2:** golden data.json 에 새 필드 채우고, golden md 를 새 렌더 결과로 갱신 (`npm run build` 후 렌더러로 재생성하거나 수동 갱신).
|
|
297
|
-
- [ ] **Step 3:** `python3 -m pytest tests/test_template_full_render_both_langs.py tests/test_report_views.py -q` → PASS. commit.
|
|
298
|
-
|
|
299
|
-
## Task 12: validator — verdict↔blocker/condition/routing 일관성 강제
|
|
300
|
-
|
|
301
|
-
**Files:** Modify `validators/validate-run.py` (final-verification 블록 ~1172), `tests/test_validate_run*.py`
|
|
302
|
-
|
|
303
|
-
- [ ] **Step 1 (test first):** 4개 회귀 테스트 추가:
|
|
304
|
-
- verdict=`accepted` + acceptanceBlockers 비어있지 않음 → fail
|
|
305
|
-
- verdict=`blocked` + acceptanceBlockers 0개 → fail
|
|
306
|
-
- verdict=`conditional-accept` + conditions 0개 → fail
|
|
307
|
-
- routingRecommendation 이 `release-handoff` 인데 verdict ≠ `accepted` → fail
|
|
308
|
-
- [ ] **Step 2:** `if task_type == "final-verification":` 블록(1172)에 위 4개 검사 추가. 신규 §4.8 섹션 추가했으면 `FINAL_VERIFICATION_REQUIRED_SECTIONS`(876)에 `"Conditional Acceptance Conditions"` 등 반영.
|
|
309
|
-
- [ ] **Step 3:** `python3 -m pytest tests/test_validate_run.py -q` → PASS. commit.
|
|
310
|
-
|
|
311
|
-
## Task 13: PR2 검증 + docs + PR
|
|
312
|
-
|
|
313
|
-
- [ ] **Step 1:** `python3 -m pytest tests/ -q`, `bash validators/validate-workflow.sh`, golden 렌더 테스트 전부 PASS.
|
|
314
|
-
- [ ] **Step 2:** `CHANGES.md` 에 사용자 영향 엔트리(verdict 일관성 강제 + diff-stat/conditions/command-status 구조화).
|
|
315
|
-
- [ ] **Step 3:** diff critique(rule #5) — schema↔template↔i18n↔fixture↔validator 5자 정합, 새 식별자 grep.
|
|
316
|
-
- [ ] **Step 4:** push + `gh pr create --base main` (`feat(final-verification): report contract 구조화 — diff-stat/conditions/command-status + verdict 강제 (PR2)`).
|
|
317
|
-
|
|
318
|
-
---
|
|
319
|
-
|
|
320
|
-
## Self-Review (작성자 체크)
|
|
321
|
-
|
|
322
|
-
- **Spec coverage:** 다른 에이전트 8개 항목 매핑 — #1 target snapshot=Task4, #2 diff-stat=Task7/10/11, #3 requirement source=Task5, #4 no-mutation=Task2, #5 conditions=Task3/8/10/12, #6 command status=Task9/10/12, #7 routing=Task3, #8 section-name=Task3. + 검증 초점 재설계=Task1.
|
|
323
|
-
- **범위 밖 명시:** material.py 중복(cross-cutting)은 별도 — spawn 권장.
|
|
324
|
-
- **Placeholder:** schema/profile/preamble/input 은 완전한 텍스트 포함. template/i18n/fixture(Task10/11)는 정확한 위치·키를 지정하되, 렌더 결과 golden md 는 빌드로 재생성하는 절차로 둠(수작업 전체 전사 비현실적).
|
|
325
|
-
- **enforcement 정직성:** 검증 초점(Task1)·no-mutation(Task2)·target snapshot(Task4)은 선언 레벨(런타임 강제 없음). verdict↔blocker/condition/routing(Task12)·schema 필드(Task7-9)는 validator/schema 가 런타임 강제.
|
|
326
|
-
- **의존성:** Task3 Step3(conditional 참조)는 PR2 의 conditions 와 짝 — PR1 단독이면 보류.
|
|
@@ -1,337 +0,0 @@
|
|
|
1
|
-
# okstra-run 브랜치 결정 확인 단계 구현 계획
|
|
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:** okstra-run wizard 의 최종 confirm 직전에 "새 worktree+브랜치 생성 vs 현재 worktree 재사용" 을 명시 확인하는 전용 `branch_confirm` 단계를 추가한다(동작 변경 없음, 확인 게이트만).
|
|
6
|
-
|
|
7
|
-
**Architecture:** `worktree.py` 의 provisioning 결정 로직을 부수효과 없는 `preview_worktree_decision()` 으로 추출하고 `provision_task_worktree` 가 이를 호출하게 리팩터한다(미리보기=실제 보장). wizard 에 predicate-driven `branch_confirm` Step 을 추가해 그 헬퍼로 결정을 미리보고 picker 로 확인받는다. 강제는 state 전이 구조(`confirm` 도달 전 `branch_confirm` 필수).
|
|
8
|
-
|
|
9
|
-
**Tech Stack:** Python 3 (pytest), wizard prompts JSON(`prompts/wizard/prompts.ko.json`).
|
|
10
|
-
|
|
11
|
-
설계 근거: [docs/superpowers/specs/2026-06-02-okstra-run-branch-confirm-step-design.md](../specs/2026-06-02-okstra-run-branch-confirm-step-design.md)
|
|
12
|
-
|
|
13
|
-
핵심 사실(검증됨):
|
|
14
|
-
- okstra-run 스킬은 `--work-category` 를 넘기지 않으므로 wizard 경로의 work_category 는 `""` → 실제 브랜치는 `task-<task-id>` (`_work_category_prefix("")=="task"`). 미리보기도 `work_category=""` 로 동일 계산.
|
|
15
|
-
- wizard 는 predicate-driven: 각 `Step.applies(state)` 가 참인 첫 미답 Step 이 다음 단계. prompt 텍스트는 `prompts/wizard/prompts.ko.json` 의 `steps.<id>`.
|
|
16
|
-
- provision 결정 4갈래: not-git(`skipped-not-git`) / in-worktree(`skipped-in-worktree`) / registry active(`reused`) / 신규(`created`).
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
## File Structure
|
|
21
|
-
|
|
22
|
-
- `scripts/okstra_ctl/worktree.py` — `WorktreeDecision` dataclass + `preview_worktree_decision()` 추출, `provision_task_worktree` 가 이를 사용하도록 리팩터.
|
|
23
|
-
- `scripts/okstra_ctl/wizard.py` — `S_BRANCH_CONFIRM` 상수, `WizardState.branch_confirmed`, `_build_branch_confirm`/`_submit_branch_confirm`, STEPS 항목, `_ready_for_confirm` 갱신.
|
|
24
|
-
- `prompts/wizard/prompts.ko.json` — `steps.branch_confirm` 텍스트.
|
|
25
|
-
- `docs/kr/architecture.md`, `CHANGES.md` — 새 단계 / 사용자 영향.
|
|
26
|
-
- tests: `tests/test_okstra_worktree.py`, `tests/test_okstra_ctl_wizard.py`, `tests/test_wizard_prompts.py`.
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## Task 1: preview_worktree_decision 추출 + provision 리팩터
|
|
31
|
-
|
|
32
|
-
**Files:**
|
|
33
|
-
- Modify: `scripts/okstra_ctl/worktree.py`
|
|
34
|
-
- Test: `tests/test_okstra_worktree.py`
|
|
35
|
-
|
|
36
|
-
- [ ] **Step 1: 실패 테스트 작성** (`tests/test_okstra_worktree.py` 에 추가)
|
|
37
|
-
|
|
38
|
-
```python
|
|
39
|
-
def test_preview_decision_new_when_main_repo(tmp_path, monkeypatch):
|
|
40
|
-
import subprocess
|
|
41
|
-
from okstra_ctl.worktree import preview_worktree_decision
|
|
42
|
-
repo = tmp_path / "repo"; repo.mkdir()
|
|
43
|
-
subprocess.run(["git", "init", "-q"], cwd=repo, check=True)
|
|
44
|
-
monkeypatch.setenv("OKSTRA_HOME", str(tmp_path / "home"))
|
|
45
|
-
d = preview_worktree_decision(
|
|
46
|
-
project_root=repo, project_id="proj", task_group_segment="grp",
|
|
47
|
-
task_id_segment="dev-1", work_category="", base_ref="main",
|
|
48
|
-
)
|
|
49
|
-
assert d.status == "new"
|
|
50
|
-
assert d.branch == "task-dev-1"
|
|
51
|
-
assert d.base_ref == "main"
|
|
52
|
-
assert d.worktree_path.endswith("/proj/grp/dev-1")
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def test_preview_decision_not_git(tmp_path):
|
|
56
|
-
from okstra_ctl.worktree import preview_worktree_decision
|
|
57
|
-
d = preview_worktree_decision(
|
|
58
|
-
project_root=tmp_path, project_id="proj", task_group_segment="grp",
|
|
59
|
-
task_id_segment="dev-1", work_category="", base_ref="main",
|
|
60
|
-
)
|
|
61
|
-
assert d.status == "skipped-not-git"
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
- [ ] **Step 2: 실패 확인**
|
|
65
|
-
|
|
66
|
-
Run: `python3 -m pytest tests/test_okstra_worktree.py -k preview -q`
|
|
67
|
-
Expected: FAIL — `ImportError: cannot import name 'preview_worktree_decision'`
|
|
68
|
-
|
|
69
|
-
- [ ] **Step 3: WorktreeDecision + preview_worktree_decision 구현**
|
|
70
|
-
|
|
71
|
-
`worktree.py` 에 추가 (기존 `WorktreeProvision` dataclass 근처). decision 은 provision 의 4갈래를 부수효과 없이 계산한다. registry 재사용/in-worktree/not-git 분기는 기존 `provision_task_worktree` 의 가드(`_is_git_repo`, `_is_inside_non_main_worktree`, `worktree_registry.lookup`)를 그대로 호출(모두 read-only).
|
|
72
|
-
|
|
73
|
-
```python
|
|
74
|
-
from dataclasses import dataclass
|
|
75
|
-
|
|
76
|
-
@dataclass
|
|
77
|
-
class WorktreeDecision:
|
|
78
|
-
status: str # "new" | "reused" | "skipped-in-worktree" | "skipped-not-git"
|
|
79
|
-
path: str # worktree path (new: prospective; reuse: existing; skip: project_root)
|
|
80
|
-
branch: str = "" # new: prospective branch; reused: existing branch
|
|
81
|
-
base_ref: str = "" # new: requested base_ref; reused: existing base
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
def preview_worktree_decision(
|
|
85
|
-
*, project_root, project_id, task_group_segment, task_id_segment,
|
|
86
|
-
work_category, base_ref="",
|
|
87
|
-
) -> "WorktreeDecision":
|
|
88
|
-
"""Side-effect-free: what provision_task_worktree WOULD do, without touching disk.
|
|
89
|
-
|
|
90
|
-
Mirrors provision's decision branches exactly; reuses the same read-only
|
|
91
|
-
helpers so preview never diverges from the actual provisioning result.
|
|
92
|
-
"""
|
|
93
|
-
project_root = Path(project_root)
|
|
94
|
-
if not _is_git_repo(project_root):
|
|
95
|
-
return WorktreeDecision(status="skipped-not-git", path=str(project_root))
|
|
96
|
-
if _is_inside_non_main_worktree(project_root):
|
|
97
|
-
return WorktreeDecision(status="skipped-in-worktree", path=str(project_root))
|
|
98
|
-
safe_project = _safe_segment(project_id)
|
|
99
|
-
safe_group = _safe_segment(task_group_segment)
|
|
100
|
-
safe_task = _safe_segment(task_id_segment)
|
|
101
|
-
existing = worktree_registry.lookup(safe_project, safe_group, safe_task)
|
|
102
|
-
if existing is not None and existing.status == "active":
|
|
103
|
-
return WorktreeDecision(
|
|
104
|
-
status="reused", path=existing.worktree_path,
|
|
105
|
-
branch=existing.branch, base_ref=existing.base_ref,
|
|
106
|
-
)
|
|
107
|
-
return WorktreeDecision(
|
|
108
|
-
status="new",
|
|
109
|
-
path=str(compute_worktree_path(
|
|
110
|
-
project_id=safe_project, task_group_segment=safe_group,
|
|
111
|
-
task_id_segment=safe_task)),
|
|
112
|
-
branch=compute_branch_name(work_category=work_category, task_id_segment=safe_task),
|
|
113
|
-
base_ref=base_ref,
|
|
114
|
-
)
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
- [ ] **Step 4: provision_task_worktree 가 헬퍼를 쓰도록 리팩터**
|
|
118
|
-
|
|
119
|
-
`provision_task_worktree` 의 결정 분기(현재 not-git / in-worktree / registry-lookup 구간, 약 line 494-532)를 `decision = preview_worktree_decision(...)` 한 줄 호출로 교체하고, `decision.status` 로 분기:
|
|
120
|
-
- `skipped-not-git` → 기존 note 로 `WorktreeProvision(status="skipped-not-git", ...)` 반환.
|
|
121
|
-
- `skipped-in-worktree` → 기존 note 로 반환.
|
|
122
|
-
- `reused` → `worktree_registry.touch_phase(...)` + `_seed_worktree_settings_symlink(Path(decision.path))` 후 기존 reused note 로 반환.
|
|
123
|
-
- `new` → `decision.branch` / `decision.path` 를 사용해 기존 생성 로직(`git worktree add` + `worktree_registry.reserve` + seed) 그대로 수행, `status="created"` 반환.
|
|
124
|
-
|
|
125
|
-
핵심: 결정(분기 판정 + branch/path 계산)은 헬퍼가 단일 소스. provision 은 실행만.
|
|
126
|
-
|
|
127
|
-
- [ ] **Step 5: 통과 + 회귀 확인**
|
|
128
|
-
|
|
129
|
-
Run: `python3 -m pytest tests/test_okstra_worktree.py -q`
|
|
130
|
-
Expected: 신규 preview 테스트 통과 + 기존 worktree 테스트 전부 통과(회귀 0).
|
|
131
|
-
|
|
132
|
-
- [ ] **Step 6: 커밋**
|
|
133
|
-
|
|
134
|
-
```bash
|
|
135
|
-
git add scripts/okstra_ctl/worktree.py tests/test_okstra_worktree.py
|
|
136
|
-
git commit -m "refactor(worktree): preview_worktree_decision 추출 + provision 공유"
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
---
|
|
140
|
-
|
|
141
|
-
## Task 2: wizard branch_confirm 단계
|
|
142
|
-
|
|
143
|
-
**Files:**
|
|
144
|
-
- Modify: `scripts/okstra_ctl/wizard.py`
|
|
145
|
-
- Modify: `prompts/wizard/prompts.ko.json`
|
|
146
|
-
- Test: `tests/test_okstra_ctl_wizard.py`, `tests/test_wizard_prompts.py`
|
|
147
|
-
|
|
148
|
-
- [ ] **Step 1: 프롬프트 텍스트 추가** (`prompts/wizard/prompts.ko.json` 의 `steps` 객체에)
|
|
149
|
-
|
|
150
|
-
```json
|
|
151
|
-
"branch_confirm": {
|
|
152
|
-
"label": "{summary}",
|
|
153
|
-
"labels": {
|
|
154
|
-
"new": "새 브랜치 `{branch}` 를 base-ref `{base_ref}` 에서 새 worktree(`{path}`)에 생성합니다 — 진행할까요?",
|
|
155
|
-
"reuse": "현재 worktree(`{path}`, 브랜치 `{branch}`)를 재사용합니다 — 진행할까요?",
|
|
156
|
-
"in_worktree": "현재 worktree(`{path}`)에서 그대로 진행합니다(이미 non-main worktree) — 진행할까요?",
|
|
157
|
-
"not_git": "git 저장소가 아니므로 `{path}` 에서 직접 진행합니다 — 진행할까요?"
|
|
158
|
-
},
|
|
159
|
-
"options": { "proceed": "진행", "edit": "base-ref 다시 고르기" },
|
|
160
|
-
"echo_template": "branch-confirm: {value}"
|
|
161
|
-
}
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
- [ ] **Step 2: 실패 테스트 작성** — 핸들러 직접 테스트 (전체 wizard 구동 없이; 기존 파일의 `WizardState(...)` 직접 구성 + 핸들러 직접 호출 패턴을 따름. `_seed_wizard_prompts` 헬퍼는 파일 상단에 이미 있음)
|
|
165
|
-
|
|
166
|
-
```python
|
|
167
|
-
def test_build_branch_confirm_new_worktree(tmp_path, monkeypatch):
|
|
168
|
-
import subprocess
|
|
169
|
-
from okstra_ctl.wizard import WizardState, _build_branch_confirm, S_BRANCH_CONFIRM
|
|
170
|
-
repo = tmp_path / "repo"; repo.mkdir()
|
|
171
|
-
subprocess.run(["git", "init", "-q"], cwd=repo, check=True)
|
|
172
|
-
_seed_wizard_prompts(repo)
|
|
173
|
-
monkeypatch.setenv("OKSTRA_HOME", str(tmp_path / "home"))
|
|
174
|
-
state = WizardState(
|
|
175
|
-
workspace_root=str(repo), project_root=str(repo),
|
|
176
|
-
project_id="proj", task_group="grp", task_id="dev-1", base_ref="main",
|
|
177
|
-
)
|
|
178
|
-
p = _build_branch_confirm(state)
|
|
179
|
-
assert p.step == S_BRANCH_CONFIRM and p.kind == "pick"
|
|
180
|
-
assert "task-dev-1" in p.label and "main" in p.label
|
|
181
|
-
vals = [o.value for o in p.options]
|
|
182
|
-
assert "proceed" in vals and "edit" in vals # new 모드 → edit 제공
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
def test_submit_branch_confirm_proceed_and_edit(tmp_path):
|
|
186
|
-
from okstra_ctl.wizard import WizardState, _submit_branch_confirm
|
|
187
|
-
state = WizardState(
|
|
188
|
-
workspace_root=str(tmp_path), project_root=str(tmp_path),
|
|
189
|
-
project_id="proj", task_group="grp", task_id="dev-1", base_ref="main",
|
|
190
|
-
)
|
|
191
|
-
assert _submit_branch_confirm(state, "proceed") is not None
|
|
192
|
-
assert state.branch_confirmed is True
|
|
193
|
-
state.branch_confirmed = True
|
|
194
|
-
_submit_branch_confirm(state, "edit")
|
|
195
|
-
assert state.branch_confirmed is None # edit → 재확인 위해 리셋
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
(전이 자체 — `branch_confirm → confirm` 순서 — 는 기존 confirm-도달 테스트를 갱신해 검증한다. Step 5 참조.)
|
|
199
|
-
|
|
200
|
-
- [ ] **Step 3: 실패 확인**
|
|
201
|
-
|
|
202
|
-
Run: `python3 -m pytest tests/test_okstra_ctl_wizard.py -k branch_confirm -q`
|
|
203
|
-
Expected: FAIL (S_BRANCH_CONFIRM 미정의 / 전이 없음).
|
|
204
|
-
|
|
205
|
-
- [ ] **Step 4: wizard 구현** (`scripts/okstra_ctl/wizard.py`)
|
|
206
|
-
|
|
207
|
-
1) 상수: `S_CONFIRM` 정의 부근에 `S_BRANCH_CONFIRM = "branch_confirm"`.
|
|
208
|
-
2) `WizardState` 에 필드 추가: `branch_confirmed: Optional[bool] = None`.
|
|
209
|
-
3) build/submit 핸들러 추가:
|
|
210
|
-
|
|
211
|
-
```python
|
|
212
|
-
def _build_branch_confirm(state: WizardState) -> Prompt:
|
|
213
|
-
from okstra_ctl.worktree import preview_worktree_decision
|
|
214
|
-
decision = preview_worktree_decision(
|
|
215
|
-
project_root=Path(state.project_root),
|
|
216
|
-
project_id=state.project_id,
|
|
217
|
-
task_group_segment=state.task_group,
|
|
218
|
-
task_id_segment=state.task_id,
|
|
219
|
-
work_category="", # okstra-run 경로는 --work-category 를 안 넘김
|
|
220
|
-
base_ref=state.base_ref,
|
|
221
|
-
)
|
|
222
|
-
key = {
|
|
223
|
-
"new": "new", "reused": "reuse",
|
|
224
|
-
"skipped-in-worktree": "in_worktree", "skipped-not-git": "not_git",
|
|
225
|
-
}[decision.status]
|
|
226
|
-
t = _p(state.workspace_root, "branch_confirm")
|
|
227
|
-
label = t["labels"][key].format(
|
|
228
|
-
branch=decision.branch or "(none)",
|
|
229
|
-
base_ref=decision.base_ref or "(HEAD)",
|
|
230
|
-
path=decision.path,
|
|
231
|
-
)
|
|
232
|
-
# new 모드에서만 Edit 제공; 그 외에는 Proceed 만.
|
|
233
|
-
opts = t["options"]
|
|
234
|
-
options = [_opt("proceed", opts["proceed"])]
|
|
235
|
-
if decision.status == "new":
|
|
236
|
-
options.append(_opt("edit", opts["edit"]))
|
|
237
|
-
return Prompt(step=S_BRANCH_CONFIRM, kind="pick", label=label,
|
|
238
|
-
options=options, echo_template=t["echo_template"])
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
def _submit_branch_confirm(state: WizardState, value: str) -> Optional[str]:
|
|
242
|
-
if value == "edit":
|
|
243
|
-
_reset_from(state, S_BASE_REF_PICK) # base-ref 재질문
|
|
244
|
-
state.branch_confirmed = None
|
|
245
|
-
return "branch-confirm: edit"
|
|
246
|
-
if value != "proceed":
|
|
247
|
-
raise WizardError(f"expected 'proceed' or 'edit', got: {value!r}")
|
|
248
|
-
state.branch_confirmed = True
|
|
249
|
-
return "branch-confirm: proceed"
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
4) STEPS 리스트에서 `Step(S_CONFIRM, ...)` **바로 앞**에 삽입:
|
|
253
|
-
|
|
254
|
-
```python
|
|
255
|
-
Step(S_BRANCH_CONFIRM,
|
|
256
|
-
applies=lambda s: _ready_for_confirm(s) and s.branch_confirmed is None,
|
|
257
|
-
build=_build_branch_confirm, submit=_submit_branch_confirm,
|
|
258
|
-
owns=("branch_confirmed",)),
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
5) `_ready_for_confirm` 가 confirm 전에 branch_confirm 을 강제하도록, `S_CONFIRM` 의 `applies` 를 `_ready_for_confirm(s) and s.branch_confirmed is True and s.confirmed is None` 로 변경.
|
|
262
|
-
|
|
263
|
-
> 주의: `applies` 술어가 `_ready_for_confirm(s)` 를 공유하므로, STEPS 리스트에서 `S_BRANCH_CONFIRM` 이 `S_CONFIRM` 보다 **앞에** 와야 branch_confirm 이 먼저 매칭된다(첫 매칭 우선). `_reset_from` 가 `branch_confirmed` 도 리셋 범위에 포함하는지 확인 — base-ref edit 시 branch_confirmed 가 다시 None 이어야 재계산된다(위 submit 에서 명시적으로 None 처리했으니 OK).
|
|
264
|
-
|
|
265
|
-
- [ ] **Step 5: 기존 confirm-도달 테스트 갱신 (필수 — 안 하면 회귀)**
|
|
266
|
-
|
|
267
|
-
`tests/test_okstra_ctl_wizard.py` 에서 `next_prompt(state).step == S_CONFIRM` 를 단언하는 기존 테스트들(현재 약 line 478, 519, 664, 685, 899 — `grep -n "== S_CONFIRM" tests/test_okstra_ctl_wizard.py` 로 전수 확인)은 이제 confirm **직전에 `S_BRANCH_CONFIRM` 이 먼저 나온다.** 각 지점을 다음 패턴으로 갱신:
|
|
268
|
-
|
|
269
|
-
```python
|
|
270
|
-
p = next_prompt(state)
|
|
271
|
-
assert p.step == S_BRANCH_CONFIRM # 새 게이트가 먼저
|
|
272
|
-
submit(state, "proceed")
|
|
273
|
-
assert next_prompt(state).step == S_CONFIRM
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
`S_BRANCH_CONFIRM` 을 테스트 상단 import 에 추가. 누락하면 해당 테스트들이 `S_BRANCH_CONFIRM != S_CONFIRM` 로 실패한다 — 전수 갱신할 것.
|
|
277
|
-
|
|
278
|
-
- [ ] **Step 6: 통과 + 회귀**
|
|
279
|
-
|
|
280
|
-
Run: `python3 -m pytest tests/test_okstra_ctl_wizard.py tests/test_wizard_prompts.py -q`
|
|
281
|
-
Expected: 신규 + 갱신된 기존 전부 통과. 이어서 `python3 -m pytest tests/ -q` 전체 회귀 0.
|
|
282
|
-
|
|
283
|
-
- [ ] **Step 7: 커밋**
|
|
284
|
-
|
|
285
|
-
```bash
|
|
286
|
-
git add scripts/okstra_ctl/wizard.py prompts/wizard/prompts.ko.json tests/test_okstra_ctl_wizard.py tests/test_wizard_prompts.py
|
|
287
|
-
git commit -m "feat(wizard): branch_confirm 단계 — 브랜치/worktree 결정 명시 확인"
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
---
|
|
291
|
-
|
|
292
|
-
## Task 3: okstra-run 스킬 안내 + 문서
|
|
293
|
-
|
|
294
|
-
**Files:**
|
|
295
|
-
- Modify: `skills/okstra-run/SKILL.md`
|
|
296
|
-
- Modify: `docs/kr/architecture.md`, `CHANGES.md`
|
|
297
|
-
|
|
298
|
-
- [ ] **Step 1: 스킬 1줄 안내** — `skills/okstra-run/SKILL.md` 의 pick 처리 설명 부근에, `branch_confirm` 도 일반 pick step 으로 그대로 렌더된다는 1줄 추가(별도 처리 불필요 명시). 기존 step 설명 형식을 따른다.
|
|
299
|
-
|
|
300
|
-
- [ ] **Step 2: architecture.md** — requirements-discovery fan-out 절 부근(또는 wizard/worktree 설명부)에 추가:
|
|
301
|
-
|
|
302
|
-
```markdown
|
|
303
|
-
#### branch_confirm (worktree 결정 확인)
|
|
304
|
-
|
|
305
|
-
okstra-run wizard 는 최종 confirm 직전에 `branch_confirm` 단계로 "새 브랜치/worktree 생성 vs
|
|
306
|
-
현재 worktree 재사용"을 명시 확인한다. 결정은 `worktree.preview_worktree_decision()`(부수효과 없음)
|
|
307
|
-
으로 미리보고, 같은 헬퍼를 `provision_task_worktree` 가 실행에 쓰므로 미리보기와 실제가 일치한다.
|
|
308
|
-
worktree 격리 동작 자체는 변경 없음(확인 게이트만).
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
- [ ] **Step 3: CHANGES.md** — `## 2026-06-02` 섹션에 추가:
|
|
312
|
-
|
|
313
|
-
```markdown
|
|
314
|
-
### feat(wizard): okstra-run 에 브랜치/worktree 결정 확인 단계 추가
|
|
315
|
-
|
|
316
|
-
- okstra-run wizard 가 최종 confirm 직전에 `branch_confirm` 단계를 띄워, 새 브랜치를 base-ref 에서
|
|
317
|
-
새 worktree 에 만드는지(또는 현재 worktree 재사용)를 명시 확인하게 함. auto mode 에서 base-ref 가
|
|
318
|
-
조용히 선택되어 의도치 않은 브랜치가 생기던 문제의 가시성을 높임. worktree 격리 동작은 변경 없음.
|
|
319
|
-
- 사용자 영향: 다음 release + `npx -y okstra@latest install` 후 적용. okstra-run 진행 시 브랜치 생성
|
|
320
|
-
여부를 확인하는 단계가 한 번 더 추가된다(full-auto 가 아닌 경우 실제로 멈춰 확인).
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
- [ ] **Step 4: 커밋**
|
|
324
|
-
|
|
325
|
-
```bash
|
|
326
|
-
git add skills/okstra-run/SKILL.md docs/kr/architecture.md CHANGES.md
|
|
327
|
-
git commit -m "docs(branch-confirm): 스킬 안내 + architecture + CHANGES"
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
---
|
|
331
|
-
|
|
332
|
-
## Task 4: 전체 회귀 + 빌드
|
|
333
|
-
|
|
334
|
-
- [ ] **Step 1:** `python3 -m pytest tests/ -q` → 전부 통과(회귀 0).
|
|
335
|
-
- [ ] **Step 2:** `npm run build` → 성공(runtime 동기화).
|
|
336
|
-
- [ ] **Step 3:** `node bin/okstra --version` → 버전 출력.
|
|
337
|
-
- [ ] **Step 4:** `git status --short` → clean 확인.
|