okstra 0.102.2 → 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.
Files changed (161) hide show
  1. package/README.kr.md +5 -5
  2. package/README.md +5 -5
  3. package/docs/kr/architecture/storage-model.md +1 -1
  4. package/docs/kr/architecture.md +7 -11
  5. package/docs/kr/cli.md +4 -4
  6. package/docs/kr/container.md +1 -1
  7. package/docs/kr/performance-improvement-plan-v2.md +2 -2
  8. package/docs/project-structure-overview.md +2 -2
  9. package/package.json +7 -2
  10. package/runtime/BUILD.json +2 -2
  11. package/runtime/bin/okstra-antigravity-exec.sh +1 -2
  12. package/runtime/bin/okstra-codex-exec.sh +1 -2
  13. package/runtime/bin/okstra-render-final-report.py +2 -9
  14. package/runtime/bin/okstra-spawn-followups.py +4 -6
  15. package/runtime/bin/okstra-trace-cleanup.sh +24 -4
  16. package/runtime/prompts/lead/okstra-lead-contract.md +2 -2
  17. package/runtime/prompts/lead/report-writer.md +1 -1
  18. package/runtime/prompts/profiles/_common-contract.md +9 -11
  19. package/runtime/python/okstra_ctl/codex_dispatch.py +4 -12
  20. package/runtime/python/okstra_ctl/consumers.py +35 -0
  21. package/runtime/python/okstra_ctl/container.py +4 -6
  22. package/runtime/python/okstra_ctl/dispatch_core.py +4 -12
  23. package/runtime/python/okstra_ctl/final_report_paths.py +24 -0
  24. package/runtime/python/okstra_ctl/handoff.py +2 -1
  25. package/runtime/python/okstra_ctl/implementation_stage.py +7 -11
  26. package/runtime/python/okstra_ctl/report_view_artifacts.py +14 -0
  27. package/runtime/python/okstra_ctl/report_views.py +7 -4
  28. package/runtime/python/okstra_ctl/run.py +3 -10
  29. package/runtime/python/okstra_ctl/stage_targets.py +18 -0
  30. package/runtime/python/okstra_ctl/wizard.py +24 -25
  31. package/runtime/python/okstra_ctl/wizard_stage_intent.py +54 -0
  32. package/runtime/python/okstra_token_usage/report.py +2 -5
  33. package/runtime/validators/validate-report-views.py +2 -1
  34. package/runtime/validators/validate-run.py +1 -11
  35. package/src/commands/lifecycle/install.mjs +5 -5
  36. package/src/commands/lifecycle/uninstall.mjs +4 -4
  37. package/docs/superpowers/plans/2026-05-12-ticket-id-in-reports.md +0 -638
  38. package/docs/superpowers/plans/2026-05-14-convergence-queue-pruning.md +0 -1568
  39. package/docs/superpowers/plans/2026-05-17-dual-format-final-report.md +0 -167
  40. package/docs/superpowers/plans/2026-05-20-final-report-language.md +0 -1501
  41. package/docs/superpowers/plans/2026-05-20-implementation-planning-multi-stage.md +0 -1267
  42. package/docs/superpowers/plans/2026-05-20-okstra-run-prompt-sot-b1.md +0 -1007
  43. package/docs/superpowers/plans/2026-05-20-wizard-messages-json-sot.md +0 -720
  44. package/docs/superpowers/plans/2026-05-20-wizard-prompt-json-sot-a1.md +0 -681
  45. package/docs/superpowers/plans/2026-05-21-improvement-discovery-task-type.md +0 -1691
  46. package/docs/superpowers/plans/2026-05-24-implementation-lead-context-slimming.md +0 -1700
  47. package/docs/superpowers/plans/2026-05-25-okstra-project-root-rename.md +0 -158
  48. package/docs/superpowers/plans/2026-05-26-wizard-3-option-picker.md +0 -860
  49. package/docs/superpowers/plans/2026-06-02-final-verification-protocol-hardening.md +0 -326
  50. package/docs/superpowers/plans/2026-06-02-okstra-run-branch-confirm-step.md +0 -337
  51. package/docs/superpowers/plans/2026-06-02-okstra-run-phase-pane-cleanup.md +0 -410
  52. package/docs/superpowers/plans/2026-06-02-requirements-discovery-fanout.md +0 -728
  53. package/docs/superpowers/plans/2026-06-04-adversarial-implementation-planning.md +0 -294
  54. package/docs/superpowers/plans/2026-06-04-adversarial-verification.md +0 -570
  55. package/docs/superpowers/plans/2026-06-04-coverage-critic.md +0 -516
  56. package/docs/superpowers/plans/2026-06-04-stage-cohesion-planner.md +0 -351
  57. package/docs/superpowers/plans/2026-06-04-stage-run-batching.md +0 -457
  58. package/docs/superpowers/plans/2026-06-05-acceptance-critic.md +0 -251
  59. package/docs/superpowers/plans/2026-06-05-compact-markdown-report-tables.md +0 -323
  60. package/docs/superpowers/plans/2026-06-05-wizard-batch-prompts.md +0 -559
  61. package/docs/superpowers/plans/2026-06-06-final-verification-whole-task-gate.md +0 -993
  62. package/docs/superpowers/plans/2026-06-06-stage-parallel-and-pending-fixes.md +0 -93
  63. package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p1.md +0 -447
  64. package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p2.md +0 -289
  65. package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p3.md +0 -774
  66. package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p4.md +0 -303
  67. package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p5-multidep-base.md +0 -387
  68. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase2.md +0 -275
  69. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase3.md +0 -282
  70. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4a.md +0 -147
  71. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4b.md +0 -262
  72. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4c.md +0 -184
  73. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4d.md +0 -88
  74. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4e.md +0 -250
  75. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa.md +0 -409
  76. package/docs/superpowers/plans/2026-06-09-implementation-run-artifact-stage-isolation.md +0 -320
  77. package/docs/superpowers/plans/2026-06-10-concurrent-run-team-guard.md +0 -456
  78. package/docs/superpowers/plans/2026-06-10-git-reconcile-stale-sha-recovery.md +0 -1408
  79. package/docs/superpowers/plans/2026-06-10-lead-worker-completion-polling-PROBE.md +0 -42
  80. package/docs/superpowers/plans/2026-06-10-lead-worker-completion-polling.md +0 -337
  81. package/docs/superpowers/plans/2026-06-10-p6-token-usage-incremental.md +0 -1029
  82. package/docs/superpowers/plans/2026-06-10-stage-group-handoff.md +0 -1572
  83. package/docs/superpowers/plans/2026-06-11-fix-cycle.md +0 -1290
  84. package/docs/superpowers/plans/2026-06-11-wizard-whole-task-final-verification.md +0 -526
  85. package/docs/superpowers/plans/2026-06-12-html-plan-approval.md +0 -1000
  86. package/docs/superpowers/plans/2026-06-13-repo-risk-hardening.md +0 -493
  87. package/docs/superpowers/plans/2026-06-14-host-runtime-auto-execution.md +0 -1775
  88. package/docs/superpowers/plans/2026-06-15-coding-preflight-pack-dispatch-path.md +0 -504
  89. package/docs/superpowers/plans/2026-06-15-internal-skill-migration-final-fixups.md +0 -342
  90. package/docs/superpowers/plans/2026-06-15-internal-skill-migration-fixups.md +0 -258
  91. package/docs/superpowers/plans/2026-06-15-internal-skill-migration-remaining-fixups.md +0 -387
  92. package/docs/superpowers/plans/2026-06-15-internal-skill-resource-migration.md +0 -749
  93. package/docs/superpowers/plans/2026-06-15-worker-prompt-anchor-final-fixups.md +0 -828
  94. package/docs/superpowers/plans/2026-06-15-worker-prompt-header-error-contract.md +0 -490
  95. package/docs/superpowers/plans/2026-06-17-okstra-error-report.md +0 -724
  96. package/docs/superpowers/plans/2026-06-18-subagent-pane-reclaim.md +0 -483
  97. package/docs/superpowers/plans/2026-06-19-agent-operating-standard.md +0 -476
  98. package/docs/superpowers/plans/2026-06-19-okstra-inspect-recap-facet.md +0 -647
  99. package/docs/superpowers/plans/2026-06-20-error-feedback-loop.md +0 -1019
  100. package/docs/superpowers/plans/2026-06-20-run-index-row-normalization.md +0 -583
  101. package/docs/superpowers/plans/2026-06-20-stage-auto-integrate-teardown.md +0 -819
  102. package/docs/superpowers/plans/2026-06-21-okstra-container-local-user-test.md +0 -714
  103. package/docs/superpowers/plans/2026-06-21-release-handoff-local-checkout.md +0 -348
  104. package/docs/superpowers/plans/2026-06-23-implementation-stage-multiselect-chain.md +0 -630
  105. package/docs/superpowers/plans/2026-06-23-implementation-step-commit-granularity.md +0 -274
  106. package/docs/superpowers/plans/2026-06-23-phase-batch-cleanup-enforcement.md +0 -409
  107. package/docs/superpowers/plans/2026-06-24-cross-project-precondition.md +0 -542
  108. package/docs/superpowers/plans/2026-06-24-decision-drafts-render-gap.md +0 -568
  109. package/docs/superpowers/plans/2026-06-24-manual-user-test-section.md +0 -203
  110. package/docs/superpowers/plans/2026-06-24-okstra-container-build-rename.md +0 -525
  111. package/docs/superpowers/specs/2026-05-12-ticket-id-in-reports-design.md +0 -131
  112. package/docs/superpowers/specs/2026-05-15-implementation-plan-verification-design.md +0 -254
  113. package/docs/superpowers/specs/2026-05-20-final-report-language-design.md +0 -383
  114. package/docs/superpowers/specs/2026-05-20-implementation-planning-multi-stage-design.md +0 -322
  115. package/docs/superpowers/specs/2026-05-20-okstra-run-prompt-sot-design.md +0 -299
  116. package/docs/superpowers/specs/2026-05-21-improvement-discovery-task-type-design.md +0 -335
  117. package/docs/superpowers/specs/2026-06-02-okstra-run-branch-confirm-step-design.md +0 -113
  118. package/docs/superpowers/specs/2026-06-02-okstra-run-phase-pane-cleanup-design.md +0 -173
  119. package/docs/superpowers/specs/2026-06-02-requirements-discovery-fanout-design.md +0 -154
  120. package/docs/superpowers/specs/2026-06-04-adversarial-implementation-planning-design.md +0 -90
  121. package/docs/superpowers/specs/2026-06-04-adversarial-verification-design.md +0 -176
  122. package/docs/superpowers/specs/2026-06-04-coverage-critic-design.md +0 -99
  123. package/docs/superpowers/specs/2026-06-04-stage-splitting-cost-aware-design.md +0 -98
  124. package/docs/superpowers/specs/2026-06-05-acceptance-critic-design.md +0 -90
  125. package/docs/superpowers/specs/2026-06-05-compact-markdown-report-tables-design.md +0 -87
  126. package/docs/superpowers/specs/2026-06-05-wizard-batch-prompts-design.md +0 -121
  127. package/docs/superpowers/specs/2026-06-06-final-verification-whole-task-gate-design.md +0 -126
  128. package/docs/superpowers/specs/2026-06-06-stage-worktree-isolation-design.md +0 -180
  129. package/docs/superpowers/specs/2026-06-06-vertical-slice-tdd-planning-design.md +0 -179
  130. package/docs/superpowers/specs/2026-06-07-stage-conformance-qa-design.md +0 -169
  131. package/docs/superpowers/specs/2026-06-09-executor-model-custom-id-cascade-design.md +0 -66
  132. package/docs/superpowers/specs/2026-06-09-implementation-run-artifact-stage-isolation-design.md +0 -87
  133. package/docs/superpowers/specs/2026-06-10-blocking-contract-posthoc-conformance-design.md +0 -168
  134. package/docs/superpowers/specs/2026-06-10-concurrent-run-team-guard-design.md +0 -107
  135. package/docs/superpowers/specs/2026-06-10-git-reconcile-stale-sha-recovery-design.md +0 -105
  136. package/docs/superpowers/specs/2026-06-10-lead-worker-completion-polling-design.md +0 -113
  137. package/docs/superpowers/specs/2026-06-10-stage-group-handoff-design.md +0 -156
  138. package/docs/superpowers/specs/2026-06-11-brief-entry-only-handoff-stage-entry-design.md +0 -158
  139. package/docs/superpowers/specs/2026-06-11-fix-cycle-design.md +0 -94
  140. package/docs/superpowers/specs/2026-06-11-wizard-whole-task-final-verification-design.md +0 -89
  141. package/docs/superpowers/specs/2026-06-12-codex-lead-adapter-design.md +0 -358
  142. package/docs/superpowers/specs/2026-06-12-html-plan-approval-design.md +0 -85
  143. package/docs/superpowers/specs/2026-06-12-stage-discipline-rule-design.md +0 -108
  144. package/docs/superpowers/specs/2026-06-13-forbidden-actions-ssot-design.md +0 -134
  145. package/docs/superpowers/specs/2026-06-13-neutral-tmux-lead-adapter-design.md +0 -284
  146. package/docs/superpowers/specs/2026-06-14-host-runtime-auto-execution-design.md +0 -404
  147. package/docs/superpowers/specs/2026-06-17-okstra-error-report-design.md +0 -123
  148. package/docs/superpowers/specs/2026-06-18-subagent-pane-reclaim-design.md +0 -150
  149. package/docs/superpowers/specs/2026-06-19-agent-operating-standard-design.md +0 -120
  150. package/docs/superpowers/specs/2026-06-19-okstra-inspect-recap-facet-design.md +0 -96
  151. package/docs/superpowers/specs/2026-06-20-error-feedback-loop-design.md +0 -171
  152. package/docs/superpowers/specs/2026-06-20-run-index-row-normalization-design.md +0 -112
  153. package/docs/superpowers/specs/2026-06-20-stage-auto-integrate-teardown-design.md +0 -145
  154. package/docs/superpowers/specs/2026-06-21-okstra-container-local-user-test-design.md +0 -125
  155. package/docs/superpowers/specs/2026-06-21-release-handoff-local-checkout-design.md +0 -113
  156. package/docs/superpowers/specs/2026-06-23-implementation-stage-multiselect-chain-design.md +0 -138
  157. package/docs/superpowers/specs/2026-06-23-implementation-step-commit-granularity-design.md +0 -120
  158. package/docs/superpowers/specs/2026-06-24-cross-project-precondition-design.md +0 -129
  159. package/docs/superpowers/specs/2026-06-24-decision-drafts-render-gap-design.md +0 -185
  160. package/docs/superpowers/specs/2026-06-24-manual-user-test-section-design.md +0 -121
  161. package/docs/superpowers/specs/2026-06-24-okstra-container-build-rename-design.md +0 -110
@@ -1,828 +0,0 @@
1
- # Worker Prompt Anchor Final Fixups 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:** 모든 deterministic worker prompt materializer가 `team-contract` 의 anchor header 계약을 같은 런타임 홈 기준으로 만족하게 만든다.
6
-
7
- **Architecture:** `scripts/okstra_ctl/worker_prompt_headers.py` 를 새 단일 헬퍼로 두고, worker prompt anchor header 8줄을 여기서만 렌더링한다. `codex_dispatch.py` 와 `dispatch_core.py` 는 같은 헬퍼를 호출해 `Worker Preamble Path`, `Coding preflight pack`, error-log/sidecar 경로를 동일하게 계산한다. 런타임 리소스 경로는 `active-run-context.runtimeResources` 를 우선하고, 없으면 `OKSTRA_HOME` 기반 `okstra_home()` 으로 fallback 한다.
8
-
9
- **Tech Stack:** Python 3.14, pytest, Node build/test runner, existing `okstra_ctl` Python modules.
10
-
11
- ---
12
-
13
- ## Current Evidence
14
-
15
- - `team-contract` 는 모든 worker prompt 가 header 8줄로 시작해야 한다고 규정한다: `prompts/lead/team-contract.md:64-75`.
16
- - `codex_dispatch.py` 는 `Coding preflight pack` 은 active context / `OKSTRA_HOME` 을 따르지만, `Worker Preamble Path` 는 module constant `Path.home() / ".okstra"` 로 고정한다: `scripts/okstra_ctl/codex_dispatch.py:35`, `scripts/okstra_ctl/codex_dispatch.py:670-695`.
17
- - `dispatch_core.py` fallback prompt 는 `# {worker_id} worker prompt` 로 시작하고, `Prompt History Path`, `Assigned worker prompt history path`, `Worker Preamble Path`, `Errors log path`, `Errors sidecar path` 를 쓰지 않는다: `scripts/okstra_ctl/dispatch_core.py:760-776`.
18
- - 현재 tests 는 fallback prompt 의 `Coding preflight pack` 존재만 확인한다: `tests/test_dispatch_core.py:11-44`.
19
-
20
- ## File Structure
21
-
22
- - Create `scripts/okstra_ctl/worker_prompt_headers.py`
23
- - Responsibility: worker prompt anchor header 8줄 렌더링 SSOT.
24
- - Owns path fallback helpers for preamble, coding-preflight pack, run errors log, worker errors sidecar.
25
- - Create `tests/test_worker_prompt_headers.py`
26
- - Responsibility: shared header renderer의 active-context 우선순위와 `OKSTRA_HOME` fallback 검증.
27
- - Modify `scripts/okstra_ctl/codex_dispatch.py`
28
- - Responsibility: `_base_prompt_headers()` 에서 shared helper 호출.
29
- - Remove local `WORKER_PREAMBLE_PATH` and local path helper duplication used only for headers.
30
- - Modify `scripts/okstra_ctl/dispatch_core.py`
31
- - Responsibility: missing prompt fallback에서도 full anchor header block을 shared helper로 생성.
32
- - Modify `tests/test_codex_dispatch.py`
33
- - Responsibility: Codex materialized prompt가 custom `OKSTRA_HOME` preamble path와 coding-preflight path를 함께 받는지 검증.
34
- - Modify `tests/test_dispatch_core.py`
35
- - Responsibility: fallback prompt가 header 8줄로 시작하고 default-home hardcode 없이 custom runtime home을 쓰는지 검증.
36
- - Modify `tests/test_docs_runtime_contract.py`
37
- - Responsibility: prompt materializer가 default `~/.okstra` preamble/coding-preflight path를 하드코딩하지 않는다는 contract guard.
38
- - Modify `CHANGES.md`
39
- - Responsibility: user-visible dispatch robustness fix 기록.
40
-
41
- ---
42
-
43
- ### Task 1: Add Shared Worker Prompt Header Renderer
44
-
45
- **Files:**
46
- - Create: `scripts/okstra_ctl/worker_prompt_headers.py`
47
- - Create: `tests/test_worker_prompt_headers.py`
48
-
49
- - [ ] **Step 1: Write failing tests for active-context paths and fallback paths**
50
-
51
- Create `tests/test_worker_prompt_headers.py` with:
52
-
53
- ```python
54
- from __future__ import annotations
55
-
56
- import sys
57
- from pathlib import Path
58
-
59
- sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "scripts"))
60
-
61
- from okstra_ctl.worker_prompt_headers import worker_prompt_headers # noqa: E402
62
-
63
-
64
- def test_worker_prompt_headers_use_active_context_paths(
65
- tmp_path: Path, monkeypatch
66
- ) -> None:
67
- monkeypatch.setenv("OKSTRA_HOME", str(tmp_path / "custom-home"))
68
- project_root = tmp_path / "project"
69
- headers = worker_prompt_headers(
70
- project_root=project_root,
71
- prompt_rel=".okstra/run/prompts/codex.md",
72
- result_rel=".okstra/run/worker-results/codex.md",
73
- worker_id="codex",
74
- manifest={},
75
- active_context={
76
- "runtimeResources": {
77
- "codingPreflightDir": "/runtime/prompts/coding-preflight",
78
- },
79
- "errorLogs": {
80
- "runErrorsLogPath": ".okstra/run/logs/errors.jsonl",
81
- "sidecarsByWorkerId": {
82
- "codex": ".okstra/run/worker-results/codex-errors.json",
83
- },
84
- },
85
- },
86
- )
87
-
88
- assert headers == [
89
- f"**Project Root:** {project_root}",
90
- "**Prompt History Path:** .okstra/run/prompts/codex.md",
91
- "**Result Path:** .okstra/run/worker-results/codex.md",
92
- f"Assigned worker prompt history path: {project_root / '.okstra/run/prompts/codex.md'}",
93
- f"**Worker Preamble Path:** {tmp_path / 'custom-home' / 'templates' / 'worker-prompt-preamble.md'}",
94
- "**Coding preflight pack:** /runtime/prompts/coding-preflight",
95
- f"**Errors log path:** {project_root / '.okstra/run/logs/errors.jsonl'}",
96
- f"**Errors sidecar path:** {project_root / '.okstra/run/worker-results/codex-errors.json'}",
97
- ]
98
-
99
-
100
- def test_worker_prompt_headers_fall_back_to_manifest_and_okstra_home(
101
- tmp_path: Path, monkeypatch
102
- ) -> None:
103
- monkeypatch.setenv("OKSTRA_HOME", str(tmp_path / "runtime-home"))
104
- project_root = tmp_path / "project"
105
- headers = worker_prompt_headers(
106
- project_root=project_root,
107
- prompt_rel=".okstra/run/prompts/codex.md",
108
- result_rel=".okstra/run/worker-results/codex.md",
109
- worker_id="codex",
110
- manifest={
111
- "taskType": "error-analysis",
112
- "runDirectoryPath": ".okstra/tasks/group/task/runs/error-analysis",
113
- "runSequencesByCategory": {
114
- "state": "001",
115
- "workerResults": "001",
116
- },
117
- },
118
- active_context={},
119
- )
120
-
121
- assert headers == [
122
- f"**Project Root:** {project_root}",
123
- "**Prompt History Path:** .okstra/run/prompts/codex.md",
124
- "**Result Path:** .okstra/run/worker-results/codex.md",
125
- f"Assigned worker prompt history path: {project_root / '.okstra/run/prompts/codex.md'}",
126
- f"**Worker Preamble Path:** {tmp_path / 'runtime-home' / 'templates' / 'worker-prompt-preamble.md'}",
127
- f"**Coding preflight pack:** {tmp_path / 'runtime-home' / 'prompts' / 'coding-preflight'}",
128
- f"**Errors log path:** {project_root / '.okstra/tasks/group/task/runs/error-analysis/logs/errors-error-analysis-001.jsonl'}",
129
- f"**Errors sidecar path:** {project_root / '.okstra/tasks/group/task/runs/error-analysis/worker-results/codex-worker-errors-error-analysis-001.json'}",
130
- ]
131
- ```
132
-
133
- - [ ] **Step 2: Run tests and verify they fail because the helper does not exist**
134
-
135
- Run:
136
-
137
- ```bash
138
- python3 -m pytest tests/test_worker_prompt_headers.py -q
139
- ```
140
-
141
- Expected: fail with `ModuleNotFoundError: No module named 'okstra_ctl.worker_prompt_headers'`.
142
-
143
- - [ ] **Step 3: Implement the shared helper**
144
-
145
- Create `scripts/okstra_ctl/worker_prompt_headers.py` with:
146
-
147
- ```python
148
- """Shared worker prompt anchor header rendering."""
149
- from __future__ import annotations
150
-
151
- from pathlib import Path
152
- from typing import Any, Mapping
153
-
154
- from .paths import okstra_home
155
-
156
-
157
- def worker_prompt_headers(
158
- *,
159
- project_root: Path,
160
- prompt_rel: str,
161
- result_rel: str,
162
- worker_id: str,
163
- manifest: Mapping[str, Any],
164
- active_context: Mapping[str, Any],
165
- ) -> list[str]:
166
- """Render the team-contract worker prompt anchor headers."""
167
- prompt_path = _resolve_project_path(project_root, prompt_rel)
168
- return [
169
- f"**Project Root:** {project_root}",
170
- f"**Prompt History Path:** {prompt_rel}",
171
- f"**Result Path:** {result_rel}",
172
- f"Assigned worker prompt history path: {prompt_path}",
173
- f"**Worker Preamble Path:** {_worker_preamble_path()}",
174
- f"**Coding preflight pack:** {_coding_preflight_pack_path(active_context)}",
175
- f"**Errors log path:** {_errors_log_path(project_root, manifest, active_context)}",
176
- (
177
- f"**Errors sidecar path:** "
178
- f"{_worker_errors_sidecar_path(project_root, manifest, active_context, worker_id)}"
179
- ),
180
- ]
181
-
182
-
183
- def _worker_preamble_path() -> Path:
184
- return okstra_home() / "templates" / "worker-prompt-preamble.md"
185
-
186
-
187
- def _coding_preflight_pack_path(active_context: Mapping[str, Any]) -> Path:
188
- runtime_resources = active_context.get("runtimeResources")
189
- if isinstance(runtime_resources, Mapping):
190
- value = _string_value(runtime_resources.get("codingPreflightDir"))
191
- if value:
192
- return Path(value)
193
- return okstra_home() / "prompts" / "coding-preflight"
194
-
195
-
196
- def _errors_log_path(
197
- project_root: Path,
198
- manifest: Mapping[str, Any],
199
- active_context: Mapping[str, Any],
200
- ) -> Path:
201
- error_logs = active_context.get("errorLogs")
202
- if isinstance(error_logs, Mapping):
203
- value = _string_value(error_logs.get("runErrorsLogPath"))
204
- if value:
205
- return _resolve_project_path(project_root, value)
206
- run_dir = _run_directory_path(project_root, manifest)
207
- task_type = _require_string(manifest, "taskType")
208
- seq = _sequence(manifest, "state")
209
- return run_dir / "logs" / f"errors-{task_type}-{seq}.jsonl"
210
-
211
-
212
- def _worker_errors_sidecar_path(
213
- project_root: Path,
214
- manifest: Mapping[str, Any],
215
- active_context: Mapping[str, Any],
216
- worker_id: str,
217
- ) -> Path:
218
- error_logs = active_context.get("errorLogs")
219
- if isinstance(error_logs, Mapping):
220
- sidecars = error_logs.get("sidecarsByWorkerId")
221
- if isinstance(sidecars, Mapping):
222
- value = _string_value(sidecars.get(worker_id))
223
- if value:
224
- return _resolve_project_path(project_root, value)
225
- run_dir = _run_directory_path(project_root, manifest)
226
- task_type = _require_string(manifest, "taskType")
227
- seq = _sequence(manifest, "workerResults")
228
- return run_dir / "worker-results" / f"{worker_id}-worker-errors-{task_type}-{seq}.json"
229
-
230
-
231
- def _run_directory_path(project_root: Path, manifest: Mapping[str, Any]) -> Path:
232
- value = _string_value(manifest.get("runDirectoryPath"))
233
- if value:
234
- return _resolve_project_path(project_root, value)
235
- team_state_path = _resolve_project_path(
236
- project_root,
237
- _require_string(manifest, "teamStatePath"),
238
- )
239
- return team_state_path.parent.parent
240
-
241
-
242
- def _sequence(manifest: Mapping[str, Any], key: str) -> str:
243
- seqs = manifest.get("runSequencesByCategory")
244
- if isinstance(seqs, Mapping):
245
- return _string_value(seqs.get(key)) or _run_seq(manifest)
246
- return _run_seq(manifest)
247
-
248
-
249
- def _run_seq(manifest: Mapping[str, Any]) -> str:
250
- seqs = manifest.get("runSequencesByCategory")
251
- if not isinstance(seqs, Mapping):
252
- raise ValueError("run manifest has no runSequencesByCategory object")
253
- return _require_string(seqs, "manifests")
254
-
255
-
256
- def _resolve_project_path(project_root: Path, value: str) -> Path:
257
- path = Path(value)
258
- return path if path.is_absolute() else project_root / path
259
-
260
-
261
- def _require_string(payload: Mapping[str, Any], key: str) -> str:
262
- value = payload.get(key)
263
- if not isinstance(value, str) or not value.strip():
264
- raise ValueError(f"missing required string field: {key}")
265
- return value
266
-
267
-
268
- def _string_value(value: Any) -> str:
269
- return value.strip() if isinstance(value, str) else ""
270
- ```
271
-
272
- - [ ] **Step 4: Run the new helper tests**
273
-
274
- Run:
275
-
276
- ```bash
277
- python3 -m pytest tests/test_worker_prompt_headers.py -q
278
- ```
279
-
280
- Expected: `2 passed`.
281
-
282
- - [ ] **Step 5: Commit Task 1**
283
-
284
- Run:
285
-
286
- ```bash
287
- git add scripts/okstra_ctl/worker_prompt_headers.py tests/test_worker_prompt_headers.py
288
- git commit -m "fix(dispatch): centralize worker prompt anchors"
289
- ```
290
-
291
- ---
292
-
293
- ### Task 2: Route Codex Dispatch Headers Through the Shared Helper
294
-
295
- **Files:**
296
- - Modify: `scripts/okstra_ctl/codex_dispatch.py:23-35`
297
- - Modify: `scripts/okstra_ctl/codex_dispatch.py:670-700`
298
- - Modify: `scripts/okstra_ctl/codex_dispatch.py:827-871`
299
- - Modify: `tests/test_codex_dispatch.py:439-457`
300
-
301
- - [ ] **Step 1: Strengthen the Codex custom-runtime test first**
302
-
303
- Replace `tests/test_codex_dispatch.py:439-457` with:
304
-
305
- ```python
306
- def test_build_dispatch_plan_materializes_codex_runtime_resources_from_okstra_home(
307
- tmp_path: Path, monkeypatch: pytest.MonkeyPatch
308
- ) -> None:
309
- runtime_home = tmp_path / "custom-okstra-home"
310
- monkeypatch.setenv("OKSTRA_HOME", str(runtime_home))
311
- paths = _write_codex_run(tmp_path, write_codex_prompt=False)
312
-
313
- build_dispatch_plan(
314
- project_root=paths["project_root"],
315
- run_manifest_path=paths["manifest_path"],
316
- workspace_root=paths["workspace_root"],
317
- okstra_bin=paths["okstra_bin"],
318
- requested_workers=["codex"],
319
- )
320
-
321
- prompt = paths["prompt_path"].read_text(encoding="utf-8")
322
- expected_preamble = runtime_home / "templates" / "worker-prompt-preamble.md"
323
- expected_preflight = runtime_home / "prompts" / "coding-preflight"
324
- default_preamble = Path.home() / ".okstra" / "templates" / "worker-prompt-preamble.md"
325
-
326
- assert f"**Worker Preamble Path:** {expected_preamble}" in prompt
327
- assert f"**Coding preflight pack:** {expected_preflight}" in prompt
328
- if default_preamble != expected_preamble:
329
- assert f"**Worker Preamble Path:** {default_preamble}" not in prompt
330
- ```
331
-
332
- - [ ] **Step 2: Run the targeted Codex test and verify it fails on the preamble assertion**
333
-
334
- Run:
335
-
336
- ```bash
337
- python3 -m pytest tests/test_codex_dispatch.py::test_build_dispatch_plan_materializes_codex_runtime_resources_from_okstra_home -q
338
- ```
339
-
340
- Expected: fail because the prompt still contains the default-home `Worker Preamble Path`.
341
-
342
- - [ ] **Step 3: Replace local Codex header rendering with shared helper**
343
-
344
- In `scripts/okstra_ctl/codex_dispatch.py`, change imports near line 23 from:
345
-
346
- ```python
347
- from .paths import okstra_home, task_dir
348
- ```
349
-
350
- to:
351
-
352
- ```python
353
- from .paths import task_dir
354
- from .worker_prompt_headers import worker_prompt_headers
355
- ```
356
-
357
- Delete this module constant near line 35:
358
-
359
- ```python
360
- WORKER_PREAMBLE_PATH = Path.home() / ".okstra" / "templates" / "worker-prompt-preamble.md"
361
- ```
362
-
363
- Replace `_base_prompt_headers()` body with:
364
-
365
- ```python
366
- def _base_prompt_headers(
367
- *,
368
- project_root: Path,
369
- manifest: Mapping[str, Any],
370
- active_context: Mapping[str, Any],
371
- worker_id: str,
372
- prompt_rel: str,
373
- result_rel: str,
374
- ) -> list[str]:
375
- return worker_prompt_headers(
376
- project_root=project_root,
377
- prompt_rel=prompt_rel,
378
- result_rel=result_rel,
379
- worker_id=worker_id,
380
- manifest=manifest,
381
- active_context=active_context,
382
- )
383
- ```
384
-
385
- Delete the local helpers that are now replaced by `worker_prompt_headers.py`:
386
-
387
- ```python
388
- def _coding_preflight_pack_path(active_context: Mapping[str, Any]) -> Path:
389
- runtime_resources = active_context.get("runtimeResources")
390
- if isinstance(runtime_resources, Mapping):
391
- value = _string_value(runtime_resources.get("codingPreflightDir"))
392
- if value:
393
- return Path(value)
394
- return okstra_home() / "prompts" / "coding-preflight"
395
- ```
396
-
397
- ```python
398
- def _errors_log_path(
399
- project_root: Path,
400
- manifest: Mapping[str, Any],
401
- active_context: Mapping[str, Any],
402
- ) -> Path:
403
- error_logs = active_context.get("errorLogs")
404
- if isinstance(error_logs, Mapping):
405
- value = _string_value(error_logs.get("runErrorsLogPath"))
406
- if value:
407
- return _resolve_project_path(project_root, value)
408
- run_dir = _run_directory_path(project_root, manifest)
409
- return run_dir / "logs" / f"errors-{_require_string(manifest, 'taskType')}-{_sequence(manifest, 'state')}.jsonl"
410
-
411
-
412
- def _worker_errors_sidecar_path(
413
- project_root: Path,
414
- manifest: Mapping[str, Any],
415
- active_context: Mapping[str, Any],
416
- worker_id: str,
417
- ) -> Path:
418
- error_logs = active_context.get("errorLogs")
419
- if isinstance(error_logs, Mapping):
420
- sidecars = error_logs.get("sidecarsByWorkerId")
421
- if isinstance(sidecars, Mapping):
422
- value = _string_value(sidecars.get(worker_id))
423
- if value:
424
- return _resolve_project_path(project_root, value)
425
- run_dir = _run_directory_path(project_root, manifest)
426
- task_type = _require_string(manifest, "taskType")
427
- seq = _sequence(manifest, "workerResults")
428
- return run_dir / "worker-results" / f"{worker_id}-worker-errors-{task_type}-{seq}.json"
429
-
430
-
431
- def _run_directory_path(project_root: Path, manifest: Mapping[str, Any]) -> Path:
432
- value = _string_value(manifest.get("runDirectoryPath"))
433
- if value:
434
- return _resolve_project_path(project_root, value)
435
- return _resolve_required_path(project_root, manifest, "teamStatePath", "team-state").parent.parent
436
-
437
-
438
- def _sequence(manifest: Mapping[str, Any], key: str) -> str:
439
- seqs = manifest.get("runSequencesByCategory")
440
- if not isinstance(seqs, Mapping):
441
- return _run_seq(manifest)
442
- return _string_value(seqs.get(key)) or _run_seq(manifest)
443
- ```
444
-
445
- - [ ] **Step 4: Run Codex focused tests**
446
-
447
- Run:
448
-
449
- ```bash
450
- python3 -m pytest tests/test_worker_prompt_headers.py tests/test_codex_dispatch.py -q
451
- ```
452
-
453
- Expected: all tests pass.
454
-
455
- - [ ] **Step 5: Commit Task 2**
456
-
457
- Run:
458
-
459
- ```bash
460
- git add scripts/okstra_ctl/codex_dispatch.py tests/test_codex_dispatch.py
461
- git commit -m "fix(dispatch): resolve codex preamble from runtime home"
462
- ```
463
-
464
- ---
465
-
466
- ### Task 3: Make Dispatch Core Fallback Prompts Contract-Compliant
467
-
468
- **Files:**
469
- - Modify: `scripts/okstra_ctl/dispatch_core.py:14-16`
470
- - Modify: `scripts/okstra_ctl/dispatch_core.py:281-297`
471
- - Modify: `scripts/okstra_ctl/dispatch_core.py:751-779`
472
- - Modify: `tests/test_dispatch_core.py:11-44`
473
-
474
- - [ ] **Step 1: Replace fallback prompt tests with contract-header assertions**
475
-
476
- Replace `tests/test_dispatch_core.py:11-44` with:
477
-
478
- ```python
479
- def test_materialize_prompt_writes_contract_anchor_headers(
480
- tmp_path: Path, monkeypatch
481
- ) -> None:
482
- runtime_home = tmp_path / "runtime-home"
483
- monkeypatch.setenv("OKSTRA_HOME", str(runtime_home))
484
- project_root = tmp_path / "project"
485
- prompt_path = project_root / "prompts" / "claude-worker-prompt.md"
486
- manifest = {
487
- "taskType": "error-analysis",
488
- "runDirectoryPath": ".okstra/tasks/group/task/runs/error-analysis",
489
- "runSequencesByCategory": {
490
- "state": "001",
491
- "workerResults": "001",
492
- },
493
- }
494
- active_context = {
495
- "runtimeResources": {
496
- "codingPreflightDir": "/tmp/rt/prompts/coding-preflight",
497
- },
498
- "errorLogs": {
499
- "runErrorsLogPath": ".okstra/run/logs/errors.jsonl",
500
- "sidecarsByWorkerId": {
501
- "claude": ".okstra/run/worker-results/claude-errors.json",
502
- },
503
- },
504
- }
505
-
506
- dispatch_core._materialize_prompt_if_missing(
507
- prompt_path=prompt_path,
508
- prompt_rel="prompts/claude-worker-prompt.md",
509
- worker_id="claude",
510
- result_rel="worker-results/claude.md",
511
- project_root=project_root,
512
- manifest=manifest,
513
- active_context=active_context,
514
- )
515
-
516
- lines = prompt_path.read_text(encoding="utf-8").splitlines()
517
- assert lines[:8] == [
518
- f"**Project Root:** {project_root}",
519
- "**Prompt History Path:** prompts/claude-worker-prompt.md",
520
- "**Result Path:** worker-results/claude.md",
521
- f"Assigned worker prompt history path: {prompt_path}",
522
- f"**Worker Preamble Path:** {runtime_home / 'templates' / 'worker-prompt-preamble.md'}",
523
- "**Coding preflight pack:** /tmp/rt/prompts/coding-preflight",
524
- f"**Errors log path:** {project_root / '.okstra/run/logs/errors.jsonl'}",
525
- f"**Errors sidecar path:** {project_root / '.okstra/run/worker-results/claude-errors.json'}",
526
- ]
527
- assert not lines[0].startswith("#")
528
-
529
-
530
- def test_materialize_prompt_falls_back_to_okstra_home_and_manifest_paths(
531
- tmp_path: Path, monkeypatch
532
- ) -> None:
533
- runtime_home = tmp_path / "custom-home"
534
- monkeypatch.setenv("OKSTRA_HOME", str(runtime_home))
535
- project_root = tmp_path / "project"
536
- prompt_path = project_root / "prompts" / "claude-worker-prompt.md"
537
-
538
- dispatch_core._materialize_prompt_if_missing(
539
- prompt_path=prompt_path,
540
- prompt_rel="prompts/claude-worker-prompt.md",
541
- worker_id="claude",
542
- result_rel="worker-results/claude.md",
543
- project_root=project_root,
544
- manifest={
545
- "taskType": "implementation",
546
- "runDirectoryPath": ".okstra/tasks/group/task/runs/implementation/stage-1",
547
- "runSequencesByCategory": {
548
- "state": "003",
549
- "workerResults": "003",
550
- },
551
- },
552
- active_context={},
553
- )
554
-
555
- text = prompt_path.read_text(encoding="utf-8")
556
- assert f"**Worker Preamble Path:** {runtime_home / 'templates' / 'worker-prompt-preamble.md'}" in text
557
- assert f"**Coding preflight pack:** {runtime_home / 'prompts' / 'coding-preflight'}" in text
558
- assert (
559
- f"**Errors log path:** {project_root / '.okstra/tasks/group/task/runs/implementation/stage-1/logs/errors-implementation-003.jsonl'}"
560
- in text
561
- )
562
- assert (
563
- f"**Errors sidecar path:** {project_root / '.okstra/tasks/group/task/runs/implementation/stage-1/worker-results/claude-worker-errors-implementation-003.json'}"
564
- in text
565
- )
566
- ```
567
-
568
- - [ ] **Step 2: Run dispatch-core tests and verify they fail on signature/header mismatch**
569
-
570
- Run:
571
-
572
- ```bash
573
- python3 -m pytest tests/test_dispatch_core.py -q
574
- ```
575
-
576
- Expected: fail because `_materialize_prompt_if_missing()` does not accept `prompt_rel`, `result_rel`, or `manifest`, and its prompt starts with a Markdown heading.
577
-
578
- - [ ] **Step 3: Wire dispatch core to shared helper**
579
-
580
- In `scripts/okstra_ctl/dispatch_core.py`, replace imports near lines 13-16 with:
581
-
582
- ```python
583
- from . import tmux
584
- from .lead_events import LeadEvent, append_lead_event
585
- from .worker_prompt_headers import worker_prompt_headers
586
- from .wrapper_status import read_wrapper_status, status_path_for_prompt
587
- ```
588
-
589
- In `_job_from_roster_worker()`, replace lines 291-296 with:
590
-
591
- ```python
592
- state = _worker_state(team_state, worker_id)
593
- provider = _provider_for_worker(worker_id)
594
- model = _model_for_worker(worker_id, state, report_writer_model)
595
- prompt_rel = _worker_prompt_path(manifest, worker_id)
596
- result_rel = _require_string(state, "resultPath")
597
- prompt_path = _resolve_project_path(project_root, prompt_rel)
598
- result_path = _resolve_project_path(project_root, result_rel)
599
- _materialize_prompt_if_missing(
600
- prompt_path=prompt_path,
601
- prompt_rel=prompt_rel,
602
- worker_id=worker_id,
603
- result_rel=result_rel,
604
- project_root=project_root,
605
- manifest=manifest,
606
- active_context=active_context,
607
- )
608
- ```
609
-
610
- Delete local `_coding_preflight_pack_path()` from `dispatch_core.py`.
611
-
612
- Replace `_materialize_prompt_if_missing()` with:
613
-
614
- ```python
615
- def _materialize_prompt_if_missing(
616
- *,
617
- prompt_path: Path,
618
- prompt_rel: str,
619
- worker_id: str,
620
- result_rel: str,
621
- project_root: Path,
622
- manifest: Mapping[str, Any],
623
- active_context: Mapping[str, Any],
624
- ) -> None:
625
- if prompt_path.is_file():
626
- return
627
- prompt_path.parent.mkdir(parents=True, exist_ok=True)
628
- prompt_path.write_text(
629
- "\n".join([
630
- *worker_prompt_headers(
631
- project_root=project_root,
632
- prompt_rel=prompt_rel,
633
- result_rel=result_rel,
634
- worker_id=worker_id,
635
- manifest=manifest,
636
- active_context=active_context,
637
- ),
638
- "",
639
- ]),
640
- encoding="utf-8",
641
- )
642
- ```
643
-
644
- - [ ] **Step 4: Run dispatch-core and Codex tests together**
645
-
646
- Run:
647
-
648
- ```bash
649
- python3 -m pytest tests/test_worker_prompt_headers.py tests/test_dispatch_core.py tests/test_codex_dispatch.py -q
650
- ```
651
-
652
- Expected: all tests pass.
653
-
654
- - [ ] **Step 5: Commit Task 3**
655
-
656
- Run:
657
-
658
- ```bash
659
- git add scripts/okstra_ctl/dispatch_core.py tests/test_dispatch_core.py
660
- git commit -m "fix(dispatch): materialize full fallback prompt anchors"
661
- ```
662
-
663
- ---
664
-
665
- ### Task 4: Add Contract Guards and User-Visible Change Note
666
-
667
- **Files:**
668
- - Modify: `tests/test_docs_runtime_contract.py`
669
- - Modify: `CHANGES.md:19-23`
670
-
671
- - [ ] **Step 1: Add a contract test that blocks prompt materializer default-home literals**
672
-
673
- Append this test after `test_worker_prompt_contract_carries_coding_preflight_pack_anchor()` in `tests/test_docs_runtime_contract.py`:
674
-
675
- ```python
676
- def test_prompt_materializers_do_not_hardcode_default_runtime_home():
677
- forbidden_literals = [
678
- 'Path.home() / ".okstra" / "templates" / "worker-prompt-preamble.md"',
679
- 'Path.home() / ".okstra" / "prompts" / "coding-preflight"',
680
- ]
681
- for relative_path in [
682
- "scripts/okstra_ctl/codex_dispatch.py",
683
- "scripts/okstra_ctl/dispatch_core.py",
684
- ]:
685
- text = _read_doc(relative_path)
686
- for literal in forbidden_literals:
687
- assert literal not in text, f"{relative_path}: {literal}"
688
- ```
689
-
690
- - [ ] **Step 2: Run the contract test before the source changes from Tasks 2-3 are present**
691
-
692
- Run:
693
-
694
- ```bash
695
- python3 -m pytest tests/test_docs_runtime_contract.py::test_prompt_materializers_do_not_hardcode_default_runtime_home -q
696
- ```
697
-
698
- Expected before Task 2 source changes: fail on `scripts/okstra_ctl/codex_dispatch.py` containing the default preamble literal. Expected after Task 2 and Task 3: pass.
699
-
700
- - [ ] **Step 3: Update the `fix(dispatch)` entry in `CHANGES.md`**
701
-
702
- Replace `CHANGES.md:22` with:
703
-
704
- ```markdown
705
- - **해결**: `paths.py` 가 이미 계산하는 `OKSTRA_CODING_PREFLIGHT_DIR` 을 machine-readable active-run-context 에 `runtimeResources.codingPreflightDir` 로 승격하고, 모든 worker prompt 앵커 헤더에 `**Coding preflight pack:** <절대경로>`(Worker Preamble Path 다음, error-log 헤더 앞, header #6)를 추가했다. deterministic dispatcher(`codex_dispatch.py`, `dispatch_core.py`)는 shared anchor renderer 로 `Worker Preamble Path` 와 `Coding preflight pack` 을 같은 `OKSTRA_HOME` 기준으로 주입하고, fallback prompt 도 `team-contract` 의 8줄 anchor header block 으로 시작한다.
706
- ```
707
-
708
- - [ ] **Step 4: Run docs contract tests**
709
-
710
- Run:
711
-
712
- ```bash
713
- python3 -m pytest tests/test_docs_runtime_contract.py -q
714
- ```
715
-
716
- Expected: all tests pass.
717
-
718
- - [ ] **Step 5: Commit Task 4**
719
-
720
- Run:
721
-
722
- ```bash
723
- git add tests/test_docs_runtime_contract.py CHANGES.md
724
- git commit -m "test(dispatch): guard worker prompt anchor paths"
725
- ```
726
-
727
- ---
728
-
729
- ### Task 5: Final Verification
730
-
731
- **Files:**
732
- - Verify: `runtime/`
733
- - Verify: graphify output, if `graphify` is available in the environment
734
-
735
- - [ ] **Step 1: Run focused Python tests**
736
-
737
- Run:
738
-
739
- ```bash
740
- python3 -m pytest tests/test_worker_prompt_headers.py tests/test_codex_dispatch.py tests/test_dispatch_core.py tests/test_docs_runtime_contract.py -q
741
- ```
742
-
743
- Expected: all selected tests pass.
744
-
745
- - [ ] **Step 2: Build runtime**
746
-
747
- Run:
748
-
749
- ```bash
750
- npm run build
751
- ```
752
-
753
- Expected: build exits 0 and reports sources synced into `runtime/`.
754
-
755
- - [ ] **Step 3: Run full project check**
756
-
757
- Run:
758
-
759
- ```bash
760
- npm run check
761
- ```
762
-
763
- Expected: JS tests, Python tests, and workflow validator all pass.
764
-
765
- - [ ] **Step 4: Run a runtime-home smoke for Codex prompt materialization**
766
-
767
- Run:
768
-
769
- ```bash
770
- PYTHONPATH=scripts OKSTRA_HOME=/tmp/okstra-custom python3 -c 'from pathlib import Path
771
- from okstra_ctl.codex_dispatch import _base_prompt_headers
772
- manifest = {}
773
- active_context = {"runtimeResources": {"codingPreflightDir": "/tmp/okstra-custom/prompts/coding-preflight"}, "errorLogs": {"runErrorsLogPath": ".okstra/run/logs/errors.jsonl", "sidecarsByWorkerId": {"codex": ".okstra/run/results/codex-errors.json"}}}
774
- headers = _base_prompt_headers(project_root=Path("/project"), manifest=manifest, active_context=active_context, worker_id="codex", prompt_rel=".okstra/run/prompts/codex.md", result_rel=".okstra/run/results/codex.md")
775
- assert "**Worker Preamble Path:** /tmp/okstra-custom/templates/worker-prompt-preamble.md" in headers
776
- assert "**Coding preflight pack:** /tmp/okstra-custom/prompts/coding-preflight" in headers
777
- print("codex runtime anchors ok")'
778
- ```
779
-
780
- Expected: prints `codex runtime anchors ok`.
781
-
782
- - [ ] **Step 5: Verify runtime surface still exposes only public skills and installed resources**
783
-
784
- Run:
785
-
786
- ```bash
787
- node --input-type=module -e "
788
- import assert from 'node:assert/strict';
789
- import { readdirSync, existsSync } from 'node:fs';
790
- import { join } from 'node:path';
791
- import { USER_SKILL_NAMES, OBSOLETE_INTERNAL_SKILL_NAMES } from './src/skill-catalog.mjs';
792
- const names = readdirSync('runtime/skills', { withFileTypes: true })
793
- .filter((entry) => entry.isDirectory())
794
- .map((entry) => entry.name)
795
- .sort();
796
- assert.deepEqual(names, [...USER_SKILL_NAMES].sort());
797
- for (const name of OBSOLETE_INTERNAL_SKILL_NAMES) {
798
- assert.equal(existsSync(join('runtime/skills', name)), false, name);
799
- }
800
- assert.equal(existsSync('runtime/prompts/lead/okstra-lead-contract.md'), true);
801
- assert.equal(existsSync('runtime/prompts/coding-preflight/overview.md'), true);
802
- assert.equal(existsSync('runtime/prompts/coding-preflight/languages/python.md'), true);
803
- console.log('runtime surface ok');
804
- "
805
- ```
806
-
807
- Expected: prints `runtime surface ok`.
808
-
809
- - [ ] **Step 6: Refresh graphify output after code changes**
810
-
811
- Run:
812
-
813
- ```bash
814
- graphify update .
815
- ```
816
-
817
- Expected: command exits 0 and refreshes `graphify-out/` for the changed Python dispatch modules.
818
-
819
- - [ ] **Step 7: Commit final build artifacts if runtime changed**
820
-
821
- Run:
822
-
823
- ```bash
824
- git add runtime graphify-out
825
- git commit -m "build: refresh runtime prompt dispatch assets"
826
- ```
827
-
828
- If `runtime/` or `graphify-out/` has no changes, skip this commit and record that there was no generated output to commit.