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,316 @@
1
+ """Compact initial final-verification prompt contract."""
2
+ from __future__ import annotations
3
+
4
+ import re
5
+ from dataclasses import dataclass
6
+ from pathlib import Path
7
+ from typing import Any, Mapping, Sequence
8
+
9
+ from .worker_prompt_policy import PromptPlan, resolve_prompt_plan_for_manifest
10
+
11
+
12
+ MAX_FINAL_VERIFICATION_DIRECTIVE_LINES = 40
13
+ MAX_FINAL_VERIFICATION_BODY_LINES = 96
14
+
15
+ _DIRECTIVE_HEADING = "## Run-specific directive"
16
+ _WORKER_ERROR_CONTRACT_HEADER = "**Worker Error Contract Path:**"
17
+ _PRIMARY_PACKET_RE = re.compile(
18
+ r"(?im)^-\s+Primary analysis packet:\s+`[^`\n]*analysis-packet\.md`\s*$"
19
+ )
20
+ _COPIED_SECTION_PATTERNS = (
21
+ ("Primary focus areas", re.compile(r"(?im)^(?:#{1,6}\s+|-\s+)Primary focus areas\b")),
22
+ (
23
+ "Required deliverable shape",
24
+ re.compile(r"(?im)^(?:#{1,6}\s+|-\s+)Required deliverable shape\b"),
25
+ ),
26
+ (
27
+ "Self-review pass",
28
+ re.compile(r"(?im)^(?:#{1,6}\s+|-\s+)Self-review pass\b"),
29
+ ),
30
+ )
31
+ _NON_BODY_PREFIXES = (
32
+ "**Project Root:**",
33
+ "**Prompt History Path:**",
34
+ "**Result Path:**",
35
+ "Assigned worker prompt history path:",
36
+ "**Worker Preamble Path:**",
37
+ "**Errors log path:**",
38
+ "**Errors sidecar path:**",
39
+ "**Read scope:**",
40
+ "**Worktree:**",
41
+ "**Verification scope:**",
42
+ "**Verification base ref:**",
43
+ "**Verification head ref:**",
44
+ "**Verification target path:**",
45
+ "**Verification target digest:**",
46
+ )
47
+ _REQUIRED_TARGET_PREFIXES = (
48
+ "**Worktree:**",
49
+ "**Verification scope:**",
50
+ "**Verification base ref:**",
51
+ "**Verification head ref:**",
52
+ "**Verification target path:**",
53
+ "**Verification target digest:**",
54
+ )
55
+ _WORKER_SPECIFIC_PREFIXES = (
56
+ "**Prompt History Path:**",
57
+ "**Result Path:**",
58
+ "Assigned worker prompt history path:",
59
+ "**Errors sidecar path:**",
60
+ "**Worker Result Path:**",
61
+ "**Model:**",
62
+ "**Pane role:**",
63
+ )
64
+ _WORKER_LABEL_RE = re.compile(
65
+ r"\b(?:Claude|Codex|Antigravity) worker\b",
66
+ re.IGNORECASE,
67
+ )
68
+
69
+
70
+ @dataclass(frozen=True)
71
+ class PromptRecord:
72
+ worker_id: str
73
+ dispatch_kind: str
74
+ path: Path
75
+
76
+
77
+ def validate_final_verification_initial_prompt(text: str) -> list[str]:
78
+ """Return deterministic compact-prompt contract violations."""
79
+ errors: list[str] = []
80
+ _reject_literal(
81
+ text,
82
+ "**Coding preflight pack:**",
83
+ "Coding preflight pack is forbidden for final-verification",
84
+ errors,
85
+ )
86
+ _reject_literal(
87
+ text,
88
+ "**Verification diff stat:**",
89
+ "inline Verification diff stat is forbidden; use verification-target.md",
90
+ errors,
91
+ )
92
+ _reject_literal(
93
+ text,
94
+ "## Source / fallback paths",
95
+ "Source / fallback paths is forbidden; use analysis-packet.md",
96
+ errors,
97
+ )
98
+ for label, pattern in _COPIED_SECTION_PATTERNS:
99
+ if pattern.search(text):
100
+ errors.append(f"copied {label} section is forbidden; use analysis-packet.md")
101
+ _validate_compact_target_identity(text, errors)
102
+ packet_count = len(_PRIMARY_PACKET_RE.findall(text))
103
+ if packet_count != 1:
104
+ errors.append(
105
+ "exactly one Primary analysis packet path is required "
106
+ f"(found {packet_count})"
107
+ )
108
+ directive_count = text.count(_DIRECTIVE_HEADING)
109
+ if directive_count > 1:
110
+ errors.append("at most one Run-specific directive section is allowed")
111
+ if directive_count == 1:
112
+ directive_lines = _directive_nonblank_lines(text)
113
+ if directive_lines > MAX_FINAL_VERIFICATION_DIRECTIVE_LINES:
114
+ errors.append(
115
+ "Run-specific directive exceeds "
116
+ f"{MAX_FINAL_VERIFICATION_DIRECTIVE_LINES} nonblank lines "
117
+ f"(found {directive_lines})"
118
+ )
119
+ body_lines = _body_nonblank_lines(text)
120
+ if body_lines > MAX_FINAL_VERIFICATION_BODY_LINES:
121
+ errors.append(
122
+ f"prompt body exceeds {MAX_FINAL_VERIFICATION_BODY_LINES} "
123
+ f"nonblank lines (found {body_lines})"
124
+ )
125
+ return errors
126
+
127
+
128
+ def normalise_analysis_prompt(text: str) -> str:
129
+ """Remove only permitted worker identity, model, role, and path deltas."""
130
+ normalized: list[str] = []
131
+ for line in text.replace("\r\n", "\n").replace("\r", "\n").splitlines():
132
+ stripped = line.strip()
133
+ prefix = next(
134
+ (candidate for candidate in _WORKER_SPECIFIC_PREFIXES if stripped.startswith(candidate)),
135
+ "",
136
+ )
137
+ if prefix:
138
+ normalized.append(f"{prefix} <worker-specific>")
139
+ continue
140
+ normalized.append(_WORKER_LABEL_RE.sub("<analysis-worker>", line.rstrip()))
141
+ return "\n".join(normalized).strip() + "\n"
142
+
143
+
144
+ def validate_analysis_prompt_set(prompts: Mapping[str, str]) -> list[str]:
145
+ """Require byte-identical normalized bodies for initial analysis workers."""
146
+ if len(prompts) < 2:
147
+ return []
148
+ normalized = {
149
+ worker_id: normalise_analysis_prompt(text)
150
+ for worker_id, text in sorted(prompts.items())
151
+ }
152
+ baseline_worker = next(iter(normalized))
153
+ baseline = normalized[baseline_worker]
154
+ different = [
155
+ worker_id
156
+ for worker_id, body in normalized.items()
157
+ if body != baseline
158
+ ]
159
+ if not different:
160
+ return []
161
+ workers = ", ".join([baseline_worker, *different])
162
+ return [f"normalized initial analysis prompts differ across workers: {workers}"]
163
+
164
+
165
+ def validate_final_verification_prompt_paths(
166
+ prompt_paths: Mapping[str, Path],
167
+ ) -> list[str]:
168
+ """Validate persisted initial prompts and their normalized equality."""
169
+ records = [
170
+ PromptRecord(worker_id, "initial", path)
171
+ for worker_id, path in sorted(prompt_paths.items())
172
+ ]
173
+ return validate_initial_prompt_records(
174
+ manifest={"taskType": "final-verification"},
175
+ records=records,
176
+ )
177
+
178
+
179
+ def validate_initial_prompt_records(
180
+ *,
181
+ manifest: Mapping[str, Any],
182
+ records: Sequence[PromptRecord],
183
+ ) -> list[str]:
184
+ """Validate prompt audiences and compare their normalized equality groups."""
185
+ errors: list[str] = []
186
+ equality_groups: dict[str, dict[str, str]] = {}
187
+ for record in records:
188
+ plan = _resolve_record_plan(manifest, record, errors)
189
+ if plan is None or plan.audience in {"lead-only", "reverify"}:
190
+ continue
191
+ try:
192
+ text = record.path.read_text(encoding="utf-8")
193
+ except OSError as exc:
194
+ errors.append(
195
+ f"{record.worker_id}: cannot read prompt {record.path}: {exc}"
196
+ )
197
+ continue
198
+ errors.extend(
199
+ f"{record.worker_id}: {error}"
200
+ for error in _validate_prompt_for_plan(text, plan, manifest)
201
+ )
202
+ if plan.equality_group:
203
+ group = equality_groups.setdefault(plan.equality_group, {})
204
+ group[record.worker_id] = text
205
+ for prompts in equality_groups.values():
206
+ errors.extend(validate_analysis_prompt_set(prompts))
207
+ return errors
208
+
209
+
210
+ def _resolve_record_plan(
211
+ manifest: Mapping[str, Any],
212
+ record: PromptRecord,
213
+ errors: list[str],
214
+ ) -> PromptPlan | None:
215
+ try:
216
+ return resolve_prompt_plan_for_manifest(
217
+ manifest=manifest,
218
+ worker_id=record.worker_id,
219
+ dispatch_kind=record.dispatch_kind,
220
+ )
221
+ except ValueError as exc:
222
+ errors.append(f"{record.worker_id}: {exc}")
223
+ return None
224
+
225
+
226
+ def _validate_prompt_for_plan(
227
+ text: str,
228
+ plan: PromptPlan,
229
+ manifest: Mapping[str, Any],
230
+ ) -> list[str]:
231
+ errors: list[str] = []
232
+ _require_non_empty_header(text, _WORKER_ERROR_CONTRACT_HEADER, errors)
233
+ if manifest.get("taskType") == "final-verification" and plan.audience == "analysis":
234
+ return [*errors, *validate_final_verification_initial_prompt(text)]
235
+ if not plan.allow_coding_preflight:
236
+ _reject_literal(
237
+ text,
238
+ "**Coding preflight pack:**",
239
+ "Coding preflight pack is forbidden for this prompt audience",
240
+ errors,
241
+ )
242
+ for prefix in plan.required_headers:
243
+ _require_non_empty_header(text, prefix, errors)
244
+ if plan.audience == "analysis":
245
+ packet_count = len(_PRIMARY_PACKET_RE.findall(text))
246
+ if packet_count != 1:
247
+ errors.append(
248
+ "exactly one Primary analysis packet path is required "
249
+ f"(found {packet_count})"
250
+ )
251
+ return errors
252
+
253
+
254
+ def _require_non_empty_header(
255
+ text: str,
256
+ prefix: str,
257
+ errors: list[str],
258
+ ) -> None:
259
+ matches = [
260
+ line.strip()
261
+ for line in text.splitlines()
262
+ if line.strip().startswith(prefix)
263
+ ]
264
+ if len(matches) != 1 or not matches[0][len(prefix):].strip():
265
+ errors.append(f"exactly one non-empty {prefix} header is required")
266
+
267
+
268
+ def _reject_literal(
269
+ text: str,
270
+ literal: str,
271
+ message: str,
272
+ errors: list[str],
273
+ ) -> None:
274
+ if literal in text:
275
+ errors.append(message)
276
+
277
+
278
+ def _validate_compact_target_identity(text: str, errors: list[str]) -> None:
279
+ stripped_lines = [line.strip() for line in text.splitlines()]
280
+ for prefix in _REQUIRED_TARGET_PREFIXES:
281
+ matches = [line for line in stripped_lines if line.startswith(prefix)]
282
+ if len(matches) != 1 or not matches[0][len(prefix):].strip():
283
+ errors.append(f"exactly one non-empty {prefix} header is required")
284
+ scope_line = next(
285
+ (line for line in stripped_lines if line.startswith("**Verification scope:**")),
286
+ "",
287
+ )
288
+ scope = scope_line.removeprefix("**Verification scope:**").strip()
289
+ if scope and scope not in {"whole-task", "single-stage"}:
290
+ errors.append("Verification scope must be whole-task or single-stage")
291
+ digest_line = next(
292
+ (
293
+ line
294
+ for line in stripped_lines
295
+ if line.startswith("**Verification target digest:**")
296
+ ),
297
+ "",
298
+ )
299
+ digest = digest_line.removeprefix("**Verification target digest:**").strip()
300
+ if digest and not re.fullmatch(r"sha256:[0-9a-f]{64}", digest):
301
+ errors.append("Verification target digest must be sha256:<64 lowercase hex>")
302
+
303
+
304
+ def _directive_nonblank_lines(text: str) -> int:
305
+ section = text.split(_DIRECTIVE_HEADING, 1)[1]
306
+ section = re.split(r"(?m)^##\s+", section, maxsplit=1)[0]
307
+ return sum(1 for line in section.splitlines() if line.strip())
308
+
309
+
310
+ def _body_nonblank_lines(text: str) -> int:
311
+ return sum(
312
+ 1
313
+ for line in text.splitlines()
314
+ if line.strip()
315
+ and not any(line.strip().startswith(prefix) for prefix in _NON_BODY_PREFIXES)
316
+ )
@@ -5,6 +5,12 @@ from pathlib import Path
5
5
  from typing import Any, Mapping
6
6
 
7
7
  from .paths import okstra_home
8
+ from .worker_prompt_policy import (
9
+ PromptPlan,
10
+ WORKER_ERROR_CONTRACT_FILENAME,
11
+ WORKER_PREAMBLE_FILENAME_BY_AUDIENCE,
12
+ resolve_prompt_plan_for_manifest,
13
+ )
8
14
 
9
15
 
10
16
  class WorkerPromptHeaderError(Exception):
@@ -36,29 +42,93 @@ def worker_prompt_headers(
36
42
  prompt_rel: str,
37
43
  result_rel: str,
38
44
  worker_id: str,
45
+ dispatch_kind: str,
39
46
  manifest: Mapping[str, Any],
40
47
  active_context: Mapping[str, Any],
41
48
  ) -> list[str]:
42
49
  """Render the team-contract worker prompt anchor headers."""
43
50
  prompt_path = _resolve_project_path(project_root, prompt_rel)
44
- return [
51
+ errors_log_path = _errors_log_path(project_root, manifest, active_context)
52
+ errors_sidecar_path = _worker_errors_sidecar_path(
53
+ project_root,
54
+ manifest,
55
+ active_context,
56
+ worker_id,
57
+ )
58
+ plan = _prompt_plan(manifest, worker_id, dispatch_kind)
59
+ headers = [
45
60
  f"**Project Root:** {project_root}",
46
61
  f"**Prompt History Path:** {prompt_rel}",
47
62
  f"**Result Path:** {result_rel}",
48
63
  f"Assigned worker prompt history path: {prompt_path}",
49
- f"**Worker Preamble Path:** {_worker_preamble_path()}",
50
- f"**Coding preflight pack:** {_coding_preflight_pack_path(active_context)}",
51
- f"**Errors log path:** {_errors_log_path(project_root, manifest, active_context)}",
52
- (
53
- f"**Errors sidecar path:** "
54
- f"{_worker_errors_sidecar_path(project_root, manifest, active_context, worker_id)}"
55
- ),
64
+ f"**Worker Preamble Path:** {_worker_preamble_path(plan, active_context)}",
65
+ f"**Worker Error Contract Path:** {_worker_error_contract_path(active_context)}",
66
+ ]
67
+ if plan.allow_coding_preflight:
68
+ headers.append(
69
+ f"**Coding preflight pack:** {_coding_preflight_pack_path(active_context)}"
70
+ )
71
+ headers.extend([
72
+ f"**Errors log path:** {errors_log_path}",
73
+ f"**Errors sidecar path:** {errors_sidecar_path}",
56
74
  READ_SCOPE_HEADER,
75
+ ])
76
+ if _string_value(manifest.get("taskType")) == "improvement-discovery":
77
+ headers.append(
78
+ f"**Phase 1.5 Grilling Log:** "
79
+ f"{_improvement_grilling_log_path(project_root, manifest)}"
80
+ )
81
+ if _string_value(manifest.get("taskType")) == "final-verification":
82
+ headers.extend(_final_verification_target_headers(active_context))
83
+ return headers
84
+
85
+
86
+ def _final_verification_target_headers(
87
+ active_context: Mapping[str, Any],
88
+ ) -> list[str]:
89
+ target = active_context.get("verificationTarget")
90
+ if not isinstance(target, Mapping):
91
+ return []
92
+ fields = (
93
+ ("Worktree", "worktreePath"),
94
+ ("Verification scope", "scope"),
95
+ ("Verification base ref", "baseRef"),
96
+ ("Verification head ref", "headRef"),
97
+ ("Verification target path", "path"),
98
+ ("Verification target digest", "digest"),
99
+ )
100
+ return [
101
+ f"**{label}:** {_string_value(target.get(key))}"
102
+ for label, key in fields
103
+ if _string_value(target.get(key))
57
104
  ]
58
105
 
59
106
 
60
- def _worker_preamble_path() -> Path:
61
- return okstra_home() / "templates" / "worker-prompt-preamble.md"
107
+ def _worker_preamble_path(
108
+ plan: PromptPlan,
109
+ active_context: Mapping[str, Any],
110
+ ) -> Path:
111
+ runtime_resources = active_context.get("runtimeResources")
112
+ if isinstance(runtime_resources, Mapping):
113
+ paths = runtime_resources.get("workerPreamblePathByAudience")
114
+ if isinstance(paths, Mapping):
115
+ value = _string_value(paths.get(plan.audience))
116
+ if value:
117
+ return Path(value)
118
+ filename = WORKER_PREAMBLE_FILENAME_BY_AUDIENCE.get(
119
+ plan.audience,
120
+ WORKER_PREAMBLE_FILENAME_BY_AUDIENCE["analysis"],
121
+ )
122
+ return okstra_home() / "templates" / filename
123
+
124
+
125
+ def _worker_error_contract_path(active_context: Mapping[str, Any]) -> Path:
126
+ runtime_resources = active_context.get("runtimeResources")
127
+ if isinstance(runtime_resources, Mapping):
128
+ value = _string_value(runtime_resources.get("workerErrorContractPath"))
129
+ if value:
130
+ return Path(value)
131
+ return okstra_home() / "templates" / WORKER_ERROR_CONTRACT_FILENAME
62
132
 
63
133
 
64
134
  def _coding_preflight_pack_path(active_context: Mapping[str, Any]) -> Path:
@@ -70,6 +140,35 @@ def _coding_preflight_pack_path(active_context: Mapping[str, Any]) -> Path:
70
140
  return okstra_home() / "prompts" / "coding-preflight"
71
141
 
72
142
 
143
+ def _prompt_plan(
144
+ manifest: Mapping[str, Any],
145
+ worker_id: str,
146
+ dispatch_kind: str,
147
+ ) -> PromptPlan:
148
+ try:
149
+ return resolve_prompt_plan_for_manifest(
150
+ manifest=manifest,
151
+ worker_id=worker_id,
152
+ dispatch_kind=dispatch_kind,
153
+ )
154
+ except ValueError as exc:
155
+ raise WorkerPromptHeaderError(str(exc)) from exc
156
+
157
+
158
+ def _improvement_grilling_log_path(
159
+ project_root: Path,
160
+ manifest: Mapping[str, Any],
161
+ ) -> Path:
162
+ path = (
163
+ _run_directory_path(project_root, manifest)
164
+ / "state"
165
+ / "phase-1.5-grilling.md"
166
+ )
167
+ if not path.is_file():
168
+ raise WorkerPromptHeaderError(f"Phase 1.5 grilling log not found: {path}")
169
+ return path
170
+
171
+
73
172
  def _errors_log_path(
74
173
  project_root: Path,
75
174
  manifest: Mapping[str, Any],
@@ -0,0 +1,158 @@
1
+ """Resolve worker prompt requirements from functional audience."""
2
+ from __future__ import annotations
3
+
4
+ from dataclasses import dataclass
5
+ from typing import Any, Literal, Mapping
6
+
7
+
8
+ PromptAudience = Literal[
9
+ "analysis",
10
+ "implementation-executor",
11
+ "implementation-verifier",
12
+ "report-writer",
13
+ "reverify",
14
+ "lead-only",
15
+ ]
16
+
17
+ FINAL_VERIFICATION_HEADERS = (
18
+ "**Worktree:**",
19
+ "**Verification scope:**",
20
+ "**Verification base ref:**",
21
+ "**Verification head ref:**",
22
+ "**Verification target path:**",
23
+ "**Verification target digest:**",
24
+ )
25
+ SUPPORTED_TASK_TYPES = frozenset({
26
+ "requirements-discovery",
27
+ "error-analysis",
28
+ "implementation-planning",
29
+ "improvement-discovery",
30
+ "implementation",
31
+ "final-verification",
32
+ "release-handoff",
33
+ })
34
+ WORKER_PREAMBLE_FILENAME_BY_AUDIENCE = {
35
+ "analysis": "worker-prompt-preamble.md",
36
+ "implementation-executor": "implementation-worker-preamble.md",
37
+ "implementation-verifier": "implementation-worker-preamble.md",
38
+ "report-writer": "report-writer-prompt-preamble.md",
39
+ }
40
+ WORKER_ERROR_CONTRACT_FILENAME = "worker-error-contract.md"
41
+
42
+
43
+ @dataclass(frozen=True)
44
+ class PromptPlan:
45
+ audience: PromptAudience
46
+ equality_group: str | None
47
+ packet_only: bool
48
+ allow_coding_preflight: bool
49
+ required_headers: tuple[str, ...]
50
+ max_body_lines: int | None
51
+ max_directive_lines: int | None
52
+
53
+
54
+ def resolve_prompt_plan(
55
+ *,
56
+ task_type: str,
57
+ worker_id: str,
58
+ executor_worker_id: str | None,
59
+ dispatch_kind: str,
60
+ ) -> PromptPlan:
61
+ """Resolve prompt policy without consulting provider or model identity."""
62
+ if task_type not in SUPPORTED_TASK_TYPES:
63
+ raise ValueError(f"unsupported task type: {task_type}")
64
+ if task_type == "release-handoff":
65
+ return _plan("lead-only")
66
+ if not worker_id.strip():
67
+ raise ValueError("worker ID is required")
68
+ if dispatch_kind.startswith("reverify-r"):
69
+ return _plan("reverify")
70
+ if task_type == "implementation" and not executor_worker_id:
71
+ raise ValueError("implementation executor worker ID is required")
72
+ if worker_id == "report-writer":
73
+ return _plan("report-writer")
74
+ if task_type == "implementation" and worker_id == executor_worker_id:
75
+ return _plan(
76
+ "implementation-executor",
77
+ allow_coding_preflight=True,
78
+ required_headers=("**Worktree:**",),
79
+ )
80
+ if task_type == "implementation":
81
+ return _plan(
82
+ "implementation-verifier",
83
+ equality_group="implementation-verifier-core",
84
+ allow_coding_preflight=True,
85
+ required_headers=("**Worktree:**",),
86
+ )
87
+ if task_type == "final-verification":
88
+ return _plan(
89
+ "analysis",
90
+ equality_group="analysis-core",
91
+ packet_only=True,
92
+ required_headers=FINAL_VERIFICATION_HEADERS,
93
+ max_body_lines=96,
94
+ max_directive_lines=40,
95
+ )
96
+ if task_type == "improvement-discovery":
97
+ return _plan(
98
+ "analysis",
99
+ equality_group="analysis-core",
100
+ packet_only=True,
101
+ required_headers=("**Phase 1.5 Grilling Log:**",),
102
+ )
103
+ return _plan("analysis", equality_group="analysis-core", packet_only=True)
104
+
105
+
106
+ def resolve_prompt_plan_for_manifest(
107
+ *,
108
+ manifest: Mapping[str, Any],
109
+ worker_id: str,
110
+ dispatch_kind: str,
111
+ ) -> PromptPlan:
112
+ """Resolve policy from canonical task and executor manifest fields."""
113
+ task_type = _required_string(manifest, "taskType")
114
+ return resolve_prompt_plan(
115
+ task_type=task_type,
116
+ worker_id=worker_id,
117
+ executor_worker_id=_executor_worker_id(manifest),
118
+ dispatch_kind=dispatch_kind,
119
+ )
120
+
121
+
122
+ def _plan(
123
+ audience: PromptAudience,
124
+ *,
125
+ equality_group: str | None = None,
126
+ packet_only: bool = False,
127
+ allow_coding_preflight: bool = False,
128
+ required_headers: tuple[str, ...] = (),
129
+ max_body_lines: int | None = None,
130
+ max_directive_lines: int | None = None,
131
+ ) -> PromptPlan:
132
+ return PromptPlan(
133
+ audience=audience,
134
+ equality_group=equality_group,
135
+ packet_only=packet_only,
136
+ allow_coding_preflight=allow_coding_preflight,
137
+ required_headers=required_headers,
138
+ max_body_lines=max_body_lines,
139
+ max_directive_lines=max_directive_lines,
140
+ )
141
+
142
+
143
+ def _executor_worker_id(manifest: Mapping[str, Any]) -> str | None:
144
+ team_contract = manifest.get("teamContract")
145
+ if not isinstance(team_contract, Mapping):
146
+ return None
147
+ executor = team_contract.get("executor")
148
+ if not isinstance(executor, Mapping):
149
+ return None
150
+ provider = executor.get("provider")
151
+ return provider.strip() if isinstance(provider, str) and provider.strip() else None
152
+
153
+
154
+ def _required_string(payload: Mapping[str, Any], key: str) -> str:
155
+ value = payload.get(key)
156
+ if not isinstance(value, str) or not value.strip():
157
+ raise ValueError(f"missing required string field: {key}")
158
+ return value.strip()
@@ -0,0 +1,51 @@
1
+ # Implementation Worker Prompt Preamble (canonical)
2
+
3
+ This file is shared by the `implementation-executor` and `implementation-verifier` audiences. Read it end-to-end, then read the role sidecar enumerated by the prompt. 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
+ - 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.
14
+
15
+ ## Required reading
16
+
17
+ - Read the implementation role sidecar named by the prompt end-to-end. The executor sidecar owns mutation behavior; the verifier sidecar owns read-only review behavior.
18
+ - Read `overview.md` and `clean-code.md` under `**Coding preflight pack:**`, then follow every matching language, framework, and architecture route before editing or verification.
19
+ - Read the approved implementation deliverable and any effective design-preparation block enumerated by the prompt.
20
+
21
+ ## Worktree and command discipline
22
+
23
+ - `**Worktree:**` is the canonical checkout. Project commands run with that directory as cwd.
24
+ - `.okstra/**` artifacts remain anchored at `**Project Root:**`; the worktree may not contain them.
25
+ - Only the executor may mutate source files. Verifiers remain read-only except for okstra result/audit artifacts and project-declared QA commands.
26
+ - Execute the role sidecar's pre-write, post-write, QA, and return gates without substituting analysis Sections 1–6 or report-authoring instructions.
27
+
28
+ ## Anchor headers
29
+
30
+ Every initial implementation prompt begins with these generated common anchors in this exact order, before its implementation-specific body:
31
+
32
+ 1. `**Project Root:** <absolute-path>`
33
+ 2. `**Prompt History Path:** <project-relative-path>`
34
+ 3. `**Result Path:** <project-relative-path>`
35
+ 4. `Assigned worker prompt history path: <absolute-path>`
36
+ 5. `**Worker Preamble Path:** <absolute-path>`
37
+ 6. `**Worker Error Contract Path:** <absolute-path>`
38
+ 7. `**Coding preflight pack:** <absolute-path>`
39
+ 8. `**Errors log path:** <absolute-path>`
40
+ 9. `**Errors sidecar path:** <absolute-path>`
41
+ 10. `**Read scope:** <allowlist>`
42
+
43
+ The implementation body additionally carries `**Worktree:**` and its role-sidecar inputs. Do not synthesize any missing path.
44
+
45
+ ## Return message to the lead
46
+
47
+ Begin the inline return with the exact `**Model:** <Role>, <modelExecutionValue>` line from the prompt, followed by the role-sidecar status summary. Never invent or abbreviate the model.
48
+
49
+ ## Writing style
50
+
51
+ Use concise evidence-backed prose. Keep identifiers, paths, symbols, model names, CLI flags, and status tokens in English. Translate meaning rather than dictionary words.
@@ -1,10 +1,10 @@
1
1
  # Operating Standard (canonical)
2
2
 
3
3
  This file is the single source of truth for the operating standard injected into
4
- every okstra agent. The "Common core" block below is inlined verbatim into
5
- `templates/worker-prompt-preamble.md` (workers) and
6
- `prompts/lead/okstra-lead-contract.md` (lead). A unit test asserts both inlined
7
- copies match this core — update all three together.
4
+ every okstra agent. The "Common core" block below is inlined verbatim into the
5
+ three audience preambles under `templates/` and
6
+ `prompts/lead/okstra-lead-contract.md` (lead). A unit test asserts every inlined
7
+ copy matches this core — update all copies together.
8
8
 
9
9
  ## Common core
10
10