okstra 0.102.2 → 0.102.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.kr.md +5 -5
- package/README.md +5 -5
- package/docs/kr/architecture/storage-model.md +8 -3
- package/docs/kr/architecture.md +12 -13
- package/docs/kr/cli.md +4 -4
- package/docs/kr/container.md +1 -1
- package/docs/kr/performance-improvement-plan-v2.md +2 -2
- package/docs/project-structure-overview.md +2 -2
- package/package.json +7 -2
- package/runtime/BUILD.json +2 -2
- package/runtime/bin/lib/okstra/interactive.sh +12 -0
- package/runtime/bin/okstra-antigravity-exec.sh +1 -2
- package/runtime/bin/okstra-codex-exec.sh +1 -2
- package/runtime/bin/okstra-render-final-report.py +2 -9
- package/runtime/bin/okstra-spawn-followups.py +4 -6
- package/runtime/bin/okstra-trace-cleanup.sh +24 -4
- package/runtime/prompts/lead/okstra-lead-contract.md +2 -2
- package/runtime/prompts/lead/report-writer.md +1 -1
- package/runtime/prompts/profiles/_common-contract.md +9 -11
- package/runtime/python/okstra_ctl/codex_dispatch.py +6 -13
- package/runtime/python/okstra_ctl/consumers.py +35 -0
- package/runtime/python/okstra_ctl/container.py +4 -6
- package/runtime/python/okstra_ctl/dispatch_core.py +8 -13
- package/runtime/python/okstra_ctl/final_report_paths.py +24 -0
- package/runtime/python/okstra_ctl/handoff.py +2 -1
- package/runtime/python/okstra_ctl/implementation_outcome.py +271 -0
- package/runtime/python/okstra_ctl/implementation_stage.py +7 -11
- package/runtime/python/okstra_ctl/path_hints.py +665 -0
- package/runtime/python/okstra_ctl/render.py +4 -3
- package/runtime/python/okstra_ctl/report_view_artifacts.py +14 -0
- package/runtime/python/okstra_ctl/report_views.py +7 -4
- package/runtime/python/okstra_ctl/run.py +3 -10
- package/runtime/python/okstra_ctl/run_context.py +4 -2
- package/runtime/python/okstra_ctl/stage_targets.py +18 -0
- package/runtime/python/okstra_ctl/wizard.py +37 -26
- package/runtime/python/okstra_ctl/wizard_stage_intent.py +54 -0
- package/runtime/python/okstra_project/state.py +40 -2
- package/runtime/python/okstra_token_usage/report.py +2 -5
- package/runtime/validators/validate-report-views.py +2 -1
- package/runtime/validators/validate-run.py +1 -11
- package/src/commands/lifecycle/install.mjs +5 -5
- package/src/commands/lifecycle/uninstall.mjs +4 -4
- package/docs/superpowers/plans/2026-05-12-ticket-id-in-reports.md +0 -638
- package/docs/superpowers/plans/2026-05-14-convergence-queue-pruning.md +0 -1568
- package/docs/superpowers/plans/2026-05-17-dual-format-final-report.md +0 -167
- package/docs/superpowers/plans/2026-05-20-final-report-language.md +0 -1501
- package/docs/superpowers/plans/2026-05-20-implementation-planning-multi-stage.md +0 -1267
- package/docs/superpowers/plans/2026-05-20-okstra-run-prompt-sot-b1.md +0 -1007
- package/docs/superpowers/plans/2026-05-20-wizard-messages-json-sot.md +0 -720
- package/docs/superpowers/plans/2026-05-20-wizard-prompt-json-sot-a1.md +0 -681
- package/docs/superpowers/plans/2026-05-21-improvement-discovery-task-type.md +0 -1691
- package/docs/superpowers/plans/2026-05-24-implementation-lead-context-slimming.md +0 -1700
- package/docs/superpowers/plans/2026-05-25-okstra-project-root-rename.md +0 -158
- package/docs/superpowers/plans/2026-05-26-wizard-3-option-picker.md +0 -860
- package/docs/superpowers/plans/2026-06-02-final-verification-protocol-hardening.md +0 -326
- package/docs/superpowers/plans/2026-06-02-okstra-run-branch-confirm-step.md +0 -337
- package/docs/superpowers/plans/2026-06-02-okstra-run-phase-pane-cleanup.md +0 -410
- package/docs/superpowers/plans/2026-06-02-requirements-discovery-fanout.md +0 -728
- package/docs/superpowers/plans/2026-06-04-adversarial-implementation-planning.md +0 -294
- package/docs/superpowers/plans/2026-06-04-adversarial-verification.md +0 -570
- package/docs/superpowers/plans/2026-06-04-coverage-critic.md +0 -516
- package/docs/superpowers/plans/2026-06-04-stage-cohesion-planner.md +0 -351
- package/docs/superpowers/plans/2026-06-04-stage-run-batching.md +0 -457
- package/docs/superpowers/plans/2026-06-05-acceptance-critic.md +0 -251
- package/docs/superpowers/plans/2026-06-05-compact-markdown-report-tables.md +0 -323
- package/docs/superpowers/plans/2026-06-05-wizard-batch-prompts.md +0 -559
- package/docs/superpowers/plans/2026-06-06-final-verification-whole-task-gate.md +0 -993
- package/docs/superpowers/plans/2026-06-06-stage-parallel-and-pending-fixes.md +0 -93
- package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p1.md +0 -447
- package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p2.md +0 -289
- package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p3.md +0 -774
- package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p4.md +0 -303
- package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p5-multidep-base.md +0 -387
- package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase2.md +0 -275
- package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase3.md +0 -282
- package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4a.md +0 -147
- package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4b.md +0 -262
- package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4c.md +0 -184
- package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4d.md +0 -88
- package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4e.md +0 -250
- package/docs/superpowers/plans/2026-06-07-stage-conformance-qa.md +0 -409
- package/docs/superpowers/plans/2026-06-09-implementation-run-artifact-stage-isolation.md +0 -320
- package/docs/superpowers/plans/2026-06-10-concurrent-run-team-guard.md +0 -456
- package/docs/superpowers/plans/2026-06-10-git-reconcile-stale-sha-recovery.md +0 -1408
- package/docs/superpowers/plans/2026-06-10-lead-worker-completion-polling-PROBE.md +0 -42
- package/docs/superpowers/plans/2026-06-10-lead-worker-completion-polling.md +0 -337
- package/docs/superpowers/plans/2026-06-10-p6-token-usage-incremental.md +0 -1029
- package/docs/superpowers/plans/2026-06-10-stage-group-handoff.md +0 -1572
- package/docs/superpowers/plans/2026-06-11-fix-cycle.md +0 -1290
- package/docs/superpowers/plans/2026-06-11-wizard-whole-task-final-verification.md +0 -526
- package/docs/superpowers/plans/2026-06-12-html-plan-approval.md +0 -1000
- package/docs/superpowers/plans/2026-06-13-repo-risk-hardening.md +0 -493
- package/docs/superpowers/plans/2026-06-14-host-runtime-auto-execution.md +0 -1775
- package/docs/superpowers/plans/2026-06-15-coding-preflight-pack-dispatch-path.md +0 -504
- package/docs/superpowers/plans/2026-06-15-internal-skill-migration-final-fixups.md +0 -342
- package/docs/superpowers/plans/2026-06-15-internal-skill-migration-fixups.md +0 -258
- package/docs/superpowers/plans/2026-06-15-internal-skill-migration-remaining-fixups.md +0 -387
- package/docs/superpowers/plans/2026-06-15-internal-skill-resource-migration.md +0 -749
- package/docs/superpowers/plans/2026-06-15-worker-prompt-anchor-final-fixups.md +0 -828
- package/docs/superpowers/plans/2026-06-15-worker-prompt-header-error-contract.md +0 -490
- package/docs/superpowers/plans/2026-06-17-okstra-error-report.md +0 -724
- package/docs/superpowers/plans/2026-06-18-subagent-pane-reclaim.md +0 -483
- package/docs/superpowers/plans/2026-06-19-agent-operating-standard.md +0 -476
- package/docs/superpowers/plans/2026-06-19-okstra-inspect-recap-facet.md +0 -647
- package/docs/superpowers/plans/2026-06-20-error-feedback-loop.md +0 -1019
- package/docs/superpowers/plans/2026-06-20-run-index-row-normalization.md +0 -583
- package/docs/superpowers/plans/2026-06-20-stage-auto-integrate-teardown.md +0 -819
- package/docs/superpowers/plans/2026-06-21-okstra-container-local-user-test.md +0 -714
- package/docs/superpowers/plans/2026-06-21-release-handoff-local-checkout.md +0 -348
- package/docs/superpowers/plans/2026-06-23-implementation-stage-multiselect-chain.md +0 -630
- package/docs/superpowers/plans/2026-06-23-implementation-step-commit-granularity.md +0 -274
- package/docs/superpowers/plans/2026-06-23-phase-batch-cleanup-enforcement.md +0 -409
- package/docs/superpowers/plans/2026-06-24-cross-project-precondition.md +0 -542
- package/docs/superpowers/plans/2026-06-24-decision-drafts-render-gap.md +0 -568
- package/docs/superpowers/plans/2026-06-24-manual-user-test-section.md +0 -203
- package/docs/superpowers/plans/2026-06-24-okstra-container-build-rename.md +0 -525
- package/docs/superpowers/specs/2026-05-12-ticket-id-in-reports-design.md +0 -131
- package/docs/superpowers/specs/2026-05-15-implementation-plan-verification-design.md +0 -254
- package/docs/superpowers/specs/2026-05-20-final-report-language-design.md +0 -383
- package/docs/superpowers/specs/2026-05-20-implementation-planning-multi-stage-design.md +0 -322
- package/docs/superpowers/specs/2026-05-20-okstra-run-prompt-sot-design.md +0 -299
- package/docs/superpowers/specs/2026-05-21-improvement-discovery-task-type-design.md +0 -335
- package/docs/superpowers/specs/2026-06-02-okstra-run-branch-confirm-step-design.md +0 -113
- package/docs/superpowers/specs/2026-06-02-okstra-run-phase-pane-cleanup-design.md +0 -173
- package/docs/superpowers/specs/2026-06-02-requirements-discovery-fanout-design.md +0 -154
- package/docs/superpowers/specs/2026-06-04-adversarial-implementation-planning-design.md +0 -90
- package/docs/superpowers/specs/2026-06-04-adversarial-verification-design.md +0 -176
- package/docs/superpowers/specs/2026-06-04-coverage-critic-design.md +0 -99
- package/docs/superpowers/specs/2026-06-04-stage-splitting-cost-aware-design.md +0 -98
- package/docs/superpowers/specs/2026-06-05-acceptance-critic-design.md +0 -90
- package/docs/superpowers/specs/2026-06-05-compact-markdown-report-tables-design.md +0 -87
- package/docs/superpowers/specs/2026-06-05-wizard-batch-prompts-design.md +0 -121
- package/docs/superpowers/specs/2026-06-06-final-verification-whole-task-gate-design.md +0 -126
- package/docs/superpowers/specs/2026-06-06-stage-worktree-isolation-design.md +0 -180
- package/docs/superpowers/specs/2026-06-06-vertical-slice-tdd-planning-design.md +0 -179
- package/docs/superpowers/specs/2026-06-07-stage-conformance-qa-design.md +0 -169
- package/docs/superpowers/specs/2026-06-09-executor-model-custom-id-cascade-design.md +0 -66
- package/docs/superpowers/specs/2026-06-09-implementation-run-artifact-stage-isolation-design.md +0 -87
- package/docs/superpowers/specs/2026-06-10-blocking-contract-posthoc-conformance-design.md +0 -168
- package/docs/superpowers/specs/2026-06-10-concurrent-run-team-guard-design.md +0 -107
- package/docs/superpowers/specs/2026-06-10-git-reconcile-stale-sha-recovery-design.md +0 -105
- package/docs/superpowers/specs/2026-06-10-lead-worker-completion-polling-design.md +0 -113
- package/docs/superpowers/specs/2026-06-10-stage-group-handoff-design.md +0 -156
- package/docs/superpowers/specs/2026-06-11-brief-entry-only-handoff-stage-entry-design.md +0 -158
- package/docs/superpowers/specs/2026-06-11-fix-cycle-design.md +0 -94
- package/docs/superpowers/specs/2026-06-11-wizard-whole-task-final-verification-design.md +0 -89
- package/docs/superpowers/specs/2026-06-12-codex-lead-adapter-design.md +0 -358
- package/docs/superpowers/specs/2026-06-12-html-plan-approval-design.md +0 -85
- package/docs/superpowers/specs/2026-06-12-stage-discipline-rule-design.md +0 -108
- package/docs/superpowers/specs/2026-06-13-forbidden-actions-ssot-design.md +0 -134
- package/docs/superpowers/specs/2026-06-13-neutral-tmux-lead-adapter-design.md +0 -284
- package/docs/superpowers/specs/2026-06-14-host-runtime-auto-execution-design.md +0 -404
- package/docs/superpowers/specs/2026-06-17-okstra-error-report-design.md +0 -123
- package/docs/superpowers/specs/2026-06-18-subagent-pane-reclaim-design.md +0 -150
- package/docs/superpowers/specs/2026-06-19-agent-operating-standard-design.md +0 -120
- package/docs/superpowers/specs/2026-06-19-okstra-inspect-recap-facet-design.md +0 -96
- package/docs/superpowers/specs/2026-06-20-error-feedback-loop-design.md +0 -171
- package/docs/superpowers/specs/2026-06-20-run-index-row-normalization-design.md +0 -112
- package/docs/superpowers/specs/2026-06-20-stage-auto-integrate-teardown-design.md +0 -145
- package/docs/superpowers/specs/2026-06-21-okstra-container-local-user-test-design.md +0 -125
- package/docs/superpowers/specs/2026-06-21-release-handoff-local-checkout-design.md +0 -113
- package/docs/superpowers/specs/2026-06-23-implementation-stage-multiselect-chain-design.md +0 -138
- package/docs/superpowers/specs/2026-06-23-implementation-step-commit-granularity-design.md +0 -120
- package/docs/superpowers/specs/2026-06-24-cross-project-precondition-design.md +0 -129
- package/docs/superpowers/specs/2026-06-24-decision-drafts-render-gap-design.md +0 -185
- package/docs/superpowers/specs/2026-06-24-manual-user-test-section-design.md +0 -121
- package/docs/superpowers/specs/2026-06-24-okstra-container-build-rename-design.md +0 -110
|
@@ -1,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.
|