okstra 0.127.0 → 0.129.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/docs/architecture/storage-model.md +23 -3
  2. package/docs/architecture.md +28 -1
  3. package/docs/cli.md +9 -0
  4. package/docs/project-structure-overview.md +17 -7
  5. package/package.json +1 -1
  6. package/runtime/BUILD.json +2 -2
  7. package/runtime/agents/workers/antigravity-worker.md +3 -3
  8. package/runtime/agents/workers/claude-worker.md +4 -4
  9. package/runtime/agents/workers/codex-worker.md +3 -3
  10. package/runtime/agents/workers/report-writer-worker.md +5 -5
  11. package/runtime/prompts/lead/adapters/claude-code.md +2 -1
  12. package/runtime/prompts/lead/adapters/codex.md +1 -0
  13. package/runtime/prompts/lead/adapters/external.md +1 -0
  14. package/runtime/prompts/lead/convergence.md +45 -83
  15. package/runtime/prompts/lead/okstra-lead-contract.md +12 -8
  16. package/runtime/prompts/lead/report-writer.md +3 -2
  17. package/runtime/prompts/lead/team-contract.md +19 -9
  18. package/runtime/prompts/profiles/_common-contract.md +1 -1
  19. package/runtime/prompts/profiles/error-analysis.md +1 -1
  20. package/runtime/prompts/profiles/final-verification.md +10 -6
  21. package/runtime/prompts/profiles/implementation-planning.md +5 -0
  22. package/runtime/prompts/profiles/improvement-discovery.md +11 -1
  23. package/runtime/prompts/profiles/requirements-discovery.md +8 -1
  24. package/runtime/python/okstra_ctl/analysis_packet.py +14 -15
  25. package/runtime/python/okstra_ctl/codex_dispatch.py +51 -80
  26. package/runtime/python/okstra_ctl/context_cost.py +82 -7
  27. package/runtime/python/okstra_ctl/convergence.py +223 -0
  28. package/runtime/python/okstra_ctl/convergence_engine.py +1152 -0
  29. package/runtime/python/okstra_ctl/convergence_migration.py +184 -0
  30. package/runtime/python/okstra_ctl/convergence_store.py +85 -0
  31. package/runtime/python/okstra_ctl/dispatch_core.py +60 -1
  32. package/runtime/python/okstra_ctl/improvement_assignment.py +61 -0
  33. package/runtime/python/okstra_ctl/log_report.py +44 -5
  34. package/runtime/python/okstra_ctl/path_hints.py +28 -1
  35. package/runtime/python/okstra_ctl/paths.py +10 -1
  36. package/runtime/python/okstra_ctl/render.py +78 -11
  37. package/runtime/python/okstra_ctl/run.py +66 -2
  38. package/runtime/python/okstra_ctl/wizard.py +15 -4
  39. package/runtime/python/okstra_ctl/work_categories.py +37 -0
  40. package/runtime/python/okstra_ctl/worker_prompt_body.py +107 -0
  41. package/runtime/python/okstra_ctl/worker_prompt_contract.py +316 -0
  42. package/runtime/python/okstra_ctl/worker_prompt_headers.py +109 -10
  43. package/runtime/python/okstra_ctl/worker_prompt_policy.py +158 -0
  44. package/runtime/templates/implementation-worker-preamble.md +51 -0
  45. package/runtime/templates/operating-standard.md +4 -4
  46. package/runtime/templates/report-writer-prompt-preamble.md +37 -0
  47. package/runtime/templates/worker-error-contract.md +46 -0
  48. package/runtime/templates/worker-prompt-preamble.md +28 -227
  49. package/runtime/validators/lib/fixtures.sh +27 -12
  50. package/runtime/validators/validate-run.py +228 -45
  51. package/src/cli-registry.mjs +7 -0
  52. package/src/commands/execute/convergence.mjs +34 -0
  53. package/src/commands/inspect/log-report.mjs +5 -3
@@ -0,0 +1,37 @@
1
+ # Report Writer Prompt Preamble (canonical)
2
+
3
+ This file is the audience-specific contract for `report-writer`. Read it end-to-end. Before work, also read the shared file named by `**Worker Error Contract Path:**`; error rules live only there.
4
+
5
+ ## Operating standard (read before any output)
6
+
7
+ Work like a senior engineer who owns this result, not a commentator on it.
8
+ - Evidence over assertion — back every claim with a file:line, or mark it an explicit assumption. Never state the unverified as fact.
9
+ - Read before you reason — read each required input end to end; when you lack basis, write "insufficient evidence" instead of filling the gap plausibly.
10
+ - Shortest sound path — chase the most likely cause first; don't re-verify what is settled or pad with restatement.
11
+ - Decide, don't survey — when options exist, give the trade-off and one recommendation, not an exhaustive list.
12
+ - Fit what's here — match the surrounding code and prose; size the response to the request.
13
+
14
+ ## Required reading
15
+
16
+ Read every input enumerated by the Phase 6 dispatch end-to-end: task/analysis inputs, worker results, convergence state, the instruction-set-local `final-report-template.md`, and the task-type excerpt `final-report-schema.json`. Do not pull the full repository template or schema when the scoped instruction-set copies are provided.
17
+
18
+ Write Reading Confirmation to the report-writer audit sidecar, not the rendered final report. Resolve `.okstra/**` paths against `**Project Root:**`.
19
+
20
+ ## Report authoring handoff
21
+
22
+ - Author the data.json at `**Result Path:**` and the audit file at `**Worker Result Path:**`.
23
+ - Follow the task-type schema excerpt and Phase 6 report-writer contract. Do not perform independent analysis, edit source code, or load implementation coding-preflight resources.
24
+ - Invoke `okstra render-final-report <Result Path>` after writing data.json and verify the markdown sibling exists before returning.
25
+ - Preserve source item IDs, convergence classifications, round history, and unresolved dissent; do not recompute them from intuition.
26
+
27
+ ## Anchor headers
28
+
29
+ The generated prompt selects this file through `**Worker Preamble Path:**` and includes `**Worker Error Contract Path:**`, error paths, and read scope. It never includes `**Coding preflight pack:**`.
30
+
31
+ ## Return message to the lead
32
+
33
+ Begin the inline return with the exact `**Model:** Report writer worker, <modelExecutionValue>` line from the prompt, followed by the artifact status. Never invent or abbreviate the model.
34
+
35
+ ## Writing style
36
+
37
+ Use concise reader-facing prose and honor the report language. Keep identifiers, paths, symbols, model names, CLI flags, and status tokens in English. Translate meaning rather than dictionary words.
@@ -0,0 +1,46 @@
1
+ # Worker Error Contract (canonical)
2
+
3
+ This audience-neutral file is the single source of truth for every initial worker's error path, sidecar schema, and write protocol. Read it end-to-end from `**Worker Error Contract Path:**` before work.
4
+
5
+ ## Error reporting
6
+
7
+ Record a tool call only when its failure blocked the step you intended. A non-zero exit code is NOT by itself a failure to record. Do not record an entry when:
8
+
9
+ - a search/probe exits non-zero solely because it found no matches and work proceeds unaffected;
10
+ - an optional / expected-absent path is absent and detecting absence was the purpose;
11
+ - output was truncated but a later read covered the content end-to-end.
12
+
13
+ If the non-zero exit changed nothing about what you could do next, it is normal. When in doubt, record the real blocker: under-recording a real blocker is worse than one noisy entry.
14
+
15
+ If the sidecar does not exist when a real failure occurs, create `{"schemaVersion": 1, "errors": []}` and append one entry.
16
+
17
+ ### Entry schema
18
+
19
+ ```json
20
+ {
21
+ "ts": "<ISO 8601 UTC>",
22
+ "phase": "<current okstra phase>",
23
+ "errorType": "tool-failure",
24
+ "command": "<failed command/tool signature>",
25
+ "commandKind": "bash | tool:Read | tool:Edit | mcp | ...",
26
+ "exitCode": null,
27
+ "durationMs": null,
28
+ "message": "<one-line human summary>",
29
+ "stderrExcerpt": null,
30
+ "context": null
31
+ }
32
+ ```
33
+
34
+ ### Rules
35
+
36
+ - Do not add `source`, `recordedAt`, `agent`, `agentRole`, `model`, or `taskKey`; the lead supplies them when merging the sidecar.
37
+ - The sidecar accepts only `errorType: "tool-failure"`. CLI wrappers write `cli-failure` directly to the run log; the lead records `contract-violation`.
38
+ - Continue after recording unless the failure makes the task impossible.
39
+
40
+ ### Path extraction (BLOCKING)
41
+
42
+ Extract `**Errors log path:**` and `**Errors sidecar path:**` verbatim from the dispatch prompt. If either is absent, return the worker-specific `<SENTINEL_PREFIX>_ERRORS_PATH_MISSING` sentinel and stop. Never synthesize a path from a run-directory pattern.
43
+
44
+ ## Path anchoring
45
+
46
+ Every `.okstra/...` path is anchored at `**Project Root:**`, never at cwd. A task or stage worktree does **not** contain the project's `.okstra/` directory. Mutating project commands may use `**Worktree:**`, but okstra artifact reads and error writes use absolute paths resolved from Project Root. If a relative read fails in a worktree, re-anchor it to `<Project Root>` instead of retrying the same path.
@@ -1,8 +1,6 @@
1
- # Worker Prompt Preamble (canonical)
1
+ # Analysis Worker Prompt Preamble (canonical)
2
2
 
3
- This file is the single source of truth for the boilerplate that every okstra analysis worker, verifier, and report-writer worker must honour. The lead injects ONE anchor line into each dispatched worker prompt — `**Worker Preamble Path:** <abs-path>` pointing here. Workers Read this file end-to-end before producing any output.
4
-
5
- It replaces the previous practice of inlining ~80 lines of identical boilerplate into every worker prompt body.
3
+ This file is the audience-specific contract for initial `analysis` workers. Read it end-to-end from the path selected by the dispatch prompt. Before doing work, also read the shared file named by `**Worker Error Contract Path:**`; that file is the only source for error-sidecar rules.
6
4
 
7
5
  ## Operating standard (read before any output)
8
6
 
@@ -14,251 +12,54 @@ Work like a senior engineer who owns this result, not a commentator on it.
14
12
  - Fit what's here — match the surrounding code and prose; size the response to the request.
15
13
  - Hold your own line — reason from your independent angle; do not drift toward the other workers' likely answers or echo the user. Triangulation fails if your view isn't genuinely yours.
16
14
 
17
- ---
18
-
19
- ## Required reading (analysis workers + report-writer worker)
20
-
21
- You are required to read every primary input file enumerated by the dispatcher (the lead's prompt lists them under `[Required reading]`) from the very first character to the very last character before you produce any analysis output. Skimming, partial reads, jumping to a single section, or relying on prior knowledge of a similar file's structure is not acceptable. Source files listed as fallback/evidence paths are read on demand when you need to verify a citation, resolve ambiguity, or inspect material the packet says it omitted.
22
-
23
- ### Audience-scoped enumeration (performance optimization — mandatory)
15
+ ## Required reading
24
16
 
25
- Different recipients need different files. Do NOT include `final-report-template.md` in analysis worker prompts: analysis workers produce findings (not the final report), and forcing them to read the template inflates token usage without changing finding quality.
26
-
27
- | Recipient | Files included in `[Required reading]` |
28
- |---|---|
29
- | Claude / Codex / Antigravity analysis workers | analysis-packet.md as the primary compact input; task-brief, analysis-profile, analysis-material, reference-expectations, and clarification-response remain source/fallback paths, not automatic first-read files |
30
- | Report writer worker (Phase 6) | all of the above **plus** the instruction-set-local `final-report-template.md` (phase-stripped) and `final-report-schema.json` (per-task-type excerpt) — NOT the full `templates/reports/...` / `schemas/...` sources |
31
- | Reverify dispatches (Phase 5.5, lightweight mode) | **do NOT inject `[Required reading]` at all** — see [convergence](../prompts/lead/convergence.md) "Reverify prompt: required-reading suppression". |
17
+ Read `analysis-packet.md`, the primary compact input, end-to-end. Source files named as fallback/evidence paths are read only when a finding needs to verify a citation, fill a packet gap, or resolve ambiguity. Do not read `final-report-template.md` or `final-report-schema.json`; analysis workers produce findings, not the final report.
32
18
 
33
19
  ### Reading rules
34
20
 
35
- - Use a single `Read` tool call per file with no `offset` and no `limit`. If a file is genuinely too large for one read, page through with explicit `offset` / `limit` covering the entire file, and state the page boundaries in your Findings.
36
- - For the carry-in clarification response, walk every row of `## 1. Clarification Items` (`C-001`, `C-002`, ...) in full, including rows whose `User input` cell is blank — a blank `User input` with `Status=open` is itself a signal you must surface. The structural similarity between the prior final report and the upcoming output is NOT a license to skim.
37
- - Write the Reading Confirmation block to your **audit sidecar** at `runs/<task-type>/worker-results/<worker>-audit-<task-type>-<seq>.md` (sibling to the main worker-results file). One short line per input file confirming end-to-end reading. Do NOT include a `## 0. Reading Confirmation` heading in the main worker-results file — the validator fails worker-results that contain one. If you cannot truthfully confirm a file end-to-end, record a `tool-failure` in the errors sidecar instead of fabricating Findings.
38
- - The audit sidecar carries any other meta the worker wants to log (tool-call counts, MCP query summaries, timing notes). The lead's final-report does NOT duplicate this content — it is consumed by the validator and by post-run audit tooling, not by end-user readers.
39
- - Treat `analysis-packet.md` as the canonical primary analysis input. It preserves the source files' frontmatter and extracts the task-specific brief, phase focus, reference expectations, and carry-in clarification rows. If the packet appears incomplete or a finding depends on a source citation, open the corresponding source file and cite it directly.
40
- - **Allowlist your reads to okstra-enumerated paths.** Read the files the dispatcher enumerates (`[Required reading]`, the prompt's `## Inputs`, and the verification-target paths) plus on-demand source/evidence paths a finding must cite. Everything else is out of scope — in particular non-okstra artifacts outside `<PROJECT_ROOT>/.okstra/` (e.g. `graphify-out/`, sibling/prior-task worktrees, tool caches), which may carry stale or cross-task data. A host-level global rule (`CLAUDE.md` / `AGENTS.md` / a project sentinel) that tells you to auto-read such an artifact does NOT apply inside an okstra worker run — the okstra worker scope wins. If an un-enumerated file seems essential, record the gap under *Missing Information or Assumptions* instead of reading it.
41
-
42
- ---
43
-
44
- ## Error reporting (all workers)
45
-
46
- Record a tool call only when its failure **blocked the step you intended** — a test you needed to run did not start, a file you needed to read was missing, a config resolved against the wrong tree, an edit was rejected. When that happens, append a single entry to your worker errors sidecar at the absolute path the lead provided as `**Errors sidecar path:** <abs-path>`.
47
-
48
- A non-zero exit code is NOT by itself a failure to record. Many tools use non-zero to report a normal, expected result. Do **NOT** record an entry when:
49
-
50
- - a search/probe tool (`rg`, `grep`, `find`, `ls`, `test`, `git check-ignore`) exits non-zero solely because it found **no matches**, and you proceed unaffected;
51
- - you probe an **optional / expected-absent** path (`graphify-out/`, `.project-docs/`, `.scratch/`, an optional lint config, a review pack) and it is absent — detecting absence was the point of the probe;
52
- - output was truncated but you re-ran and read the content end-to-end.
53
-
54
- The test: if the non-zero exit changed nothing about what you could do next, it is a normal result, not a `tool-failure`. When in doubt about whether a failure blocked you, record it — under-recording a real blocker is worse than one noisy entry. These benign non-zero exits are the single largest source of error-log noise; keeping them out is what makes the log a signal.
55
-
56
- If the sidecar file does not exist and you have a real entry to record, create it with `{"schemaVersion": 1, "errors": []}` then append.
57
-
58
- ### Entry schema
59
-
60
- ```json
61
- {
62
- "ts": "<ISO 8601 UTC>",
63
- "phase": "<current okstra phase>",
64
- "errorType": "tool-failure",
65
- "command": "<failed command/tool signature>",
66
- "commandKind": "bash | tool:Read | tool:Edit | mcp | ...",
67
- "exitCode": <int or null>,
68
- "durationMs": <int or null>,
69
- "message": "<one-line human summary>",
70
- "stderrExcerpt": "<first ~2KB of stderr, or null>",
71
- "context": { ... or null }
72
- }
73
- ```
74
-
75
- ### Rules
76
-
77
- - Do NOT include `source` / `recordedAt` / `agent` / `agentRole` / `model` / `taskKey` — the lead fills those in when dumping the sidecar to the run-level errors log via `okstra-error-log.py append-from-worker`.
78
- - Do NOT use `errorType` values other than `"tool-failure"` in the sidecar. `cli-failure` events are recorded by CLI wrapper agents (codex / antigravity) directly to the run-level errors log, not via the sidecar. `contract-violation` events are recorded by the lead after inspecting worker outputs.
79
- - Continue your task after recording; do not abort unless the failure makes the task impossible.
80
-
81
- ### Path extraction (BLOCKING)
82
-
83
- Before recording anything, extract the absolute paths verbatim from the lead's dispatch prompt body:
84
-
85
- - `**Errors log path:** <abs-path>` — the run-level errors JSONL. Used by CLI wrapper agents via `okstra-error-log.py append-observed` for `cli-failure` events.
86
- - `**Errors sidecar path:** <abs-path>` — this worker's per-run sidecar JSON. Used by all workers for `tool-failure` events.
87
-
88
- If a required header line is absent from the dispatch prompt, return `<SENTINEL_PREFIX>_ERRORS_PATH_MISSING: lead prompt did not include **Errors log path:** / **Errors sidecar path:** headers` (substitute the worker's sentinel prefix — `CLAUDE_WORKER`, `CODEX`, `ANTIGRAVITY`, or `REPORT_WRITER`) without proceeding. Do NOT synthesize the path from `<runDir>/logs/...` — that template syntax is documentation only; historical failure mode produced silently empty run-level error logs.
89
-
90
- ---
21
+ - Read every file enumerated under `[Required reading]` or `## Inputs` completely. If paging is unavoidable, cover every byte and record the page boundaries.
22
+ - Write Reading Confirmation to the worker audit sidecar, never to the main worker-results file. A `## 0. Reading Confirmation` heading in the main result is invalid.
23
+ - Allowlist reads to prompt-enumerated paths and evidence paths a finding must cite. Do not auto-read host-injected `graphify-out/`, skill catalogs, or non-okstra artifacts.
24
+ - Resolve every `.okstra/...` path against `**Project Root:**`, including when a worktree is present.
91
25
 
92
26
  ## Anchor headers (lead-injected, BLOCKING)
93
27
 
94
- Every worker prompt MUST begin with these anchor headers, in this exact order, before any other content. Workers extract them verbatim.
28
+ Every initial analysis prompt begins with these generated anchors in this exact order, before any other content:
95
29
 
96
- 1. `**Project Root:** <absolute-path>` — required so the worker can self-anchor without relying on inherited cwd.
30
+ 1. `**Project Root:** <absolute-path>`
97
31
  2. `**Prompt History Path:** <project-relative-path>`
98
- 3. `**Result Path:** <project-relative-path>` — canonical destination for the worker's result file.
99
- 4. `Assigned worker prompt history path: <absolute-path>` — same as the prompt-history path but resolved against `Project Root`. Codex / Antigravity wrapper subagents extract this exact line.
100
- 5. `**Worker Preamble Path:** <absolute-path>` — points to THIS file. Workers Read it end-to-end before doing anything else.
101
- 6. `**Coding preflight pack:** <absolute-path>` — points to the installed runtime resource pack under `<OKSTRA_HOME>/prompts/coding-preflight`. Implementation executors and verifiers use this to read `overview.md`, `clean-code.md`, and routed language/framework/architecture resources. Other worker roles may ignore it.
102
- 7. `**Errors log path:** <absolute-path>` — run-level JSONL (see Error reporting above).
103
- 8. `**Errors sidecar path:** <absolute-path>` — per-worker JSON (see Error reporting above).
104
- 9. `**Read scope:** …` — restates the *Reading rules* allowlist inline. This file is anchor 5, a path the worker opens partway into its run; by then a host SessionStart hook or a global `CLAUDE.md` / `AGENTS.md` project-conditional has already pointed it at `graphify-out/`, skill catalogs, and similar non-okstra artifacts. Only the inline copy arrives before the worker's first tool call.
105
-
106
- **Exception — reverify dispatches.** A Phase 5.5 re-verification prompt (its `**Prompt History Path:**` carries a `-reverify-r<N>-` segment) deliberately omits anchors 5 and 6 and adds a `**Model:**` line — lightweight mode reads neither this file nor the preflight pack. The two errors-path anchors are NOT omitted; that gate applies to reverify prompts unchanged. The reverify anchor set is owned by `prompts/lead/convergence.md` "Required reverify-prompt anchor headers".
107
-
108
- For the **implementation phase** specifically, the dispatched prompt MUST also include:
109
-
110
- - `**Worktree:** <absolute-path>` — the task worktree path.
111
- - `cwd for every mutating command: <absolute-path>` — same as Worktree path; used by codex / antigravity wrappers as `--add-dir` / `--include-directories`.
112
-
113
- For the **final-verification phase** specifically, the dispatched prompt MUST also include the verification target snapshot so every analyser verifies the SAME target the lead captured at the entry gate:
114
-
115
- - `**Worktree:** <absolute-path>` — the checkout under verification (read-only).
116
- - `**Verification base ref:** <base-ref>` — the implementation base for the diff.
117
- - `**Verification diff stat:** <git diff --stat output>` — the captured diff-stat that bounds the verification scope.
118
-
119
- For the **improvement-discovery phase** specifically, the dispatched prompt MUST also include the resolved-scope log the lead wrote during Phase 1.5, so workers key off an explicit absolute path instead of re-deriving the run directory:
120
-
121
- - `**Phase 1.5 Grilling Log:** <absolute-path>` — the lead's Phase 1.5 reflect-back log (`<RUN_DIR>/state/phase-1.5-grilling.md`, written before dispatch). Its `Resolved scope` / `Resolved lenses` blocks are the authoritative scope and lens definition for this run. Read the file at this absolute path; do NOT re-derive it from `<RUN_DIR>`, and do NOT re-interpret the brief's raw `scan-scope` / `priority-lenses`. The presence of this anchor is itself the signal that this is an improvement-discovery run — no separate task-type detection is required.
122
-
123
- ### Path anchoring (BLOCKING — the single largest source of worker tool-failures)
124
-
125
- Every `.okstra/...` path is anchored at `**Project Root:**`, **never** at your cwd. When your run has a worktree (`**Worktree:**` is present), your cwd is that worktree — and the stage/task worktree does **not** contain the project's `.okstra/` directory. So a bare `Read`/`cat .okstra/tasks/...` from cwd resolves inside the worktree and fails "no such file". This is the same trap whether the path came from the prompt, a manifest field, a prior report's citation, or your own reasoning.
126
-
127
- - Resolve any project-relative path (`.okstra/...`, `<Result Path>`, `<Prompt History Path>`, a prior-report `path:line` citation) against `**Project Root:**`: `<Project Root>/.okstra/...`. Never use the bare relative form.
128
- - Mutating build/test commands still run from the worktree cwd (`cd <Worktree> && ...`) — but reads of okstra artifacts (`.okstra/**`) always go through `<Project Root>`, even while cwd is the worktree.
129
- - If a `.okstra/...` read fails "no such file / does not exist in the worktree", do not retry the same relative path — re-anchor it to `<Project Root>` and read the absolute path.
32
+ 3. `**Result Path:** <project-relative-path>`
33
+ 4. `Assigned worker prompt history path: <absolute-path>`
34
+ 5. `**Worker Preamble Path:** <absolute-path>` — selects this analysis preamble.
35
+ 6. `**Worker Error Contract Path:** <absolute-path>` — shared by every initial audience.
36
+ 7. `**Errors log path:** <absolute-path>`
37
+ 8. `**Errors sidecar path:** <absolute-path>`
38
+ 9. `**Read scope:** <allowlist>`
130
39
 
131
- ---
40
+ `final-verification` additionally carries its six verification-target anchors. `improvement-discovery` carries `**Phase 1.5 Grilling Log:**`. Reverify prompts are lightweight and do not use this preamble.
132
41
 
133
- ## Worker output sections (analysis workers)
42
+ ## Worker output sections
134
43
 
135
- **Authoritative source.** This preamble section is the canonical worker output contract. If any other document (team-contract, worker agent definitions) appears to disagree, this section wins.
136
-
137
- ### Result Frontmatter (mandatory, precedes Section 1)
138
-
139
- Every worker result file MUST begin with a YAML frontmatter block. For analysis workers, values are sourced from `analysis-packet.md` frontmatter; fall back to `analysis-material.md` or `task-brief.md` only if the packet is missing a field. Report-writer can use `analysis-material.md` / `task-brief.md` as before. Copy values verbatim; do NOT regenerate them. Only `workerId` and `title` are worker-specific.
140
-
141
- ```yaml
142
- ---
143
- title: OKSTRA <Worker Role> Result - <task-key>
144
- id: "<task-key with ':' replaced by '-'>"
145
- aliases: ["<id>-<task-type>"]
146
- tags: ["worker-result", "<task-type>"]
147
- taskType: "<task-type>"
148
- workerId: "<claude|codex|antigravity|report-writer>"
149
- task-id: "<task-id>"
150
- task-group: "<task-group>"
151
- project-id: "<project-id>"
152
- date: <YYYY-MM-DD>
153
- ---
154
- ```
155
-
156
- Concrete example for a `claude-worker` result on task-key `fontsninja-classifier-v2:DEV-9388:DEV-9429` and task-type `implementation`:
157
-
158
- ```yaml
159
- ---
160
- title: OKSTRA Claude Worker Result - fontsninja-classifier-v2:DEV-9388:DEV-9429
161
- id: "fontsninja-classifier-v2-DEV-9388-DEV-9429"
162
- aliases: ["fontsninja-classifier-v2-DEV-9388-DEV-9429-implementation"]
163
- tags: ["worker-result", "implementation"]
164
- taskType: "implementation"
165
- workerId: "claude"
166
- task-id: "DEV-9429"
167
- task-group: "DEV-9388"
168
- project-id: "fontsninja-classifier-v2"
169
- date: 2026-05-15
170
- ---
171
- ```
172
-
173
- Rules:
174
- - `id` is the run's `task-key` with `:` replaced by `-`. It is a scalar string, NOT an array.
175
- - `aliases` is a YAML array containing a single value `"<id>-<task-type>"`.
176
- - `taskType` mirrors the run's task type (`requirements-discovery`, `error-analysis`, `implementation-planning`, `implementation`, `final-verification`, `release-handoff`).
177
- - `workerId` identifies which worker produced the file. Required values: `claude` / `codex` / `antigravity` / `report-writer`.
178
- - Other fields (`task-id`, `task-group`, `project-id`, `date`) MUST match the input files' frontmatter exactly. If the input frontmatter is missing or unreadable, the worker MUST record a `tool-failure` and stop instead of guessing.
179
-
180
- The same frontmatter contract applies to the `Report writer worker`'s final-report file — the report-writer copies these values from its inputs and only swaps `workerId` to `report-writer`.
181
-
182
- ### Worker Result Header Standard
183
-
184
- Every worker result file under `worker-results/` must begin with a standardized header:
185
-
186
- ```markdown
187
- # <Role> Analysis — <task-key>
188
-
189
- **Target:** <path or scope> <!-- OPTIONAL: include when the run is scoped to a specific file/module -->
190
- **Model:** <Role>, <AI model>
191
- ```
192
-
193
- Task-type and date are **not** repeated in this human header — the YAML frontmatter (`taskType`, `date`) is the single source for both (and the copy Obsidian indexes). The `Target:` line is optional — include it when the run is scoped to a specific path or module, omit it for whole-project runs; when present, place it between the title and the `Model:` line.
194
-
195
- Example (Codex / Report-writer headers are identical modulo the role name and model id):
196
-
197
- ```markdown
198
- # Claude Worker Analysis — jobs:tasks:8852
199
-
200
- **Target:** server/auth.ts
201
- **Model:** Claude worker, opus
202
- ```
203
-
204
- Use the actual model identifier recorded in team-state (never invent a model ID — read it from `resultContract.requiredWorkerRoles[*].modelExecutionValue` or the tool response metadata).
205
-
206
- The header is followed by the standard worker output contract sections (Findings, Missing Information, etc.).
207
-
208
- ### Section ordering
209
-
210
- A successful worker result must include the following sections in this exact order, beneath the frontmatter block:
44
+ Every analysis result starts with YAML frontmatter containing the task identity and `workerId`, followed by a header with the actual `**Model:**` value. Then emit these sections in exact order:
211
45
 
212
46
  1. Findings
213
47
  2. Missing Information or Assumptions
214
48
  3. Safe or Reasonable Areas
215
49
  4. Uncertain Points
216
50
  5. Recommended Next Actions
217
- 6. **Specialization Lens (optional, worker-specific deep dive)** — additive content produced from this worker's specialization lens (see Role Definitions table). Items here are NOT subject to convergence cross-verification and MUST NOT duplicate sections 1–5. If the worker has nothing additional to add from its lens, omit Section 6 entirely or write `- No additional lens-specific findings.`
218
-
219
- Every item in sections 1–5 (and any section 6) MUST carry a worker-internal item ID unique within the file. Lead synthesis preserves these as `<worker>:<item-id>` in `Source items (worker:item)` columns.
220
-
221
- **Sections 1–5 are the common core.** Every analysis worker (Claude / Codex / Antigravity) MUST cover the same set of dimensions in sections 1–5 — feasibility, requirement interpretation, hidden assumptions, alternatives, and execution risk — regardless of which model is producing the result. The point of running three models is to triangulate the same answer space, not to partition it. A worker that produces "Findings" populated only with items from its own lens (e.g. Codex only listing implementation-feasibility findings) is in breach of contract; convergence will treat coverage gaps as `verification-error`.
222
-
223
- **Section 6 is the only legal home for specialization.** When the worker has a depth-of-perspective contribution that genuinely sits outside the common core (e.g. a Codex-specific stack-trace decomposition, a Claude-specific assumption-chain teardown, a Antigravity-specific alternative-architecture sketch), put it there. Lead and convergence treat Section 6 as additive context, not as input to consensus measurement.
224
-
225
- Code evidence must include file paths and line numbers.
226
-
227
- ### Ticket Tagging (mandatory for sections 1–5)
228
-
229
- Every item in sections 1–5 MUST be tagged with the ticket(s) it relates to. This applies whenever the run's task type is `requirements-discovery`, `error-analysis`, `implementation-planning`, or `implementation`.
230
-
231
- - **Table-form items**: include a `Ticket ID` column. The column is placed immediately after the row-ID column (e.g. after `F-001`, `M-001`).
232
- - **Bullet / numbered-list items**: prepend `[TICKETID: <id>]` to the item title, immediately after the row ID and before the body text. Example: `- F-001 [TICKETID: TICKET-123] — <summary> (path:line)`.
233
- - **Section headers in the final report** (e.g. `### 5.5.3 Recommended Option`): append `[TICKETID: <id>]` to the header when the section is scoped to a specific ticket. Headers that span all tickets in the run omit the tag.
234
-
235
- Ticket ID fill rule (in order):
236
-
237
- 1. Use the `Issue / Ticket` value from the run's input template.
238
- 2. If empty, fall back to the `Task ID` value (no prefix; write `8852` not `task:8852`).
239
- 3. If both are absent, write `unknown`. This is allowed but signals an input-template defect — the worker SHOULD also record a `Missing Information` item noting the absent identifier.
240
- 4. When a single item maps to multiple tickets, separate them with commas: `TICKET-123, TICKET-456`. Ticket IDs containing commas are not supported.
241
-
242
- Workers MUST apply these rules to every item in sections 1–5. Lead and report-writer MUST preserve the tagging when carrying worker findings into the final report.
243
-
244
- For phases other than the four listed above (e.g. `release-handoff`, `final-verification`), ticket tagging is optional.
51
+ 6. Specialization Lens (optional, additive only)
245
52
 
246
- ## Return message to the lead (all workers)
53
+ Every item has a worker-local ID and file:line evidence where code evidence exists. Sections 1–5 are the common core: feasibility, requirement interpretation, hidden assumptions, alternatives, and execution risk. Section 6 is the only legal home for specialization and is not consensus input.
247
54
 
248
- The short message you return inline to the lead — the text shown to the user as your agent box — MUST begin with one line identifying the model you ran under, copied verbatim from the `**Model:** <Role>, <modelExecutionValue>` line in your dispatch prompt:
55
+ ### Ticket Tagging
249
56
 
250
- ```
251
- **Model:** <Role>, <modelExecutionValue>
252
- ```
57
+ For `requirements-discovery`, `error-analysis`, and `implementation-planning`, tag every section 1–5 item with its related ticket. Use `Issue / Ticket`, fall back to Task ID, then `unknown`; comma-separate multiple tickets.
253
58
 
254
- Emit that line first, then your normal status / summary text on the following lines. This keeps the acting model visible in every worker box — across every provider (Claude / Codex / Antigravity / report-writer) and every dispatch type (initial analysis, convergence reverify, report authoring). Copy the value exactly; never guess, abbreviate, or substitute a provider default. If your prompt carries no `**Model:**` line, say so in the return message rather than inventing one. Each worker spec applies this rule at its own concrete return point — see `agents/workers/claude-worker.md` "Stop Condition", `agents/workers/_cli-wrapper-template.md` step 8d, and `agents/workers/report-writer-worker.md` "Authoring Contract".
59
+ ## Return message to the lead
255
60
 
256
- ## Writing style (all prose output analysis workers + report-writer)
61
+ Begin the inline return with the model identity copied verbatim from the `**Model:** <Role>, <modelExecutionValue>` line in the prompt, followed by the status summary. Never invent or abbreviate the model.
257
62
 
258
- When you write in Korean (`Report Language: ko` / `meta.reportLanguage = "ko"`), write so a Korean developer understands it on first read. Translate the **meaning**, never the dictionary word.
63
+ ## Writing style
259
64
 
260
- - Keep code identifiers, file paths, symbols, model names, CLI flags, and status tokens in English (`strategy`, `overlay`, `accepted`, …). Translate the ordinary words around them.
261
- - Do NOT render a technical term as its literal dictionary noun. Use the term a developer actually says:
262
- - `authoritative` → render it by its domain sense — "the value that takes precedence" / "the canonical value" — never by the bare dictionary noun for "authority".
263
- - e.g. "overlays this row as authoritative" → phrase it as "overwrites this row as the definitive value", never as a word-for-word "authority" calque.
264
- - Self-check before emitting any Korean sentence: if it reads like an awkward word-for-word translation, rewrite it by meaning. Confident-but-unreadable direct translation is a defect.
65
+ Translate meaning rather than dictionary words. Keep identifiers, paths, symbols, model names, CLI flags, and status tokens in English. Rewrite awkward word-for-word Korean before returning.
@@ -123,12 +123,20 @@ if not prompt_relative:
123
123
 
124
124
  prompt_path = project_root / prompt_relative
125
125
  prompt_path.parent.mkdir(parents=True, exist_ok=True)
126
+ artifacts = task_manifest.get("artifacts", {})
127
+ analysis_packet_path = (
128
+ str(artifacts.get("analysisPacketPath", "")).strip()
129
+ if isinstance(artifacts, dict)
130
+ else ""
131
+ )
126
132
  prompt_path.write_text(
127
133
  "\n".join(
128
134
  [
129
- f"# {target_worker.get('role', target_worker_id)} Prompt Snapshot",
130
- "",
135
+ "**Worker Error Contract Path:** /okstra/templates/worker-error-contract.md",
131
136
  f"Assigned worker prompt history path: {prompt_relative}",
137
+ f"- Primary analysis packet: `{analysis_packet_path}`",
138
+ "",
139
+ "# Initial Analysis Prompt",
132
140
  f"Task Key: {task_manifest.get('taskKey', '')}",
133
141
  "Validation fixture prompt body.",
134
142
  ]
@@ -213,17 +221,24 @@ for worker in team_state.get("workers", []):
213
221
  if prompt_relative and worker_id != omitted_worker_id:
214
222
  prompt_path = project_root / prompt_relative
215
223
  prompt_path.parent.mkdir(parents=True, exist_ok=True)
216
- prompt_path.write_text(
217
- "\n".join(
218
- [
219
- f"# {worker.get('role', worker_id)} Prompt Snapshot",
220
- "",
221
- f"Assigned worker prompt history path: {prompt_relative}",
222
- f"Task Key: {task_manifest.get('taskKey', '')}",
223
- "Validation fixture prompt body.",
224
- ]
224
+ prompt_lines = [
225
+ "**Worker Error Contract Path:** /okstra/templates/worker-error-contract.md",
226
+ f"Assigned worker prompt history path: {prompt_relative}",
227
+ ]
228
+ if worker_id != "report-writer":
229
+ prompt_lines.append(
230
+ f"- Primary analysis packet: `{run_manifest.get('analysisPacketPath', '')}`"
225
231
  )
226
- + "\n"
232
+ prompt_lines.extend([
233
+ "",
234
+ "# Initial Analysis Prompt",
235
+ f"Task Key: {task_manifest.get('taskKey', '')}",
236
+ "Validation fixture prompt body.",
237
+ ])
238
+ else:
239
+ prompt_lines.extend(["", "# Report Writer Prompt"])
240
+ prompt_path.write_text(
241
+ "\n".join(prompt_lines) + "\n"
227
242
  )
228
243
 
229
244
  result_relative = str(worker.get("resultPath", "")).strip()