okstra 0.109.0 → 0.110.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 +1 -1
- package/README.md +1 -1
- package/docs/kr/architecture.md +3 -3
- package/docs/kr/cli.md +2 -2
- package/docs/project-structure-overview.md +3 -3
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/python/okstra_ctl/worktree.py +14 -13
package/README.kr.md
CHANGED
|
@@ -193,7 +193,7 @@ Claude Code 세션 밖에서 task 를 시작하려면:
|
|
|
193
193
|
|
|
194
194
|
0.8.0 이후 `main` 에 추가된 workflow 변경:
|
|
195
195
|
|
|
196
|
-
- **모든 task-type 격리 worktree 자동 provisioning** — prepare 단계에서 `okstra-ctl` 이 task-key 당 한 번 `git worktree add ~/.okstra/worktrees/<project-id>/<task-group-segment>/<task-id-segment>` 를 수행해 격리된 working tree 와 브랜치 `<work-category-
|
|
196
|
+
- **모든 task-type 격리 worktree 자동 provisioning** — prepare 단계에서 `okstra-ctl` 이 task-key 당 한 번 `git worktree add ~/.okstra/worktrees/<project-id>/<task-group-segment>/<task-id-segment>` 를 수행해 격리된 working tree 와 브랜치 `<work-category-namespace>/<task-id-segment>` (예: `feature/dev-9436`, `fix/dev-7311`) 를 만듭니다. base ref 는 사용자가 `--base-ref` 로 지정 (release-handoff PR base picker 와 동일한 메뉴: `main` / `dev` / `staging` / `preprod` / `prod` / 직접 입력). 첫 phase 에서는 필수이며, okstra-run skill 이 `AskUserQuestion` 으로 수집합니다 — 비대화형 호출자는 `--base-ref` 플래그를 직접 전달해야 prepare 가 통과합니다. 같은 task-key 의 후속 **비-`implementation`** phase(`requirements-discovery` → `error-analysis` → `implementation-planning` → `final-verification` → `release-handoff`)는 같은 path/branch를 재사용합니다. 반면 `implementation` run 은 **stage 격리** 로 동작합니다 — 각 run 이 자신의 `.../<task>/stage-<N>/` worktree(브랜치 `<work-category-namespace>/<task>-s<N>`)에서 한 stage 만 실행하므로, 독립(`depends-on (none)`) stage 를 별도 run 으로 **동시에 병렬 구현** 할 수 있습니다(트리 공유 없음). registry 는 task-key 와 **stage-key** 를 함께 flock 예약합니다. caller 가 이미 다른 worktree 안에 있거나 project_root 가 git repo 가 아니면 provisioning 은 skip 됩니다(stage 격리도 평면 경로로 degrade). 수동 cleanup: `git worktree remove <path>` → `git branch -D <branch>` + registry 항목 release/remove. 상세: [`docs/kr/architecture.md`](docs/kr/architecture.md) *Task type* 섹션, [`docs/kr/cli.md#--executor`](docs/kr/cli.md#--executor).
|
|
197
197
|
- **`release-handoff` lifecycle phase** — `final-verification` 이 `verdict=accepted` 를 반환한 직후에 실행되는 신규 phase. lead 가 Claude worker (drafter) 를 통해 commit message · PR body 후보를 만들고, `AskUserQuestion` 으로 사용자에게 (1) action (`commit only` / `commit + PR` / `skip`), (2) PR base branch (`staging` / `preprod` / `prod` / `main` / `dev` / 직접 입력), (3) message handling (`use as-is` / `edit then proceed` / `cancel`) 세 가지를 순서대로 묻습니다. 사용자가 메뉴로 선택한 git / gh 명령만 실행되고, force-push, base 브랜치 직접 push, hook bypass (`--no-verify`), release publish (`gh release`, `npm publish`, ...) 는 금지됩니다. 이 phase 에서는 소스 코드를 수정하지 않습니다. profile: [`prompts/profiles/release-handoff.md`](prompts/profiles/release-handoff.md).
|
|
198
198
|
- **PR 본문 템플릿 설정** (release-handoff) — PR 본문은 마크다운 템플릿에서 채워집니다. 해석 우선순위: 1회성 override (`--pr-template-path` 또는 okstra-run Step 6 prompt) → `<project_root>/.okstra/project.json` 의 `prTemplatePath` → `~/.okstra/config.json` 의 `prTemplatePath` → 스킬 디폴트 `~/.claude/skills/templates/prd/pr-body.template.md`. 템플릿 등록 명령: `okstra config set pr-template-path <path> [--scope project|global]` (project 스코프는 project root 기준 상대경로 허용, global 스코프는 절대경로 또는 `~/` 시작 경로만 허용). 현재 설정 확인: `okstra config get pr-template-path --scope all` 은 각 스코프 값 + 실제로 우승하는 경로(effective) 까지 보여줍니다. 디폴트 템플릿은 `## Summary` / `## Changes` / `## Test plan` / `## Linked issues` 4 섹션 + HTML 주석으로 lead 작성 가이드를 포함하며, PR 생성 직전에 lead 가 주석을 제거합니다.
|
|
199
199
|
- **프로파일 워커 로스터 검증** — `--workers <csv>` 와 okstra-run Step 6 의 워커 prompt 는 해당 프로파일의 `Required workers:` 블록에 선언된 워커 ID 만 허용합니다. 프로파일에 없는 워커 (예: `release-handoff` 에서 `codex` / `antigravity`) 를 요청하면 명확한 에러로 거절되고, 인터랙티브 prompt 도 프로파일이 실제로 받는 워커만 보여줍니다.
|
package/README.md
CHANGED
|
@@ -191,7 +191,7 @@ Notable flags added in 0.7.0 / 0.8.0:
|
|
|
191
191
|
|
|
192
192
|
Recent workflow additions (post-0.8.0, on `main`):
|
|
193
193
|
|
|
194
|
-
- **Isolated task worktree for every task-type** — prepare automatically runs `git worktree add ~/.okstra/worktrees/<project>/<group>/<task>/` on a fresh branch `<work-category-
|
|
194
|
+
- **Isolated task worktree for every task-type** — prepare automatically runs `git worktree add ~/.okstra/worktrees/<project>/<group>/<task>/` on a fresh branch `<work-category-namespace>/<task-id-segment>` (e.g. `feature/dev-9436`, `fix/dev-7311`) branched from the **user-chosen base ref** (`--base-ref`, mirroring the `release-handoff` PR-base picker: `main` / `dev` / `staging` / `preprod` / `prod` / any local ref) the first time a task-key is seen. `--base-ref` is required on first phase; the okstra-run skill collects it via `AskUserQuestion`, non-interactive callers must pass the flag explicitly. Every subsequent **non-`implementation`** phase of the same task-key (`requirements-discovery` → `error-analysis` → `implementation-planning` → `final-verification` → `release-handoff`) reuses the same path and branch, so phase N inherits the working-tree state phase N-1 left behind. `implementation` runs are **stage-isolated** instead — each run owns exactly one stage in its own `.../<task>/stage-<N>/` worktree on branch `<work-category-namespace>/<task>-s<N>`, so independent (`depends-on (none)`) stages can be implemented in parallel across simultaneous runs without sharing a tree. A global registry at `~/.okstra/worktrees/registry.json` (flock-guarded) reserves task-keys **and stage-keys** across concurrent runs; all path/branch segments are sanitised (`/`, `:`, etc. → `-`). The worktree is preserved after every run for follow-up phases, PR authoring, and rollback. Skip paths: when the caller is already inside another worktree or `project_root` is not a git repo, provisioning no-ops (stage isolation degrades to the flat path too). Manual cleanup: `git worktree remove <path>` → `git branch -D <branch>` plus releasing/removing the key from the registry. Details: [`docs/kr/architecture.md`](docs/kr/architecture.md) (*Task type* section) and [`docs/kr/cli.md#--executor`](docs/kr/cli.md#--executor).
|
|
195
195
|
- **`release-handoff` lifecycle phase** — runs after `final-verification` returns `verdict=accepted`. The lead drafts a commit message and PR body via a Claude worker, then prompts the user with `AskUserQuestion` for three choices: action (`commit only` / `commit + PR` / `skip`), PR base branch (`staging` / `preprod` / `prod` / `main` / `dev` / free-form), and message handling (`use as-is` / `edit then proceed` / `cancel`). Only user-selected mutating git/gh commands run. Force-push, base-branch direct push, hook bypass (`--no-verify`), and release publishing (`gh release`, `npm publish`, ...) are forbidden. Source code is not edited in this phase. Profile: [`prompts/profiles/release-handoff.md`](prompts/profiles/release-handoff.md).
|
|
196
196
|
- **Configurable PR body template** (release-handoff) — the PR body is filled from a markdown template chosen in priority order: per-run override (`--pr-template-path` or the okstra-run Step 6 prompt) → `<project_root>/.okstra/project.json` `prTemplatePath` → `~/.okstra/config.json` `prTemplatePath` → bundled skill default at `~/.claude/skills/templates/prd/pr-body.template.md`. Register a template with `okstra config set pr-template-path <path> [--scope project|global]` (project scope accepts paths relative to the project root; global scope requires absolute or `~/`-prefixed). `okstra config get pr-template-path --scope all` reports every scope plus the effective winner. The bundled default ships `## Summary` / `## Changes` / `## Test plan` / `## Linked issues` with HTML comment guidance that the lead strips before opening the PR.
|
|
197
197
|
- **Profile-roster worker validation** — `--workers <csv>` (and the okstra-run Step 6 worker prompt) are now restricted to the worker IDs declared by the chosen profile's `Required workers:` block. Asking for `codex` / `antigravity` on a profile that does not list them (e.g. `release-handoff`) is rejected with a clear error, and the interactive prompt only offers workers the profile actually accepts.
|
package/docs/kr/architecture.md
CHANGED
|
@@ -347,8 +347,8 @@ okstra phase 는 PRD / issue file 을 직접 쓰지 않습니다. 동등한 결
|
|
|
347
347
|
공통 제약:
|
|
348
348
|
|
|
349
349
|
- `implementation`을 제외한 모든 phase는 source code edit, build, migration, deployment, 그 밖의 state-mutating 명령을 금지합니다(`final-verification`은 read-only 테스트 명령만 허용). `implementation`은 승인된 plan의 파일 목록 안에서만 edit/commit이 허용되며, `git push`·publish·deploy·실제 migration·third-party write API는 여전히 금지됩니다.
|
|
350
|
-
- **모든 task-type 격리 worktree (BLOCKING)**: 모든 task-type 의 첫 번째 phase prepare 단계에서 `okstra-ctl` 이 자동으로 task-key 단위 `git worktree` 를 생성하고, 같은 task-key 의 이후 phase (`requirements-discovery` → `error-analysis` → `implementation-planning` → `implementation`) 는 동일한 worktree·브랜치를 재사용합니다. 위치는 `~/.okstra/worktrees/<project-id>/<task-group-segment>/<task-id-segment>/` (segment 의 `/`·`:` 등 특수문자는 `-` 로 정규화) 이고, 브랜치 이름은 `<work-category-
|
|
351
|
-
- **implementation stage 격리 worktree (동시 병렬)**: 위 task-key 단위 worktree 는 `requirements-discovery`~`implementation-planning` 의 모델입니다. `implementation` task 는 **stage 격리** 로 동작합니다 — **한 run = 한 stage**, 각 run 이 `.../<task-id-segment>/stage-<N>/` (브랜치 `<
|
|
350
|
+
- **모든 task-type 격리 worktree (BLOCKING)**: 모든 task-type 의 첫 번째 phase prepare 단계에서 `okstra-ctl` 이 자동으로 task-key 단위 `git worktree` 를 생성하고, 같은 task-key 의 이후 phase (`requirements-discovery` → `error-analysis` → `implementation-planning` → `implementation`) 는 동일한 worktree·브랜치를 재사용합니다. 위치는 `~/.okstra/worktrees/<project-id>/<task-group-segment>/<task-id-segment>/` (segment 의 `/`·`:` 등 특수문자는 `-` 로 정규화) 이고, 브랜치 이름은 `<work-category-namespace>/<task-id-segment>` (예: `feature/dev-9436`, `fix/dev-7311`) 입니다. 네임스페이스는 work_category 로 결정됩니다(`feature`·`improvement`→`feature/`, `bugfix`→`fix/`, `refactor`→`refactor/`, `ops`→`ops/`, 미지정→`task/`). base ref 는 첫 phase prepare 시점의 main worktree `HEAD`. `~/.okstra/worktrees/registry.json` (flock-guarded) 가 task-key → path/branch 매핑을 전역 관리해 동시 실행 시 path·branch 충돌을 방지합니다. configured sync dirs 는 main worktree 에서 symlink 로 연결되어 task checkout 사이의 filesystem continuity 를 제공합니다 (sync 대상 목록은 `project.json` 의 `worktreeSyncDirs` 또는 `OKSTRA_WORKTREE_SYNC_DIRS` 환경변수로 override 가능; 빈 배열이면 sync 비활성화). 이 sync 는 okstra context/write boundary 를 확장하지 않습니다. caller 가 이미 다른 worktree 안에 있거나 project_root 가 git repo 가 아니면 provisioning 은 skip 되고 executor 는 project_root 에서 그대로 작업합니다. worktree 는 run 종료 후 자동 삭제되지 않으며 후속 phase·PR 작성·rollback 검증의 권위 artefact 입니다. 수동 cleanup: `git -C <main-worktree> worktree remove <path>` → `git -C <main-worktree> branch -D <branch>` + registry 항목 삭제. 자세한 동작은 `prompts/profiles/implementation.md` 의 *Task worktree* 블록과 `prompts/lead/okstra-lead-contract.md` 의 *Task worktree (BLOCKING for every task-type)* 섹션 참고.
|
|
351
|
+
- **implementation stage 격리 worktree (동시 병렬)**: 위 task-key 단위 worktree 는 `requirements-discovery`~`implementation-planning` 의 모델입니다. `implementation` task 는 **stage 격리** 로 동작합니다 — **한 run = 한 stage**, 각 run 이 `.../<task-id-segment>/stage-<N>/` (브랜치 `<work-category-namespace>/<task-id-segment>-s<N>`) 격리 worktree 를 발급받습니다. registry 가 task-key 와 **stage-key** (`<task-key>#stage-<N>`) 를 함께 flock 예약하고, `_resolve_effective_stages` 가 `consumers.jsonl` 의 `started` + registry 예약 stage 를 ready 집합에서 제외하므로(점유 SSOT = registry), 사용자가 두 `implementation` run 을 동시에 띄우면 서로 다른 독립 stage 를 충돌 없이 진행합니다. base 결정: 독립 = 공통 anchor(첫 stage 진입 HEAD 고정), 단일 의존 = 선행 done commit, 다중 의존 = 선행이 모두 ancestor 인 task worktree HEAD(`git merge-base --is-ancestor`; 미머지 시 `PrepareError`). cost-aware-design 의 ready-set batch 는 stage 마다 격리 branch 가 필요해 의미를 잃으므로(같은 branch 에 두 stage-key reserve 시 branch-uniqueness 충돌) 폐기되었고, 순차 진행은 stage done 후 다음 run, 동시 진행은 별도 run 으로 — cost 등가. `--stage <auto|N>` 또는 wizard `stage_pick` 으로 stage 를 선택합니다. wizard `stage_pick` 은 각 stage 의 상태(`[완료]`/`[진행중]`/`[준비됨]`/`[대기]`)를 라벨에 표시하는 멀티선택이며, 선택분의 의존성 closure 를 Kahn 위상정렬(`stage_targets.order_stage_closure`)해 render-args 의 `chain-stages` CSV 로 내보냅니다. `okstra-run` SKILL 이 이 큐를 받아 의존성 순서대로 단일-stage run 을 N 회 순차 실행(무인 연쇄)하되, 각 stage 의 Phase 6 `done` 행을 확인한 뒤 다음으로 넘어갑니다. 이는 오케스트레이션 계층일 뿐이며 wizard·prepare 의 **한 run = 한 stage** 격리 불변은 그대로입니다. worktree 뿐 아니라 **run 산출물(report·state·worker-results·manifest)도 `runs/implementation/stage-<N>/` 로 stage 별 격리**되므로 동시 실행하는 두 stage 의 보고서·상태가 섞이지 않습니다. 반면 `consumers.jsonl` 과 worktree registry 는 stage 간 공유되는 조율 SSOT 라 task-type 루트(`runs/implementation/`)에 그대로 둡니다.
|
|
352
352
|
- **단일-stage final-verification 의 run 산출물 격리 (동시 병렬)**: 단독-stage `final-verification`(`--stage <N>`)도 implementation 과 동일하게 run 산출물을 `runs/final-verification/stage-<N>/` 하위에 격리하고(seq 도 stage 별 독립), 팀 이름에 `-fv-s<N>` 접미사를 붙입니다 — `-fv-` 구분자로 같은 stage 의 implementation 팀(`-s<N>`)과도, 전체-task 검증의 기본 이름과도 충돌하지 않습니다. 따라서 여러 stage 의 final-verification 을 동시에 띄워도 state·worker-results·보고서·팀이 섞이지 않습니다. worktree 는 새로 만들지 않고 해당 implementation stage worktree 를 registry 에서 read-only 로 재사용하며, 그래서 registry stage-key 예약도 하지 않습니다. `teamName` 라벨에 `-fv-s<N>` 접미사를 붙이는 것은 audit/표시용 구분일 뿐이며, 실제 팀은 세션별 implicit team(`session-<leadSid>`)이라 v2.1.178 이전의 `TeamCreate` 이름 충돌 hard-fail 은 더 이상 발생하지 않습니다. 전체-task 검증(stage 빈 값)은 기존 평면 `runs/final-verification/` 구조를 유지합니다.
|
|
353
353
|
- `implementation` 과 `release-handoff` 를 제외한 모든 phase 는 source code edit, build, migration, deployment, 그 밖의 state-mutating 명령을 금지합니다 (`final-verification` 은 read-only 테스트 명령만 허용). `implementation` 은 승인된 plan 의 파일 목록 안에서만 edit/commit 이 허용되며, `git push`·publish·deploy·실제 migration·third-party write API 는 여전히 금지됩니다. `release-handoff` 는 source code 자체는 수정하지 않고, 사용자가 메뉴로 선택한 commit / push / PR 명령만 실행합니다 (force push, base 브랜치 직접 push, hook bypass, release publish 는 여전히 금지).
|
|
354
354
|
- 사용자가 "다음 단계 진행해" 같은 표현을 보내도, 그 발화만으로 다음 phase가 자동 시작되지 않습니다. 다음 phase는 새 `okstra.sh` 실행으로만 시작합니다.
|
|
@@ -383,7 +383,7 @@ release-handoff 까지 완료된 task 의 산출물에서 버그가 발견되면
|
|
|
383
383
|
stage-group 의 상호작용 순서: **G1 base 선택 → G2 stage 확인(선택은 prepare 전에 끝남 — 재질문 없음) → assemble(수집 브랜치 생성 + 선택 stage 머지) → 충돌 프로브 → PR 초안 → push/PR**.
|
|
384
384
|
|
|
385
385
|
- 자격 판정의 SSOT 는 `consumers.jsonl` 의 두 행입니다 — `verified`(어떤 stage 가 단독-stage final-verification 에서 accepted 됨), `pr`(어떤 stage 들이 어느 PR 로 나갔는지). `verified` 인데 아직 `pr` 에 안 들어간 stage 가 자격 후보입니다.
|
|
386
|
-
- worktree registry 는 stage-group 점유를 `<task-key>#group-<id>` 키로 예약하고, 수집 브랜치 이름은 `<work-category-
|
|
386
|
+
- worktree registry 는 stage-group 점유를 `<task-key>#group-<id>` 키로 예약하고, 수집 브랜치 이름은 `<work-category-namespace>/<task-id-segment>-g2-3` (예: 선택한 stage 가 2·3 이면 `-g2-3`) 형태입니다.
|
|
387
387
|
- 강제 지점은 선언이 아니라 Python 모듈 `okstra_ctl.handoff` 입니다 (`okstra handoff <subcommand>`). 서브커맨드 4종: `eligible`(자격 stage 조회) / `assemble`(수집 브랜치 생성·머지) / `record-verified`(`verified` 행 기록) / `record-pr`(`pr` 행 기록). 수집 단계의 머지는 isolation spec 의 "okstra 자동 머지 없음" 비목표에 대한 명시적 예외입니다.
|
|
388
388
|
|
|
389
389
|
### improvement-discovery (sidetrack entry-point)
|
package/docs/kr/cli.md
CHANGED
|
@@ -398,8 +398,8 @@ fallback 기본값은 아래와 같습니다.
|
|
|
398
398
|
- Claude/Codex/Antigravity 세 verifier 는 executor provider 와 관계없이 항상 dispatch 됩니다. Executor 와 같은 provider 라도 별도 CLI 세션으로 verifier 가 호출되어 context 가 분리되므로 self-review 안전장치는 유지됩니다.
|
|
399
399
|
- 실제 파일 변경은 Codex/Antigravity 의 경우 각 CLI 의 auto-edit 모드 (예: `codex exec --sandbox workspace-write`) 를 통해 일어나며, Claude-side Edit/Write tool 을 거치지 않습니다. implementation phase 에서 worker 가 mutation 을 수행하는 위치는 다음 항목에서 설명하는 task worktree 이며, 양쪽 wrapper(`scripts/okstra-codex-exec.sh`, `scripts/okstra-antigravity-exec.sh`) 는 worktree 경로를 4번째 positional 인자로 받아 codex 는 `--add-dir`, antigravity 는 `--include-directories` 로 forward 합니다. 누락하면 codex `workspace-write` 샌드박스가 worktree 쓰기를 EPERM 으로 거부합니다.
|
|
400
400
|
- **Claude executor 의 cwd 처리**: Claude Bash tool 은 per-call cwd 인자를 받지 않고 lead session 의 cwd 를 상속하므로, cwd 에 민감한 toolchain (`cargo`, `npm`, `pnpm`, `bun`, `pytest`, `make`, `go` 등) 을 worktree 안에서 실행하려면 호출을 `cd {{EXECUTOR_WORKTREE_PATH}} && <cmd>` 로 prefix 해야 합니다. 단일 Bash 호출 안에서 `cd` 가 leading token 으로 남아야 Claude Code 의 permission auto-allow 가 정상 동작하므로 `bash -lc "..."` / `bash -c "..."` 로 감싸지 않습니다 (감싸면 `cd` 가 가려져 매 호출마다 permission prompt 가 발생). `git -C <path>`, `cargo --manifest-path`, `pytest --rootdir` 처럼 작업 디렉터리 플래그를 받는 도구는 `cd && ` chain 대신 해당 플래그를 우선 사용합니다. Edit/Write/Read tool 은 이미 절대경로를 사용하므로 별도 cwd 처리가 필요 없습니다. 이 규칙은 Claude executor 에만 적용되고 codex / antigravity executor 는 CLI wrapper 가 cwd 를 주입합니다.
|
|
401
|
-
- **Task worktree (모든 task-type 자동 격리)**: 모든 task-type 의 첫 번째 phase prepare 단계에서 `okstra-ctl` 이 `~/.okstra/worktrees/<project-id>/<task-group-segment>/<task-id-segment>/` 에 `git worktree` 를 생성하고, 브랜치 `<work-category-
|
|
402
|
-
- **implementation stage 격리 (동시 병렬)**: 위 task-key 단위 worktree 는 `requirements-discovery`~`implementation-planning` 에만 해당합니다. `implementation` task 의 각 run 은 **stage 별 격리 worktree** (`~/.okstra/worktrees/<project-id>/<task-group-segment>/<task-id-segment>/stage-<N>/`, 브랜치 `<work-category-
|
|
401
|
+
- **Task worktree (모든 task-type 자동 격리)**: 모든 task-type 의 첫 번째 phase prepare 단계에서 `okstra-ctl` 이 `~/.okstra/worktrees/<project-id>/<task-group-segment>/<task-id-segment>/` 에 `git worktree` 를 생성하고, 브랜치 `<work-category-namespace>/<task-id-segment>` (예: `feature/dev-9436`, `fix/dev-7311`) 를 main worktree `HEAD` 에서 분기합니다. 같은 task-key 의 이후 phase 는 동일한 path/branch 를 재사용하므로 status 가 `reused` 로 기록됩니다 (run-prep 시점에 새 `git worktree add` 가 일어나지 않음). 모든 segment 의 `/`·`:` 등 특수문자는 `-` 로 정규화되며, `~/.okstra/worktrees/registry.json` 가 task-key → path/branch 매핑을 전역 관리합니다 (flock-guarded). Executor 의 Edit/Write/build/test/commit, verifier 의 read 는 모두 이 worktree 안에서 수행됩니다. caller 가 이미 다른 worktree 안에 있거나 project_root 가 git repo 가 아니면 provisioning 은 skip 되고 status 가 `skipped-in-worktree` / `skipped-not-git` 로 기록됩니다. 경로·브랜치 충돌은 `PrepareError` 로 즉시 실패시키며, run 종료 후 worktree 는 자동 삭제하지 않습니다 (수동: `git worktree remove` → `git branch -D` + registry 항목 삭제). **단, 아래 implementation stage 격리는 예외입니다.**
|
|
402
|
+
- **implementation stage 격리 (동시 병렬)**: 위 task-key 단위 worktree 는 `requirements-discovery`~`implementation-planning` 에만 해당합니다. `implementation` task 의 각 run 은 **stage 별 격리 worktree** (`~/.okstra/worktrees/<project-id>/<task-group-segment>/<task-id-segment>/stage-<N>/`, 브랜치 `<work-category-namespace>/<task-id-segment>-s<N>`)에서 실행됩니다. registry 가 stage-key (`<task-key>#stage-<N>`) 를 flock 으로 원자 예약하고, `_resolve_effective_stages` 가 `consumers.jsonl` 의 `started` 행 + registry 예약 stage 를 제외하며, stage 선택부터 worktree 생성·registry 예약까지가 task-key 단위 프로비저닝 mutex(`~/.okstra/.locks/worktree-provision/`) 한 임계구역 안에서 수행되므로, 두 `implementation` run 을 동시에 띄우면 서로 다른 ready stage 를 안전하게 잡습니다 (**한 run = 한 stage**). stage worktree 의 base 는 의존 종류로 결정됩니다 — 독립(`depends-on (none)`) = 공통 anchor(첫 stage 진입 시 task-key worktree HEAD 1회 고정), 단일 의존(`depends-on X`) = 선행 stage 의 done `head_commit`, 다중 의존(`depends-on X,Y…`) = 선행들이 모두 머지된 task worktree HEAD(`git merge-base --is-ancestor` 로 검증, 미머지 시 `PrepareError` 로 머지 안내). 실행할 stage 는 `--stage <auto|N>` (`okstra.sh`/`render-bundle` 공통) 또는 okstra-run wizard 의 `stage_pick` 단계로 지정합니다. `project_root` 가 git repo 가 아니거나 nested worktree 면 stage 격리도 평면 동작으로 degrade 합니다.
|
|
403
403
|
- **단일-stage final-verification 산출물 격리**: `--task-type final-verification --stage <N>` 은 해당 implementation stage worktree 를 registry 에서 read-only 로 재사용하면서, run 산출물은 `runs/final-verification/stage-<N>/` 하위에 stage 별로 격리하고 팀 이름에 `-fv-s<N>` 접미사를 붙입니다. 서로 다른 stage 의 final-verification 을 동시에 띄워도 state·worker-results·팀이 충돌하지 않습니다 (같은 stage 를 동시에 두 번 띄우는 것은 격리되지 않음 — TeamCreate 이름 충돌로 즉시 실패). 전체-task 검증(stage 빈 값)은 평면 `runs/final-verification/` 를 유지합니다.
|
|
404
404
|
|
|
405
405
|
예:
|
|
@@ -360,10 +360,10 @@ Non-`implementation` phases share one task-key worktree:
|
|
|
360
360
|
~/.okstra/worktrees/<project-id>/<task-group-segment>/<task-id-segment>/
|
|
361
361
|
```
|
|
362
362
|
|
|
363
|
-
Branch name:
|
|
363
|
+
Branch name (namespace by work_category — `feature`/`improvement` → `feature/`, `bugfix` → `fix/`, `refactor` → `refactor/`, `ops` → `ops/`, unset → `task/`):
|
|
364
364
|
|
|
365
365
|
```text
|
|
366
|
-
<work-category-
|
|
366
|
+
<work-category-namespace>/<task-id-segment>
|
|
367
367
|
```
|
|
368
368
|
|
|
369
369
|
That task-key worktree is reused for `requirements-discovery` through `implementation-planning`, and by whole-task verification / handoff flows after implementation stages have been integrated. `worktreeSyncDirs`, `worktreeSyncFiles`, and `worktreeSnapshotFiles` provide filesystem continuity only; they do not expand okstra's context/write boundary.
|
|
@@ -372,7 +372,7 @@ That task-key worktree is reused for `requirements-discovery` through `implement
|
|
|
372
372
|
|
|
373
373
|
```text
|
|
374
374
|
~/.okstra/worktrees/<project-id>/<task-group-segment>/<task-id-segment>/stage-<N>/
|
|
375
|
-
<work-category-
|
|
375
|
+
<work-category-namespace>/<task-id-segment>-s<N>
|
|
376
376
|
```
|
|
377
377
|
|
|
378
378
|
Single-stage `final-verification --stage <N>` reuses the matching implementation stage worktree read-only, while run artifacts are isolated under `runs/final-verification/stage-<N>/`. Whole-task final-verification keeps the flat `runs/final-verification/` shape.
|
package/package.json
CHANGED
package/runtime/BUILD.json
CHANGED
|
@@ -105,17 +105,16 @@ DEFAULT_WORKTREE_SYNC_FILES: tuple[str, ...] = (
|
|
|
105
105
|
DEFAULT_WORKTREE_SNAPSHOT_FILES: tuple[str, ...] = ()
|
|
106
106
|
|
|
107
107
|
|
|
108
|
-
# Work-category →
|
|
109
|
-
# `--work-category` (bugfix / feature / refactor / ops /
|
|
110
|
-
#
|
|
111
|
-
|
|
112
|
-
|
|
108
|
+
# Work-category → branch namespace (slash-prefixed). Mirrors the values
|
|
109
|
+
# accepted by `--work-category` (bugfix / feature / refactor / ops /
|
|
110
|
+
# improvement); `feature` and `improvement` share the `feature/` namespace,
|
|
111
|
+
# and any unset/unrecognised category falls back to `task/`.
|
|
112
|
+
_WORK_CATEGORY_NAMESPACE = {
|
|
113
|
+
"feature": "feature",
|
|
114
|
+
"improvement": "feature",
|
|
113
115
|
"bugfix": "fix",
|
|
114
116
|
"refactor": "refactor",
|
|
115
117
|
"ops": "ops",
|
|
116
|
-
"improvement": "improve",
|
|
117
|
-
"docs": "doc",
|
|
118
|
-
"doc": "doc",
|
|
119
118
|
}
|
|
120
119
|
|
|
121
120
|
|
|
@@ -241,9 +240,9 @@ def _safe_segment(value: str) -> str:
|
|
|
241
240
|
return _safe_fs_segment(value)
|
|
242
241
|
|
|
243
242
|
|
|
244
|
-
def
|
|
243
|
+
def _work_category_namespace(work_category: str) -> str:
|
|
245
244
|
key = (work_category or "").strip().lower()
|
|
246
|
-
return
|
|
245
|
+
return _WORK_CATEGORY_NAMESPACE.get(key, "task")
|
|
247
246
|
|
|
248
247
|
|
|
249
248
|
def _git(cwd: Path, *args: str) -> subprocess.CompletedProcess:
|
|
@@ -663,11 +662,13 @@ def compute_branch_name(
|
|
|
663
662
|
stage_number: Optional[int] = None,
|
|
664
663
|
group_id: Optional[str] = None,
|
|
665
664
|
) -> str:
|
|
666
|
-
"""One branch per task-key
|
|
667
|
-
implementation stage worktree.
|
|
665
|
+
"""One branch per task-key as `<namespace>/<task-id>`, or
|
|
666
|
+
`<namespace>/<task-id>-s<N>` for an implementation stage worktree. The
|
|
667
|
+
namespace is a controlled constant so its slash is preserved; only the
|
|
668
|
+
task-id segment is sanitised."""
|
|
668
669
|
if stage_number is not None and group_id is not None:
|
|
669
670
|
raise ValueError("stage_number and group_id are mutually exclusive")
|
|
670
|
-
name = f"{
|
|
671
|
+
name = f"{_work_category_namespace(work_category)}/{_safe_segment(task_id_segment)}"
|
|
671
672
|
if stage_number is not None:
|
|
672
673
|
name = f"{name}-s{stage_number}"
|
|
673
674
|
if group_id is not None:
|