okstra 0.101.1 → 0.102.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.kr.md +5 -5
  2. package/README.md +5 -5
  3. package/docs/for-ai/README.md +2 -3
  4. package/docs/for-ai/skills/{okstra-container.md → okstra-container-build.md} +3 -4
  5. package/docs/for-ai/skills/okstra-inspect.md +1 -2
  6. package/docs/kr/architecture/storage-model.md +1 -2
  7. package/docs/kr/architecture.md +6 -6
  8. package/docs/kr/cli.md +3 -3
  9. package/docs/kr/container.md +1 -1
  10. package/docs/project-structure-overview.md +5 -5
  11. package/docs/superpowers/plans/2026-06-15-internal-skill-resource-migration.md +1 -1
  12. package/docs/superpowers/plans/2026-06-24-cross-project-precondition.md +542 -0
  13. package/docs/superpowers/plans/2026-06-24-decision-drafts-render-gap.md +568 -0
  14. package/docs/superpowers/plans/2026-06-24-manual-user-test-section.md +203 -0
  15. package/docs/superpowers/plans/2026-06-24-okstra-container-build-rename.md +525 -0
  16. package/docs/superpowers/specs/2026-06-24-cross-project-precondition-design.md +129 -0
  17. package/docs/superpowers/specs/2026-06-24-decision-drafts-render-gap-design.md +185 -0
  18. package/docs/superpowers/specs/2026-06-24-manual-user-test-section-design.md +121 -0
  19. package/docs/superpowers/specs/2026-06-24-okstra-container-build-rename-design.md +110 -0
  20. package/package.json +1 -1
  21. package/runtime/BUILD.json +2 -2
  22. package/runtime/agents/workers/report-writer-worker.md +1 -0
  23. package/runtime/prompts/lead/report-writer.md +1 -1
  24. package/runtime/prompts/lead/team-contract.md +2 -2
  25. package/runtime/prompts/profiles/_implementation-deliverable.md +2 -0
  26. package/runtime/prompts/profiles/final-verification.md +4 -3
  27. package/runtime/prompts/profiles/implementation-planning.md +12 -9
  28. package/runtime/python/okstra_ctl/run.py +0 -1
  29. package/runtime/python/okstra_token_usage/paths.py +1 -2
  30. package/runtime/schemas/final-report-v1.0.schema.json +106 -3
  31. package/runtime/skills/{okstra-container → okstra-container-build}/SKILL.md +3 -3
  32. package/runtime/templates/reports/final-report.template.md +63 -2
  33. package/runtime/templates/reports/final-verification-input.template.md +3 -3
  34. package/runtime/templates/reports/i18n/en.json +28 -1
  35. package/runtime/templates/reports/i18n/ko.json +28 -1
  36. package/runtime/templates/worker-prompt-preamble.md +1 -1
  37. package/runtime/validators/validate-run.py +70 -1
  38. package/src/commands/lifecycle/install.mjs +17 -18
  39. package/src/commands/lifecycle/uninstall.mjs +8 -6
  40. package/src/lib/skill-catalog.mjs +10 -9
@@ -0,0 +1,525 @@
1
+ # okstra-container-build Rename 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:** Rename the public okstra container skill from `okstra-container` to `okstra-container-build` without changing the `okstra container` CLI or container runtime trace names.
6
+
7
+ **Architecture:** The public skill surface remains driven by `src/lib/skill-catalog.mjs` and `.claude-plugin/plugin.json`. Install copy/link mode reads skill directories by exact `USER_SKILL_NAMES`, so the source directory and frontmatter must move together. Upgrade cleanup uses an exact obsolete-name allowlist so old `/okstra-container` directories are pruned without wildcard deletion.
8
+
9
+ **Tech Stack:** Node.js ES modules, Python pytest contract tests, Markdown skill/docs sources, `tools/build.mjs` runtime sync.
10
+
11
+ ## Global Constraints
12
+
13
+ - Public skill name becomes exactly `okstra-container-build`.
14
+ - Old public skill name `okstra-container` is removed from installed skill manifests and pruned from agent skill homes.
15
+ - CLI command remains exactly `okstra container <up|status|logs|stop-watcher|down>`.
16
+ - Runtime tmux/docker trace prefix remains exactly `okstra-container-<slug>`.
17
+ - Do not wildcard-delete `okstra-*`; cleanup must use exact names only.
18
+ - Do not hand-edit `runtime/`; run `npm run build` after source edits.
19
+ - Preserve historical `CHANGES.md` / `CHANGELOG.md` entries except adding a new current entry.
20
+
21
+ ---
22
+
23
+ ## File Structure
24
+
25
+ - `skills/okstra-container-build/SKILL.md`: renamed public skill source. Keeps `okstra container ...` command examples.
26
+ - `src/lib/skill-catalog.mjs`: public/obsolete skill name SSOT.
27
+ - `.claude-plugin/plugin.json`: secondary skills channel manifest.
28
+ - `src/commands/lifecycle/install.mjs`: install copy/link exact-name prune path.
29
+ - `src/commands/lifecycle/uninstall.mjs`: legacy fallback cleanup names.
30
+ - `tests-js/skill-catalog.test.mjs`: catalog/plugin/obsolete-name contract.
31
+ - `tests-js/install-runtime.test.mjs`: install target manifest plus old skill prune regression.
32
+ - `tests-js/uninstall-runtime.test.mjs`: manifest-missing fallback cleanup regression.
33
+ - `tests/contract/test_docs_runtime_contract.py`: plugin manifest contract mirror.
34
+ - `README.md`, `README.kr.md`, `docs/kr/architecture.md`, `docs/project-structure-overview.md`, `docs/kr/container.md`: live user/internal docs.
35
+ - `docs/for-ai/README.md`, `docs/for-ai/skills/okstra-container-build.md`, `docs/for-ai/skills/okstra-inspect.md`: AI routing manuals.
36
+ - `prompts/profiles/_implementation-deliverable.md`, `prompts/profiles/final-verification.md`: live phase prompt references.
37
+ - `docs/superpowers/specs/2026-06-24-manual-user-test-section-design.md`, `docs/superpowers/plans/2026-06-24-manual-user-test-section.md`: active manual-test design/plan references.
38
+ - `CHANGES.md`: current user-visible change entry.
39
+
40
+ ### Task 1: Public Skill Contract Rename
41
+
42
+ **Files:**
43
+ - Move: `skills/okstra-container` -> `skills/okstra-container-build`
44
+ - Modify: `skills/okstra-container-build/SKILL.md`
45
+ - Modify: `src/lib/skill-catalog.mjs`
46
+ - Modify: `.claude-plugin/plugin.json`
47
+ - Modify: `src/commands/lifecycle/install.mjs`
48
+ - Modify: `tests-js/skill-catalog.test.mjs`
49
+ - Modify: `tests/contract/test_docs_runtime_contract.py`
50
+
51
+ **Interfaces:**
52
+ - Produces: `USER_SKILL_NAMES` contains `okstra-container-build`, not `okstra-container`.
53
+ - Produces: `OBSOLETE_SKILL_NAMES` contains old `okstra-container`.
54
+ - Produces: plugin manifest entry `./skills/okstra-container-build`.
55
+
56
+ - [ ] **Step 1: Write failing catalog contract tests**
57
+
58
+ Update `tests-js/skill-catalog.test.mjs` import and tests to this shape:
59
+
60
+ ```js
61
+ import assert from "node:assert/strict";
62
+ import { readFileSync } from "node:fs";
63
+ import test from "node:test";
64
+
65
+ import {
66
+ OBSOLETE_SKILL_NAMES,
67
+ USER_SKILL_NAMES,
68
+ } from "../src/lib/skill-catalog.mjs";
69
+
70
+ function readJson(path) {
71
+ return JSON.parse(readFileSync(path, "utf8"));
72
+ }
73
+
74
+ test("public skill catalog matches Claude plugin manifest", () => {
75
+ const plugin = readJson(".claude-plugin/plugin.json");
76
+ const pluginNames = plugin.skills.map((entry) => entry.replace("./skills/", ""));
77
+ assert.deepEqual(pluginNames, [...USER_SKILL_NAMES]);
78
+ });
79
+
80
+ test("obsolete skill names do not overlap public skills", () => {
81
+ for (const name of OBSOLETE_SKILL_NAMES) {
82
+ assert.equal(USER_SKILL_NAMES.includes(name), false, name);
83
+ }
84
+ });
85
+
86
+ test("container skill rename keeps old public name prunable", () => {
87
+ assert.equal(USER_SKILL_NAMES.includes("okstra-container-build"), true);
88
+ assert.equal(USER_SKILL_NAMES.includes("okstra-container"), false);
89
+ assert.equal(OBSOLETE_SKILL_NAMES.includes("okstra-container"), true);
90
+ });
91
+ ```
92
+
93
+ Update `tests/contract/test_docs_runtime_contract.py` public skill list:
94
+
95
+ ```python
96
+ USER_FACING_PLUGIN_SKILLS = [
97
+ "./skills/okstra-setup",
98
+ "./skills/okstra-brief",
99
+ "./skills/okstra-run",
100
+ "./skills/okstra-memory",
101
+ "./skills/okstra-inspect",
102
+ "./skills/okstra-schedule",
103
+ "./skills/okstra-container-build",
104
+ ]
105
+ ```
106
+
107
+ - [ ] **Step 2: Run failing contract tests**
108
+
109
+ Run:
110
+
111
+ ```bash
112
+ node --test tests-js/skill-catalog.test.mjs
113
+ python3 -m pytest tests/contract/test_docs_runtime_contract.py::test_plugin_manifest_exposes_only_user_facing_skills -q
114
+ ```
115
+
116
+ Expected: FAIL because `OBSOLETE_SKILL_NAMES` is not exported yet and `.claude-plugin/plugin.json` still lists `./skills/okstra-container`.
117
+
118
+ - [ ] **Step 3: Rename skill source and public catalog**
119
+
120
+ Run:
121
+
122
+ ```bash
123
+ git mv skills/okstra-container skills/okstra-container-build
124
+ ```
125
+
126
+ Edit `skills/okstra-container-build/SKILL.md` frontmatter/title:
127
+
128
+ ```markdown
129
+ ---
130
+ name: okstra-container-build
131
+ description: |
132
+ Use to bring up, inspect, or tear down the okstra user-test container runtime for an implementation task — the docker-compose group okstra deploys from a task's worktree so a human can poke at the running build. Trigger words include "okstra container", "okstra container up", "okstra container down", "컨테이너 띄워", "컨테이너 올려", "컨테이너 내려", "컨테이너 상태", "컨테이너 로그", "유저 테스트 환경", "user test environment", "docker compose 띄워줘", "이 task 컨테이너로 띄워", "watcher 멈춰", "stop watcher", "감시 종료".
133
+ ---
134
+
135
+ # OKSTRA Container Build
136
+ ```
137
+
138
+ Edit `src/lib/skill-catalog.mjs` public and obsolete exports:
139
+
140
+ ```js
141
+ export const USER_SKILL_NAMES = Object.freeze([
142
+ "okstra-setup",
143
+ "okstra-brief",
144
+ "okstra-run",
145
+ "okstra-memory",
146
+ "okstra-inspect",
147
+ "okstra-schedule",
148
+ "okstra-container-build",
149
+ ]);
150
+
151
+ // Names okstra used to install as skills before they were renamed or moved
152
+ // into the runtime resource tree. Install prunes these exact directories from
153
+ // each target skill home so upgrades do not leave stale slash commands behind.
154
+ // Exact-name only — never wildcard.
155
+ export const OBSOLETE_SKILL_NAMES = Object.freeze([
156
+ "okstra",
157
+ "okstra-context-loader",
158
+ "okstra-team-contract",
159
+ "okstra-convergence",
160
+ "okstra-report-writer",
161
+ "okstra-coding-preflight",
162
+ "okstra-container",
163
+ ]);
164
+
165
+ export function userSkillNames() {
166
+ return [...USER_SKILL_NAMES];
167
+ }
168
+
169
+ export function obsoleteSkillNames() {
170
+ return [...OBSOLETE_SKILL_NAMES];
171
+ }
172
+ ```
173
+
174
+ Edit `.claude-plugin/plugin.json`:
175
+
176
+ ```json
177
+ {
178
+ "name": "okstra",
179
+ "description": "Multi-agent cross-verification orchestrator (Claude lead + Codex/Antigravity workers).",
180
+ "skills": [
181
+ "./skills/okstra-setup",
182
+ "./skills/okstra-brief",
183
+ "./skills/okstra-run",
184
+ "./skills/okstra-memory",
185
+ "./skills/okstra-inspect",
186
+ "./skills/okstra-schedule",
187
+ "./skills/okstra-container-build"
188
+ ]
189
+ }
190
+ ```
191
+
192
+ Edit `src/commands/lifecycle/install.mjs` import and prune helper names:
193
+
194
+ ```js
195
+ import { OBSOLETE_SKILL_NAMES, USER_SKILL_NAMES } from "../../lib/skill-catalog.mjs";
196
+ ```
197
+
198
+ ```js
199
+ const pruned = await pruneObsoleteSkills(target, opts);
200
+ ```
201
+
202
+ ```js
203
+ // Remove former skill directories left by older installs. Exact-name only
204
+ // (OBSOLETE_SKILL_NAMES) — never wildcard-delete okstra-*.
205
+ async function pruneObsoleteSkills(target, opts) {
206
+ let pruned = 0;
207
+ for (const name of OBSOLETE_SKILL_NAMES) {
208
+ const path = join(target.skillsDir, name);
209
+ if (!(await pathEntryExists(path))) continue;
210
+ pruned += 1;
211
+ if (opts.dryRun) {
212
+ process.stdout.write(`[dry-run] rm ${path}\n`);
213
+ continue;
214
+ }
215
+ await fs.rm(path, { recursive: true, force: true });
216
+ }
217
+ return pruned;
218
+ }
219
+ ```
220
+
221
+ Apply the helper call rename in both `installSkillsCopy()` and `installSkillsLink()`.
222
+
223
+ - [ ] **Step 4: Run catalog tests to verify pass**
224
+
225
+ Run:
226
+
227
+ ```bash
228
+ node --test tests-js/skill-catalog.test.mjs
229
+ python3 -m pytest tests/contract/test_docs_runtime_contract.py::test_plugin_manifest_exposes_only_user_facing_skills -q
230
+ ```
231
+
232
+ Expected: PASS.
233
+
234
+ - [ ] **Step 5: Commit Task 1**
235
+
236
+ ```bash
237
+ git add skills/okstra-container-build src/lib/skill-catalog.mjs src/commands/lifecycle/install.mjs .claude-plugin/plugin.json tests-js/skill-catalog.test.mjs tests/contract/test_docs_runtime_contract.py
238
+ git commit -m "fix(container): rename public container skill to build"
239
+ ```
240
+
241
+ ### Task 2: Install/Uninstall Upgrade Cleanup
242
+
243
+ **Files:**
244
+ - Modify: `tests-js/install-runtime.test.mjs`
245
+ - Modify: `tests-js/uninstall-runtime.test.mjs`
246
+ - Modify: `src/commands/lifecycle/uninstall.mjs`
247
+
248
+ **Interfaces:**
249
+ - Consumes: `OBSOLETE_SKILL_NAMES` includes `okstra-container`.
250
+ - Produces: install removes old `okstra-container` skill dirs during upgrade.
251
+ - Produces: uninstall fallback can remove both `okstra-container-build` and old `okstra-container`.
252
+
253
+ - [ ] **Step 1: Write failing install prune regression**
254
+
255
+ In `tests-js/install-runtime.test.mjs`, extend `install copies skills to existing Claude and Agent homes and records targets` after the `.claude` / `.agent` roots are created:
256
+
257
+ ```js
258
+ for (const providerRoot of [join(root, ".claude", "skills"), join(root, ".agent", "skills")]) {
259
+ mkdirSync(join(providerRoot, "okstra-container"), { recursive: true });
260
+ writeFileSync(join(providerRoot, "okstra-container", "SKILL.md"), "old container skill\n");
261
+ }
262
+ ```
263
+
264
+ Extend the provider-root assertions:
265
+
266
+ ```js
267
+ assert.equal(existsSync(join(providerRoot, "okstra-container-build", "SKILL.md")), true);
268
+ assert.equal(existsSync(join(providerRoot, "okstra-container", "SKILL.md")), false);
269
+ ```
270
+
271
+ - [ ] **Step 2: Write failing uninstall fallback regression**
272
+
273
+ Add this test to `tests-js/uninstall-runtime.test.mjs`:
274
+
275
+ ```js
276
+ test("uninstall fallback removes renamed and legacy container skills", () => {
277
+ const { root, env } = makeInstallEnv();
278
+ mkdirSync(join(root, ".okstra"), { recursive: true });
279
+ mkdirSync(join(root, ".claude", "skills", "okstra-container"), { recursive: true });
280
+ mkdirSync(join(root, ".claude", "skills", "okstra-container-build"), { recursive: true });
281
+
282
+ const uninstall = runCli(["uninstall", "-y"], env);
283
+ assert.equal(uninstall.code, 0, uninstall.stderr);
284
+
285
+ assert.equal(existsSync(join(root, ".claude", "skills", "okstra-container")), false);
286
+ assert.equal(existsSync(join(root, ".claude", "skills", "okstra-container-build")), false);
287
+ });
288
+ ```
289
+
290
+ - [ ] **Step 3: Run failing install/uninstall tests**
291
+
292
+ Run:
293
+
294
+ ```bash
295
+ node --test tests-js/install-runtime.test.mjs tests-js/uninstall-runtime.test.mjs
296
+ ```
297
+
298
+ Expected: FAIL until `src/commands/lifecycle/uninstall.mjs` fallback names include both container skill names and install prune is wired to `OBSOLETE_SKILL_NAMES`.
299
+
300
+ - [ ] **Step 4: Implement fallback cleanup names**
301
+
302
+ Edit `src/commands/lifecycle/uninstall.mjs` `FALLBACK_SKILL_NAMES`:
303
+
304
+ ```js
305
+ const FALLBACK_SKILL_NAMES = [
306
+ "okstra",
307
+ "okstra-setup",
308
+ "okstra-brief",
309
+ "okstra-run",
310
+ "okstra-memory",
311
+ "okstra-inspect",
312
+ "okstra-schedule",
313
+ "okstra-container-build",
314
+ "okstra-container",
315
+ "okstra-context-loader",
316
+ "okstra-team-contract",
317
+ "okstra-convergence",
318
+ "okstra-report-writer",
319
+ // Pre-merge names — kept so uninstall on an upgraded machine still cleans
320
+ // them out of ~/.claude/skills/ once the user runs `okstra uninstall`.
321
+ // Safe to drop after a few releases when nobody has them installed.
322
+ "okstra-status",
323
+ "okstra-history",
324
+ "okstra-logs",
325
+ "okstra-report-finder",
326
+ "okstra-time-summary",
327
+ ];
328
+ ```
329
+
330
+ - [ ] **Step 5: Run install/uninstall tests to verify pass**
331
+
332
+ Run:
333
+
334
+ ```bash
335
+ node --test tests-js/install-runtime.test.mjs tests-js/uninstall-runtime.test.mjs
336
+ ```
337
+
338
+ Expected: PASS.
339
+
340
+ - [ ] **Step 6: Commit Task 2**
341
+
342
+ ```bash
343
+ git add src/commands/lifecycle/uninstall.mjs tests-js/install-runtime.test.mjs tests-js/uninstall-runtime.test.mjs
344
+ git commit -m "fix(install): prune legacy container skill on rename"
345
+ ```
346
+
347
+ ### Task 3: Docs, Prompts, and User-Visible Changelog
348
+
349
+ **Files:**
350
+ - Move: `docs/for-ai/skills/okstra-container.md` -> `docs/for-ai/skills/okstra-container-build.md`
351
+ - Modify: `README.md`
352
+ - Modify: `README.kr.md`
353
+ - Modify: `docs/kr/architecture.md`
354
+ - Modify: `docs/project-structure-overview.md`
355
+ - Modify: `docs/kr/container.md`
356
+ - Modify: `docs/for-ai/README.md`
357
+ - Modify: `docs/for-ai/skills/okstra-container-build.md`
358
+ - Modify: `docs/for-ai/skills/okstra-inspect.md`
359
+ - Modify: `prompts/profiles/_implementation-deliverable.md`
360
+ - Modify: `prompts/profiles/final-verification.md`
361
+ - Modify: `docs/superpowers/specs/2026-06-24-manual-user-test-section-design.md`
362
+ - Modify: `docs/superpowers/plans/2026-06-24-manual-user-test-section.md`
363
+ - Modify: `CHANGES.md`
364
+ - Test: `tests/contract/test_docs_runtime_contract.py`
365
+
366
+ **Interfaces:**
367
+ - Consumes: public skill name `okstra-container-build`.
368
+ - Produces: user-facing slash command docs use `/okstra-container-build`.
369
+ - Produces: prompt guidance uses `/okstra-container-build` for skill invocation and `okstra container up ...` for CLI execution.
370
+
371
+ - [ ] **Step 1: Write failing docs scan command**
372
+
373
+ Run:
374
+
375
+ ```bash
376
+ rg -n -P '/okstra-container(?!-build)\\b|okstra-container up|okstra-container-build[[:alpha:]]' README.md README.kr.md docs/kr/architecture.md docs/project-structure-overview.md docs/kr/container.md docs/for-ai prompts/profiles/_implementation-deliverable.md prompts/profiles/final-verification.md docs/superpowers/specs/2026-06-24-manual-user-test-section-design.md docs/superpowers/plans/2026-06-24-manual-user-test-section.md
377
+ ```
378
+
379
+ Expected before edits: matches showing old slash-command/prompt references and zero `builder` references after the corrected spec.
380
+
381
+ - [ ] **Step 2: Rename AI manual file and update live references**
382
+
383
+ Run:
384
+
385
+ ```bash
386
+ git mv docs/for-ai/skills/okstra-container.md docs/for-ai/skills/okstra-container-build.md
387
+ ```
388
+
389
+ Apply these text rules:
390
+
391
+ ```text
392
+ /okstra-container -> /okstra-container-build
393
+ `okstra-container` as public skill name -> `okstra-container-build`
394
+ skills/okstra-container.md -> skills/okstra-container-build.md
395
+ skills/okstra-container/SKILL.md -> skills/okstra-container-build/SKILL.md
396
+ ```
397
+
398
+ Do not change these runtime strings:
399
+
400
+ ```text
401
+ okstra container
402
+ okstra-container-<slug>
403
+ @okstra_container_run
404
+ ```
405
+
406
+ In `prompts/profiles/_implementation-deliverable.md`, replace the environment line with:
407
+
408
+ ```markdown
409
+ - **Manual user test draft**: when this run produces a user-observable change (UI / API / CLI / artifact), write `target / environment / steps / expected result` per change into §5.7.9 (data field `implementation.manualUserTest`, `applicable=true` with `items`). Environment line: if the project has a `docker-compose.yml`, use `/okstra-container-build` (which runs `okstra container up <task-id>`) then connect to the published port; otherwise the project's run command (e.g. `npm start`). When there is no user-observable change, set `applicable=false` and give a one-line `exemptionReason` instead of items. Base the steps on the approved plan's `Acceptance:` and this run's actual diff — these are the steps a human (or `final-verification`) re-runs by hand, NOT the automated validation commands in `Validation evidence`.
410
+ ```
411
+
412
+ In `prompts/profiles/final-verification.md`, replace the manual test example with:
413
+
414
+ ```markdown
415
+ - **Manual user test results**: take each item from the source implementation report's §5.7.9 Manual User Test (Draft), execute the ones reproducible in this environment (e.g. `/okstra-container-build`, which runs `okstra container up`, then the documented steps), and record `result` (`pass` / `fail` / `blocked`) + observed value in §5.8.7 (data field `finalVerification.manualUserTest`). Steps that need human-only interaction this run cannot perform are recorded as `blocked` with the reason (handed to the user), never silently skipped. A failed manual test is an Acceptance Blocker. If the draft was an exemption (`applicable=false`), reaffirm the reason in one line (`applicable=false` + `exemptionReaffirm`).
416
+ ```
417
+
418
+ - [ ] **Step 3: Add current CHANGES entry**
419
+
420
+ Under `## 2026-06-24`, add this entry above the existing entries:
421
+
422
+ ```markdown
423
+ ### fix(container): 공개 컨테이너 스킬명을 okstra-container-build 로 변경
424
+
425
+ - **배경**: 컨테이너 유저 테스트 기능의 공개 slash command 이름을 `okstra-container` 에서 `okstra-container-build` 로 바꾸기로 결정했다. CLI 명령 `okstra container ...` 와 런타임 tmux/docker trace prefix `okstra-container-<slug>` 는 컨테이너 런타임 계약이므로 유지한다.
426
+ - **해결**: 공개 skill catalog, 플러그인 manifest, 설치/업그레이드 cleanup, README/architecture/AI manual/phase prompt 의 사용자-facing 표기를 `okstra-container-build` 로 동기화한다. 옛 `okstra-container` skill directory 는 exact-name obsolete cleanup 으로 재설치 시 제거한다.
427
+ - 사용자 영향: 재설치 후 slash command 는 `/okstra-container-build` 로 노출된다. 기존 `okstra container up/status/logs/stop-watcher/down` CLI 와 실행 중 container watcher trace 이름은 그대로 유지된다. (설치 환경은 `okstra install` 로 런타임 갱신 후 적용.)
428
+ ```
429
+
430
+ - [ ] **Step 4: Run docs scans and contract test**
431
+
432
+ Run:
433
+
434
+ ```bash
435
+ rg -n -P '/okstra-container(?!-build)\\b|okstra-container up|okstra-container-build[[:alpha:]]' README.md README.kr.md docs/kr/architecture.md docs/project-structure-overview.md docs/kr/container.md docs/for-ai prompts/profiles/_implementation-deliverable.md prompts/profiles/final-verification.md docs/superpowers/specs/2026-06-24-manual-user-test-section-design.md docs/superpowers/plans/2026-06-24-manual-user-test-section.md
436
+ python3 -m pytest tests/contract/test_docs_runtime_contract.py -q
437
+ ```
438
+
439
+ Expected: `rg` exits 1 with no matches; pytest PASS.
440
+
441
+ - [ ] **Step 5: Commit Task 3**
442
+
443
+ ```bash
444
+ git add README.md README.kr.md docs/kr/architecture.md docs/project-structure-overview.md docs/kr/container.md docs/for-ai/README.md docs/for-ai/skills/okstra-container-build.md docs/for-ai/skills/okstra-inspect.md prompts/profiles/_implementation-deliverable.md prompts/profiles/final-verification.md docs/superpowers/specs/2026-06-24-manual-user-test-section-design.md docs/superpowers/plans/2026-06-24-manual-user-test-section.md CHANGES.md
445
+ git commit -m "docs(container): rename container skill docs to build"
446
+ ```
447
+
448
+ ### Task 4: Runtime Build and Full Verification
449
+
450
+ **Files:**
451
+ - Generated: `runtime/` via `npm run build` (gitignored, do not hand-edit)
452
+ - Test: `tests-js/*.test.mjs`
453
+ - Test: `tests/`
454
+ - Test: `validators/validate-workflow.sh`
455
+
456
+ **Interfaces:**
457
+ - Consumes: source skill directory `skills/okstra-container-build`.
458
+ - Produces: generated `runtime/skills/okstra-container-build/SKILL.md`.
459
+ - Produces: no generated `runtime/skills/okstra-container/SKILL.md`.
460
+
461
+ - [ ] **Step 1: Run build**
462
+
463
+ Run:
464
+
465
+ ```bash
466
+ npm run build
467
+ ```
468
+
469
+ Expected: exit 0. Output includes `skills -> runtime/skills` sync. `runtime/` remains untracked/ignored.
470
+
471
+ - [ ] **Step 2: Verify runtime skill sync**
472
+
473
+ Run:
474
+
475
+ ```bash
476
+ test -f runtime/skills/okstra-container-build/SKILL.md
477
+ test ! -e runtime/skills/okstra-container/SKILL.md
478
+ rg -n "name: okstra-container-build" runtime/skills/okstra-container-build/SKILL.md
479
+ ```
480
+
481
+ Expected: all commands exit 0.
482
+
483
+ - [ ] **Step 3: Run targeted test suite**
484
+
485
+ Run:
486
+
487
+ ```bash
488
+ node --test tests-js/skill-catalog.test.mjs tests-js/install-runtime.test.mjs tests-js/uninstall-runtime.test.mjs tests-js/doctor-runtime.test.mjs
489
+ python3 -m pytest tests/contract/test_docs_runtime_contract.py -q
490
+ ```
491
+
492
+ Expected: PASS.
493
+
494
+ - [ ] **Step 4: Run project check**
495
+
496
+ Run:
497
+
498
+ ```bash
499
+ npm run check
500
+ ```
501
+
502
+ Expected: exit 0.
503
+
504
+ - [ ] **Step 5: Run final identifier audit**
505
+
506
+ Run:
507
+
508
+ ```bash
509
+ rg -n "okstra-container-build[[:alpha:]]|container-build[[:alpha:]]" .
510
+ rg -n "okstra-container" .
511
+ ```
512
+
513
+ Expected:
514
+ - First command exits 1 with no matches.
515
+ - Second command still reports historical changelog/old design-plan references and runtime prefix tests such as `okstra-container-<slug>`, but not live public skill catalog, plugin manifest, README slash-command rows, AI routing manuals, or live phase prompt instructions.
516
+
517
+ - [ ] **Step 6: Record verification-only status**
518
+
519
+ Run:
520
+
521
+ ```bash
522
+ git status --short
523
+ ```
524
+
525
+ Expected: no new tracked source changes from Task 4. `runtime/` may have been regenerated by `npm run build` but remains ignored. Do not create a commit for this task unless a tracked verification fixture changed.
@@ -0,0 +1,129 @@
1
+ # Cross-Project Dependencies — implementation-planning 선행 필수 격상 설계
2
+
3
+ - 작성일: 2026-06-24
4
+ - 대상 phase: `implementation-planning`
5
+ - 상태: 설계 승인 완료 (구현 계획 작성 대기)
6
+
7
+ ## 1. 배경과 문제
8
+
9
+ `implementation-planning` 보고서는 `data.json`(SSOT) → Jinja 템플릿(`templates/reports/final-report.template.md`)으로 **결정론적 렌더**된다. report-writer 는 마크다운을 직접 쓰지 못한다([report-writer-worker.md:27](../../../agents/workers/report-writer-worker.md:27)).
10
+
11
+ 이 run 이 **다른 프로젝트(다른 repo·published 패키지)** 의 작업에 의존할 때, 그 의존을 표현할 수 있는 채널이 현재 3개뿐이고 모두 부족하다:
12
+
13
+ 1. **`§3 Recommended Next Steps`** (`recommendedNextSteps[]`, 자유 텍스트) — "추천"이라 강제력이 없다. 실제 사례(`dev-9795`)에서 "helpers·common-api cross-repo carry 를 별도 okstra run 으로 먼저 진행하라"가 여기에 soft 하게 들어가, 선행 필수임이 드러나지 않았다.
14
+ 2. **`Dependency / Migration Risk`** DM 행 — `kind` enum 에 `flag-precondition`/`repo-sequencing` 이 있으나([schema:1369](../../../schemas/final-report-v1.0.schema.json)) "위험 서술"일 뿐 "선행 필수 + 구체 작업"을 강제하지 않는다. `repo-sequencing` 은 프로파일상 **repo-내부 순서**를 뜻한다([implementation-planning.md:100](../../../prompts/profiles/implementation-planning.md:100)) — cross-repo 마커가 아니다.
15
+ 3. **프로파일이 요구하는 `## Cross-Repo Carry — <repo>` 부록**([implementation-planning.md:94](../../../prompts/profiles/implementation-planning.md:94)) — **스키마·템플릿에 렌더 슬롯이 없어 보고서에 출력되지 못하는 잠복 버그**. 게다가 방향이 "이 run 이 상위(upstream)이고 다른 repo 가 하위"로, 사용자 사례(이 run 이 **하위**, 외부 패키지가 **선행 상위**)와 반대다.
16
+
17
+ 결과적으로 **"이 run 이 다른 프로젝트의 선행 작업에 의존한다"** 는 1급 개념이 없어 soft recommendation 으로 새어나가고, 거기서 필요한 **구체 작업**도 강제되지 않는다.
18
+
19
+ ## 2. 목표 / 비목표
20
+
21
+ ### 목표
22
+ - cross-project 의존을 **1급·렌더되는 구조 필드**로 승격한다.
23
+ - upstream(이 run 이 기다림 = 선행 필수)과 downstream(이 run 이 만들어 줌 = 기존 carry) **두 방향을 한 개념으로 통합**한다.
24
+ - 각 의존에 **구체적으로 필요한 작업**(`requiredWork`)을 빈말 못 하도록 스키마 레벨에서 강제한다.
25
+ - cross-project 의존이 선언되면 이 섹션이 비어있지 못하도록 **검증기 게이트**를 둔다.
26
+ - 기존 `## Cross-Repo Carry` 잠복 렌더 버그를 통합 과정에서 해소한다.
27
+
28
+ ### 비목표
29
+ - **런타임 게이트 없음.** `implementation` run 진입 시 선행 신호를 자동 확인하거나 워커 fan-out 을 차단하지 않는다.
30
+ - **승인 차단 없음.** 계획 frontmatter `approved` 를 막지 않는다 — 선행 작업은 병렬 진행 가능하므로 계획 승인 자체는 막지 않는다.
31
+ - 다른 repo 의 트리·`.okstra/` 에 쓰지 않는다(기존 cross-repo 구조 한계 유지).
32
+
33
+ ## 3. 설계
34
+
35
+ ### 3.1 데이터 모델 (schema)
36
+
37
+ `schemas/final-report-v1.0.schema.json` 의 `implementationPlanning` 객체에 새 배열 `crossProjectDependencies` 를 추가한다(기본 `[]` 허용 — 단일 프로젝트 계획은 빈 배열).
38
+
39
+ 새 `$defs/CrossProjectDependency`:
40
+
41
+ | 필드 | 타입/제약 | 의미 |
42
+ |---|---|---|
43
+ | `id` | `^XP-\d{3,}$` | cross-project 식별자 |
44
+ | `direction` | enum: `upstream-precondition` \| `downstream-carry` | upstream = 이 run 이 **기다림**(선행 필수); downstream = 이 run 이 **만들어 줌**(기존 carry) |
45
+ | `project` | string, minLength 1 | 상대 프로젝트/repo/패키지명 (예: `@fonts-ninja-org/common-api`) |
46
+ | `requiredWork` | string, minLength 1 | **구체적으로 필요한 작업**. upstream: 상대 프로젝트가 만들어야 할 것; downstream: 상대가 후속으로 구현할 B-portion |
47
+ | `verificationSignal` | string, minLength 1 | 충족을 증명하는 관측 신호 (예: "npm common-api ≥ 1.27.46 + Font.d.ts 에 isSlanted 존재") |
48
+ | `linkedWork` | string, minLength 1 | upstream: 신호 충족 전 **막히는 이 계획의 stage/step**; downstream: 이 run 산출물을 소비하는 상대 작업 |
49
+ | `howToStart` | string, minLength 1 | 정확한 핸드오프 (`okstra-brief …(이 보고서 절대경로 Source Material)` → `okstra-run`) |
50
+
51
+ - `additionalProperties: false`, 위 7개 전부 `required`.
52
+ - `direction` 으로 양방향을 한 구조에 담는다. 기존 Cross-Repo Carry 의 세 서브섹션은 `downstream-carry` 행으로 흡수: `Preconditions already covered by this run` → `verificationSignal`(상대가 확인할 신호), `Work for <repo> to implement` → `requiredWork`, `How to start <repo>'s run` → `howToStart`.
53
+
54
+ ### 3.2 렌더 (template + i18n)
55
+
56
+ `templates/reports/final-report.template.md` 의 §5.4 블록에서 `### Dependency / Migration Risk`([template:208](../../../templates/reports/final-report.template.md:208)) **바로 뒤**에 새 서브섹션 `### Cross-Project Dependencies` 를 추가한다.
57
+
58
+ - **엔트리별 블록** 렌더(Option Candidates 방식). 7열 표는 가독성이 떨어지므로 표를 쓰지 않는다:
59
+ ```
60
+ **XP-001 — [upstream-precondition] @fonts-ninja-org/common-api**
61
+ - Required work: Font.d.ts 에 isSlanted 컬럼 추가 후 publish (≥ 1.27.46)
62
+ - Verification signal: npm view … → ≥ 1.27.46 AND isSlanted present
63
+ - Gated work in this plan: Stage 2 yarn install / Stage 3 compile — 신호 충족 전 진행 불가
64
+ - How to start: common-api repo 에서 okstra-brief … → okstra-run
65
+ ```
66
+ - `crossProjectDependencies` 가 비면 단일 empty-state 라인(`- 해당 없음.` / 영어 i18n) 을 렌더한다 — 단일 프로젝트 계획은 항상 이 줄이 보인다.
67
+ - i18n: `templates/reports/i18n/{ko,en}.json` 에 섹션 헤딩 aside, 라벨(Required work / Verification signal / Linked work / How to start), empty-state 문자열 추가.
68
+ - 방향 라벨(`[upstream-precondition]` / `[downstream-carry]`)은 reader 가 선행/후속을 한눈에 구분하도록 블록 제목에 박는다.
69
+
70
+ ### 3.3 강제 (validator) — 두 겹
71
+
72
+ **(a) 모양 규칙 — watertight, JSON 스키마가 강제**
73
+ `crossProjectDependencies` 가 비어있지 않으면 모든 행의 7개 필드가 minLength 1 을 만족해야 한다. `requiredWork`/`verificationSignal`/`howToStart` 가 비면 스키마 검증 실패 → **"구체 작업 명시"가 빈말이 될 수 없다.** `validate-run.py` 의 data.json 스키마 검증 경로([validate-run.py:1440](../../../validators/validate-run.py:1440))에서 자동 적용.
74
+
75
+ **(b) 존재 규칙 — trigger, `validate-run.py` 교차 필드 검사**
76
+ - DM `kind` enum 에 새 값 **`cross-project`** 추가(pre-1.0, enum 확장 자유). 의미: 다른 프로젝트/repo/패키지에 대한 의존. 기존 `repo-sequencing`(repo-내부)·`flag-precondition`(repo-내 플래그)과 명확히 구분.
77
+ - `validate-run.py` 에 교차 필드 규칙 신설: **data.json 에 `dependencyMigrationRisk` 행 중 `kind == cross-project` 가 하나라도 있으면 `crossProjectDependencies` 는 비어있으면 안 되고, `direction == upstream-precondition` 행이 ≥ 1 이어야 한다.** 위반 시 `contract-violated`.
78
+ - 이 규칙이 **"추천 → 선행 필수" 격상의 강제 지점**이다. 프로파일이 "타 repo/패키지 의존은 반드시 DM `cross-project` 행 + 매칭 XP 행으로 기록"을 지시하고, 검증기가 1:1 을 강제한다(allowlist 방식).
79
+
80
+ **(c) 섹션 헤딩 contract**
81
+ `implementation-planning.md` 섹션 헤딩 contract([implementation-planning.md:57](../../../prompts/profiles/implementation-planning.md:57))의 필수 substring 목록에 `Cross-Project Dependencies` 를 추가. 템플릿이 이 헤딩을 무조건 렌더하므로(empty-state 포함) substring 검사를 통과한다.
82
+
83
+ ### 3.4 프로파일 prose (`prompts/profiles/implementation-planning.md`)
84
+
85
+ - 기존 Cross-Repo Carry 부록 블록(94–98)을 **새 구조 필드 참조로 재작성**하고 **양방향**(upstream-precondition / downstream-carry)을 커버하도록 바꾼다. "Recognition caveat"(상대 run 의 독립성) 문구는 섹션 하단 고정 노트(i18n)로 유지.
86
+ - "Required deliverable shape" 에 `crossProjectDependencies` 항목 추가: 타 프로젝트 의존은 DM `cross-project` 행 + 매칭 XP 행(구체 `requiredWork`·`verificationSignal`·`howToStart`) 으로 기록할 것.
87
+ - self-review 패스([implementation-planning.md:122](../../../prompts/profiles/implementation-planning.md:122))에 점검 추가: "타 repo/패키지 의존을 빠뜨리지 않았는가; DM `cross-project` ↔ XP 행 1:1 이 맞는가; `requiredWork` 가 구체적인가".
88
+ - §5.5.9 Plan Body Verification 의 adversarial 라운드 대상에 cross-project precondition 누락 점검을 포함.
89
+ - `recommendedNextSteps` 의 cross-project 항목 정책: **substance 는 새 섹션에, §3 는 포인터만**(이중 기록 방지). report-writer 가이드(`prompts/lead/report-writer.md:284` 인근)도 동기화.
90
+
91
+ ### 3.5 스키마 excerpt / 빌드 흐름
92
+
93
+ - per-task-type 스키마 excerpt 빌더(`scripts/okstra_ctl/schema_excerpt.py`, `final_report_schema.py`)가 `implementationPlanning` 블록과 그 `$defs` 를 자동 포함하는지 확인한다. 새 `$defs/CrossProjectDependency` 가 implementation-planning excerpt 에 반드시 들어가야 report-writer 가 올바른 shape 로 authoring 한다.
94
+ - `runtime/` 은 빌드 출력이므로 직접 수정 금지 — 소스(`schemas/`, `templates/`, `prompts/`, `validators/`, `agents/`) 수정 후 `npm run build` 로 동기화.
95
+
96
+ ## 4. 변경 파일 목록
97
+
98
+ | 파일 | 변경 |
99
+ |---|---|
100
+ | `schemas/final-report-v1.0.schema.json` | `$defs/CrossProjectDependency` 신설; `implementationPlanning.crossProjectDependencies` 추가; DM `kind` enum 에 `cross-project` 추가 |
101
+ | `templates/reports/final-report.template.md` | §5.4 에 `### Cross-Project Dependencies` 엔트리별 블록 + empty-state |
102
+ | `templates/reports/i18n/ko.json`, `en.json` | 섹션 헤딩 aside·필드 라벨·empty-state·recognition-caveat 문자열 |
103
+ | `prompts/profiles/implementation-planning.md` | Cross-Repo Carry 재작성(양방향), deliverable shape·self-review·heading contract·recommendedNextSteps 정책 갱신 |
104
+ | `prompts/lead/report-writer.md` | recommendedNextSteps cross-project 포인터 정책 동기화 |
105
+ | `validators/validate-run.py` | DM `cross-project` ↔ `crossProjectDependencies` 교차 필드 규칙 |
106
+ | `agents/workers/report-writer-worker.md` | 필요 시 새 섹션 authoring 안내(스키마 excerpt 가 주도하므로 최소) |
107
+ | `tests/` | 아래 §6 검증 계획 |
108
+
109
+ ## 5. 강제 지점 매핑 (MUST → 어디서 강제되나)
110
+
111
+ | 규칙 | 강제 지점 |
112
+ |---|---|
113
+ | XP 행의 7필드 비-빈 (구체 작업 명시) | JSON 스키마 `required` + minLength → `validate-run.py` 스키마 검증 |
114
+ | DM `cross-project` 있으면 XP `upstream-precondition` ≥ 1 | `validate-run.py` 신설 교차 필드 검사 |
115
+ | 섹션 헤딩 `Cross-Project Dependencies` 존재 | `validate-run.py` substring 검사 + 템플릿 무조건 렌더 |
116
+ | report-writer 가 올바른 shape authoring | implementation-planning 스키마 excerpt 에 포함 |
117
+
118
+ ## 6. 검증 계획 (추가할 테스트)
119
+
120
+ - `tests/report/test_render_final_report.py`: `implementation-planning` 픽스처에 `crossProjectDependencies`(upstream·downstream 각 1행) 추가 → 렌더 결과에 블록·라벨·방향 태그가 나오는지; 빈 배열 → empty-state 라인이 나오는지.
121
+ - `tests/contract/` (또는 validate-run 테스트): DM `cross-project` 행이 있는데 `crossProjectDependencies` 가 비면 `contract-violated` 인지; XP 행에 `requiredWork` 빈 값이면 스키마 검증 실패인지.
122
+ - `tests/fixtures/final-report-data/implementation-planning-001.data.json`: 새 필드 반영(빈 배열로 최소 변경하거나 샘플 1행 추가).
123
+ - 완료 게이트: `npm run check` 가 그대로 exit 0.
124
+
125
+ ## 7. 한계 / 미해결
126
+
127
+ - **존재 규칙의 trigger 는 planner 가 DM `cross-project` 를 찍어야 발동**한다. cross-project 의존을 DM 에 전혀 기록하지 않으면 검증기가 잡지 못한다(완전 watertight 불가). 이를 줄이기 위해 프로파일 self-review + §5.5.9 adversarial verification 이 누락을 잡도록 prose 로 보강한다(휴리스틱, 강제 아님 — 이 한계를 spec 에 명시).
128
+ - 자유 텍스트(`recommendedNextSteps`)에서 cross-project 신호를 토큰 매칭으로 자동 검출하지 않는다(오탐 위험). 구조 신호(DM `cross-project`)만을 강제 앵커로 쓴다.
129
+ - 런타임 자동 신호 확인(예: npm 버전 publish 여부)은 본 설계 범위 밖(비목표).