okstra 0.186.7 → 0.188.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 (546) hide show
  1. package/README.md +1 -1
  2. package/dist/cli-registry.d.mts +88 -1
  3. package/dist/cli-registry.mjs +68 -111
  4. package/dist/cli-registry.mjs.map +1 -1
  5. package/dist/commands/execute/render-bundle.mjs +0 -1
  6. package/dist/commands/execute/render-bundle.mjs.map +1 -1
  7. package/dist/commands/execute/run.mjs +8 -3
  8. package/dist/commands/execute/run.mjs.map +1 -1
  9. package/dist/commands/lifecycle/check-project.mjs +1 -14
  10. package/dist/commands/lifecycle/check-project.mjs.map +1 -1
  11. package/dist/commands/lifecycle/config.mjs +38 -40
  12. package/dist/commands/lifecycle/config.mjs.map +1 -1
  13. package/dist/commands/lifecycle/doctor.d.mts +22 -7
  14. package/dist/commands/lifecycle/doctor.mjs +77 -49
  15. package/dist/commands/lifecycle/doctor.mjs.map +1 -1
  16. package/dist/commands/lifecycle/install.d.mts +12 -10
  17. package/dist/commands/lifecycle/install.mjs +107 -40
  18. package/dist/commands/lifecycle/install.mjs.map +1 -1
  19. package/dist/commands/lifecycle/paths.mjs +8 -3
  20. package/dist/commands/lifecycle/paths.mjs.map +1 -1
  21. package/dist/commands/lifecycle/preflight.mjs +2 -1
  22. package/dist/commands/lifecycle/preflight.mjs.map +1 -1
  23. package/dist/commands/lifecycle/setup.mjs +22 -36
  24. package/dist/commands/lifecycle/setup.mjs.map +1 -1
  25. package/dist/commands/lifecycle/uninstall.d.mts +4 -2
  26. package/dist/commands/lifecycle/uninstall.mjs +59 -15
  27. package/dist/commands/lifecycle/uninstall.mjs.map +1 -1
  28. package/dist/commands/memory/memory.mjs +7 -1
  29. package/dist/commands/memory/memory.mjs.map +1 -1
  30. package/dist/lib/helper-scripts.d.mts +1 -1
  31. package/dist/lib/helper-scripts.mjs +10 -18
  32. package/dist/lib/helper-scripts.mjs.map +1 -1
  33. package/dist/lib/host-config.d.mts +72 -0
  34. package/dist/lib/host-config.mjs +404 -0
  35. package/dist/lib/host-config.mjs.map +1 -0
  36. package/dist/lib/host-registry-client.d.mts +2 -2
  37. package/dist/lib/host-registry-client.mjs +0 -3
  38. package/dist/lib/host-registry-client.mjs.map +1 -1
  39. package/dist/lib/install-assets.d.mts +1 -0
  40. package/dist/lib/install-assets.mjs +4 -0
  41. package/dist/lib/install-assets.mjs.map +1 -1
  42. package/dist/lib/proc.d.mts +2 -0
  43. package/dist/lib/proc.mjs +12 -0
  44. package/dist/lib/proc.mjs.map +1 -1
  45. package/dist/lib/python-command.d.mts +2 -0
  46. package/dist/lib/python-command.mjs +52 -0
  47. package/dist/lib/python-command.mjs.map +1 -0
  48. package/dist/lib/python-helper.d.mts +2 -5
  49. package/dist/lib/python-helper.mjs +3 -52
  50. package/dist/lib/python-helper.mjs.map +1 -1
  51. package/dist/lib/runtime-payload.d.mts +23 -0
  52. package/dist/lib/runtime-payload.mjs +57 -0
  53. package/dist/lib/runtime-payload.mjs.map +1 -0
  54. package/dist/lib/types.d.mts +24 -13
  55. package/docs/architecture/storage-model.md +21 -5
  56. package/docs/architecture.md +39 -38
  57. package/docs/cli.md +55 -76
  58. package/docs/coding-rules.md +295 -0
  59. package/docs/container.md +10 -36
  60. package/docs/contributor-change-matrix.md +1 -1
  61. package/docs/for-ai/skills/okstra-code-review.md +0 -1
  62. package/docs/for-ai/skills/okstra-container-build.md +8 -41
  63. package/docs/for-ai/skills/okstra-inspect.md +4 -4
  64. package/docs/for-ai/skills/okstra-manager.md +2 -2
  65. package/docs/for-ai/skills/okstra-rollup.md +0 -1
  66. package/docs/for-ai/skills/okstra-run.md +3 -3
  67. package/docs/for-ai/skills/okstra-user-response.md +0 -1
  68. package/docs/performance-improvement-plan-v2.md +1 -1
  69. package/docs/project-structure-overview.md +62 -62
  70. package/docs/task-process/README.md +3 -3
  71. package/docs/task-process/common-flow.md +1 -1
  72. package/docs/task-process/error-analysis.md +3 -3
  73. package/docs/task-process/implementation-planning.md +3 -1
  74. package/docs/task-process/release-handoff.md +1 -1
  75. package/package.json +3 -2
  76. package/runtime/BUILD.json +2 -2
  77. package/runtime/agents/workers/claude-worker.md +6 -11
  78. package/runtime/agents/workers/report-writer-worker.md +1 -1
  79. package/runtime/bin/lib/okstra/cli.sh +4 -0
  80. package/runtime/bin/lib/okstra/globals.sh +2 -0
  81. package/runtime/bin/lib/okstra/interactive.sh +26 -173
  82. package/runtime/bin/lib/okstra/project-resolver.sh +23 -61
  83. package/runtime/bin/lib/okstra/usage.sh +3 -3
  84. package/runtime/bin/okstra-compact-reminder.sh +1 -5
  85. package/runtime/bin/okstra-error-log.py +19 -2
  86. package/runtime/bin/okstra-import-check.py +26 -0
  87. package/runtime/bin/okstra-inject-report-index.py +5 -4
  88. package/runtime/bin/okstra-provider-exec.py +22 -17
  89. package/runtime/bin/okstra-render-final-report.py +16 -6
  90. package/runtime/bin/okstra-render-report-views.py +47 -22
  91. package/runtime/bin/okstra-report-translate.py +30 -18
  92. package/runtime/bin/okstra-spawn-followups.py +4 -0
  93. package/runtime/bin/okstra-token-usage.py +3 -0
  94. package/runtime/bin/okstra.sh +4 -2
  95. package/runtime/bin/okstra_bootstrap.py +58 -0
  96. package/runtime/prompts/coding-preflight/overview.md +1 -1
  97. package/runtime/prompts/duties/planning-worker.md +1 -1
  98. package/runtime/prompts/launch.template.md +35 -9
  99. package/runtime/prompts/lead/adapters/cmux.md +3 -3
  100. package/runtime/prompts/lead/convergence.md +99 -88
  101. package/runtime/prompts/lead/okstra-lead-contract.md +63 -12
  102. package/runtime/prompts/lead/plan-body-verification.md +65 -46
  103. package/runtime/prompts/lead/report-writer.md +35 -5
  104. package/runtime/prompts/lead/team-contract.md +4 -1
  105. package/runtime/prompts/profiles/_clarification-recommendation.md +2 -1
  106. package/runtime/prompts/profiles/_coding-conventions-preflight.md +1 -1
  107. package/runtime/prompts/profiles/_common-contract.md +3 -3
  108. package/runtime/prompts/profiles/_coverage-critic.md +1 -1
  109. package/runtime/prompts/profiles/_implementation-deliverable.md +2 -2
  110. package/runtime/prompts/profiles/_implementation-executor.md +3 -1
  111. package/runtime/prompts/profiles/_implementation-verifier.md +16 -2
  112. package/runtime/prompts/profiles/error-analysis.md +4 -3
  113. package/runtime/prompts/profiles/final-verification.md +2 -2
  114. package/runtime/prompts/profiles/implementation-planning.md +22 -17
  115. package/runtime/prompts/profiles/implementation.md +3 -2
  116. package/runtime/prompts/profiles/requirements-discovery.md +2 -1
  117. package/runtime/prompts/wizard/prompts.ko.json +29 -8
  118. package/runtime/python/okstra_ctl/__init__.py +6 -27
  119. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/relay.md +4 -5
  120. package/runtime/python/okstra_ctl/adapters/hosts/codex/adapter.py +21 -2
  121. package/runtime/python/okstra_ctl/adapters/hosts/external/adapter.py +3 -12
  122. package/runtime/python/okstra_ctl/adapters/providers/antigravity/adapter.py +63 -22
  123. package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +20 -21
  124. package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +37 -20
  125. package/runtime/python/okstra_ctl/adapters/providers/grok/adapter.py +86 -14
  126. package/runtime/python/okstra_ctl/adapters/providers/kimi/adapter.py +12 -12
  127. package/runtime/python/okstra_ctl/adapters/runtime/cmux.py +4 -7
  128. package/runtime/python/okstra_ctl/agent/__init__.py +1 -0
  129. package/runtime/python/okstra_ctl/{agent_activity.py → agent/activity.py} +16 -2
  130. package/runtime/python/okstra_ctl/{agent_invocation.py → agent/invocation.py} +34 -5
  131. package/runtime/python/okstra_ctl/agent/prompt_cli/__init__.py +19 -0
  132. package/runtime/python/okstra_ctl/agent/prompt_cli/__main__.py +11 -0
  133. package/runtime/python/okstra_ctl/agent/prompt_cli/cli.py +228 -0
  134. package/runtime/python/okstra_ctl/agent/prompt_cli/dynamic_verifier.py +155 -0
  135. package/runtime/python/okstra_ctl/agent/prompt_cli/emit.py +66 -0
  136. package/runtime/python/okstra_ctl/agent/prompt_cli/inputs.py +138 -0
  137. package/runtime/python/okstra_ctl/agent/prompt_cli/materialize.py +605 -0
  138. package/runtime/python/okstra_ctl/agent/prompt_cli/results.py +197 -0
  139. package/runtime/python/okstra_ctl/agent/prompt_cli/run_identity.py +107 -0
  140. package/runtime/python/okstra_ctl/analysis_packet.py +47 -4
  141. package/runtime/python/okstra_ctl/approval_decisions.py +287 -10
  142. package/runtime/python/okstra_ctl/assignment_resolver.py +0 -12
  143. package/runtime/python/okstra_ctl/attempt_evidence.py +12 -24
  144. package/runtime/python/okstra_ctl/blocking_checks.py +251 -0
  145. package/runtime/python/okstra_ctl/brief_frontmatter.py +0 -7
  146. package/runtime/python/okstra_ctl/clarification_items/__init__.py +102 -0
  147. package/runtime/python/okstra_ctl/clarification_items/carry.py +224 -0
  148. package/runtime/python/okstra_ctl/clarification_items/dispositions.py +135 -0
  149. package/runtime/python/okstra_ctl/clarification_items/parsing.py +253 -0
  150. package/runtime/python/okstra_ctl/clarification_items/rows.py +115 -0
  151. package/runtime/python/okstra_ctl/clarification_items/scan.py +215 -0
  152. package/runtime/python/okstra_ctl/clarification_items/sidecars.py +211 -0
  153. package/runtime/python/okstra_ctl/cmux.py +38 -31
  154. package/runtime/python/okstra_ctl/code_review_target.py +163 -1
  155. package/runtime/python/okstra_ctl/conformance.py +23 -0
  156. package/runtime/python/okstra_ctl/container.py +38 -421
  157. package/runtime/python/okstra_ctl/context_cost.py +32 -4
  158. package/runtime/python/okstra_ctl/contract_graph_cli.py +7 -0
  159. package/runtime/python/okstra_ctl/convergence.py +107 -16
  160. package/runtime/python/okstra_ctl/convergence_critic_prompt.py +345 -0
  161. package/runtime/python/okstra_ctl/convergence_engine.py +382 -70
  162. package/runtime/python/okstra_ctl/convergence_store.py +5 -29
  163. package/runtime/python/okstra_ctl/design_prep.py +108 -12
  164. package/runtime/python/okstra_ctl/design_snapshot.py +11 -1
  165. package/runtime/python/okstra_ctl/design_surfaces.py +29 -2
  166. package/runtime/python/okstra_ctl/dispatch_core.py +236 -49
  167. package/runtime/python/okstra_ctl/dispatch_state.py +417 -41
  168. package/runtime/python/okstra_ctl/doctor_cli.py +48 -0
  169. package/runtime/python/okstra_ctl/domain/worker_exec.py +10 -5
  170. package/runtime/python/okstra_ctl/domain/worker_presentation.py +28 -1
  171. package/runtime/python/okstra_ctl/domain/worker_stream.py +52 -21
  172. package/runtime/python/okstra_ctl/domain/write_policy.py +219 -0
  173. package/runtime/python/okstra_ctl/entrypoints/hosts.py +9 -2
  174. package/runtime/python/okstra_ctl/error_log_core.py +1 -1
  175. package/runtime/python/okstra_ctl/error_report.py +14 -0
  176. package/runtime/python/okstra_ctl/error_zip.py +18 -2
  177. package/runtime/python/okstra_ctl/exact_coverage.py +5 -0
  178. package/runtime/python/okstra_ctl/execution_identity.py +100 -7
  179. package/runtime/python/okstra_ctl/execution_manifest.py +67 -20
  180. package/runtime/python/okstra_ctl/execution_mutation_audit.py +90 -8
  181. package/runtime/python/okstra_ctl/final_report_paths.py +17 -0
  182. package/runtime/python/okstra_ctl/final_report_schema.py +319 -17
  183. package/runtime/python/okstra_ctl/git_reconcile.py +22 -2
  184. package/runtime/python/okstra_ctl/handoff.py +24 -1
  185. package/runtime/python/okstra_ctl/ids.py +6 -16
  186. package/runtime/python/okstra_ctl/implementation_direction.py +142 -33
  187. package/runtime/python/okstra_ctl/implementation_options.py +32 -13
  188. package/runtime/python/okstra_ctl/implementation_outcome.py +5 -2
  189. package/runtime/python/okstra_ctl/improvement_lenses.py +0 -14
  190. package/runtime/python/okstra_ctl/incremental_carry.py +69 -8
  191. package/runtime/python/okstra_ctl/incremental_scope.py +173 -12
  192. package/runtime/python/okstra_ctl/index.py +2 -2
  193. package/runtime/python/okstra_ctl/initial_prompt_materialization.py +48 -8
  194. package/runtime/python/okstra_ctl/interactive_cli.py +223 -0
  195. package/runtime/python/okstra_ctl/json_boundary.py +10 -0
  196. package/runtime/python/okstra_ctl/listing.py +0 -91
  197. package/runtime/python/okstra_ctl/locks.py +5 -19
  198. package/runtime/python/okstra_ctl/log_report.py +14 -0
  199. package/runtime/python/okstra_ctl/manager_cli.py +22 -3
  200. package/runtime/python/okstra_ctl/manager_launch.py +4 -8
  201. package/runtime/python/okstra_ctl/material.py +2 -2
  202. package/runtime/python/okstra_ctl/migrate.py +23 -1
  203. package/runtime/python/okstra_ctl/model_cli.py +19 -5
  204. package/runtime/python/okstra_ctl/model_discovery.py +46 -47
  205. package/runtime/python/okstra_ctl/model_io/__init__.py +1 -0
  206. package/runtime/python/okstra_ctl/model_io/lines.py +163 -0
  207. package/runtime/python/okstra_ctl/model_io/references.py +370 -0
  208. package/runtime/python/okstra_ctl/model_io/renderers.py +498 -0
  209. package/runtime/python/okstra_ctl/model_io_cli.py +30 -945
  210. package/runtime/python/okstra_ctl/model_pool.py +10 -6
  211. package/runtime/python/okstra_ctl/models.py +8 -8
  212. package/runtime/python/okstra_ctl/mutation_recovery.py +5 -63
  213. package/runtime/python/okstra_ctl/next_phase.py +121 -69
  214. package/runtime/python/okstra_ctl/pane_reclaim.py +23 -0
  215. package/runtime/python/okstra_ctl/pane_title.py +11 -8
  216. package/runtime/python/okstra_ctl/path_hints.py +36 -11
  217. package/runtime/python/okstra_ctl/paths.py +76 -8
  218. package/runtime/python/okstra_ctl/plan_items.py +132 -16
  219. package/runtime/python/okstra_ctl/plan_items_cli.py +486 -36
  220. package/runtime/python/okstra_ctl/plan_run_root.py +1 -1
  221. package/runtime/python/okstra_ctl/plan_validate_cli.py +51 -0
  222. package/runtime/python/okstra_ctl/plan_verify_cli.py +80 -0
  223. package/runtime/python/okstra_ctl/prepare_error.py +20 -0
  224. package/runtime/python/okstra_ctl/prior_planning.py +157 -0
  225. package/runtime/python/okstra_ctl/profile_show.py +18 -1
  226. package/runtime/python/okstra_ctl/project_setup_cli.py +140 -0
  227. package/runtime/python/okstra_ctl/recap.py +22 -1
  228. package/runtime/python/okstra_ctl/reconcile.py +84 -0
  229. package/runtime/python/okstra_ctl/registry/host_registry.py +18 -1
  230. package/runtime/python/okstra_ctl/render.py +98 -32
  231. package/runtime/python/okstra_ctl/render_final_report.py +4 -8
  232. package/runtime/python/okstra_ctl/report_assembly.py +297 -7
  233. package/runtime/python/okstra_ctl/report_contract.py +30 -7
  234. package/runtime/python/okstra_ctl/report_finalize.py +213 -16
  235. package/runtime/python/okstra_ctl/report_html/common.py +2 -2
  236. package/runtime/python/okstra_ctl/report_html/render.py +8 -12
  237. package/runtime/python/okstra_ctl/report_language.py +8 -4
  238. package/runtime/python/okstra_ctl/report_narrative.py +220 -34
  239. package/runtime/python/okstra_ctl/report_projections.py +8 -2
  240. package/runtime/python/okstra_ctl/report_synthesis_packet.py +393 -1
  241. package/runtime/python/okstra_ctl/report_translation.py +2 -35
  242. package/runtime/python/okstra_ctl/report_view_artifacts.py +42 -2
  243. package/runtime/python/okstra_ctl/report_views.py +4 -22
  244. package/runtime/python/okstra_ctl/resolve_task_key.py +13 -0
  245. package/runtime/python/okstra_ctl/rollup.py +13 -0
  246. package/runtime/python/okstra_ctl/run.py +639 -138
  247. package/runtime/python/okstra_ctl/run_audit.py +13 -0
  248. package/runtime/python/okstra_ctl/run_index_row.py +0 -12
  249. package/runtime/python/okstra_ctl/seeding.py +21 -11
  250. package/runtime/python/okstra_ctl/sequence.py +1 -1
  251. package/runtime/python/okstra_ctl/session.py +64 -14
  252. package/runtime/python/okstra_ctl/set_work_status.py +18 -0
  253. package/runtime/python/okstra_ctl/stage_integrate.py +15 -1
  254. package/runtime/python/okstra_ctl/stage_ledger.py +1 -1
  255. package/runtime/python/okstra_ctl/stage_map.py +57 -11
  256. package/runtime/python/okstra_ctl/stage_map_cli.py +83 -0
  257. package/runtime/python/okstra_ctl/stage_map_view.py +65 -0
  258. package/runtime/python/okstra_ctl/stage_targets.py +3 -12
  259. package/runtime/python/okstra_ctl/task_list_cli.py +138 -0
  260. package/runtime/python/okstra_ctl/task_show_cli.py +66 -0
  261. package/runtime/python/okstra_ctl/task_target.py +4 -16
  262. package/runtime/python/okstra_ctl/team.py +49 -2
  263. package/runtime/python/okstra_ctl/time_report.py +17 -2
  264. package/runtime/python/okstra_ctl/usage_report.py +11 -0
  265. package/runtime/python/okstra_ctl/user_response.py +55 -218
  266. package/runtime/python/okstra_ctl/user_response_values.py +242 -0
  267. package/runtime/python/okstra_ctl/validation_contract.py +3 -0
  268. package/runtime/python/okstra_ctl/verdict_blocks.py +28 -8
  269. package/runtime/python/okstra_ctl/verification_target.py +68 -0
  270. package/runtime/python/okstra_ctl/wizard.py +457 -92
  271. package/runtime/python/okstra_ctl/worker_artifacts.py +75 -16
  272. package/runtime/python/okstra_ctl/worker_audit_check.py +22 -0
  273. package/runtime/python/okstra_ctl/worker_dispatch.py +21 -0
  274. package/runtime/python/okstra_ctl/worker_liveness.py +33 -0
  275. package/runtime/python/okstra_ctl/worker_prompt_body.py +15 -2
  276. package/runtime/python/okstra_ctl/worker_prompt_contract.py +98 -7
  277. package/runtime/python/okstra_ctl/worker_prompt_headers.py +24 -2
  278. package/runtime/python/okstra_ctl/worker_prompt_policy.py +18 -3
  279. package/runtime/python/okstra_ctl/worker_request.py +2 -1
  280. package/runtime/python/okstra_ctl/worker_runner.py +58 -17
  281. package/runtime/python/okstra_ctl/worker_state.py +16 -1
  282. package/runtime/python/okstra_ctl/workflow.py +18 -1
  283. package/runtime/python/okstra_ctl/worktree/__init__.py +92 -0
  284. package/runtime/python/okstra_ctl/worktree/cleanliness.py +89 -0
  285. package/runtime/python/okstra_ctl/worktree/decisions.py +127 -0
  286. package/runtime/python/okstra_ctl/worktree/git_ops.py +165 -0
  287. package/runtime/python/okstra_ctl/worktree/linking.py +249 -0
  288. package/runtime/python/okstra_ctl/worktree/naming.py +91 -0
  289. package/runtime/python/okstra_ctl/worktree/provision.py +385 -0
  290. package/runtime/python/okstra_ctl/worktree/sync_config.py +181 -0
  291. package/runtime/python/okstra_ctl/worktree_cli.py +75 -0
  292. package/runtime/python/okstra_ctl/worktree_lookup_cli.py +39 -0
  293. package/runtime/python/okstra_ctl/worktree_registry.py +7 -0
  294. package/runtime/python/okstra_ctl/worktree_status_cli.py +53 -0
  295. package/runtime/python/okstra_ctl/write_policy.py +90 -213
  296. package/runtime/python/okstra_project/__init__.py +0 -4
  297. package/runtime/python/okstra_project/dirs.py +2 -2
  298. package/runtime/python/okstra_project/phase_pointer.py +84 -0
  299. package/runtime/python/okstra_project/slug.py +24 -0
  300. package/runtime/python/okstra_project/state.py +22 -230
  301. package/runtime/python/okstra_token_usage/antigravity.py +50 -12
  302. package/runtime/python/okstra_token_usage/claude.py +9 -1
  303. package/runtime/python/okstra_token_usage/cli.py +3 -1
  304. package/runtime/python/okstra_token_usage/collect.py +171 -36
  305. package/runtime/python/okstra_token_usage/cursor.py +2 -0
  306. package/runtime/python/okstra_token_usage/grok.py +1 -5
  307. package/runtime/python/okstra_token_usage/paths.py +26 -0
  308. package/runtime/python/okstra_token_usage/pricing.py +23 -8
  309. package/runtime/schemas/convergence-critic-results-v1.0.schema.json +5 -0
  310. package/runtime/schemas/execution-manifest-v2.schema.json +10 -10
  311. package/runtime/schemas/final-report-v2.0.schema.json +9 -26
  312. package/runtime/schemas/final-report-v3.0.schema.json +173 -41
  313. package/runtime/schemas/report-narrative-v3.0.schema.json +3 -2
  314. package/runtime/skills/okstra-brief-gen/SKILL.md +35 -2
  315. package/runtime/skills/okstra-container-build/SKILL.md +16 -47
  316. package/runtime/skills/okstra-inspect/facets/history.md +1 -1
  317. package/runtime/skills/okstra-inspect/facets/status.md +7 -6
  318. package/runtime/skills/okstra-pr-gen/SKILL.md +1 -1
  319. package/runtime/skills/okstra-run/SKILL.md +7 -5
  320. package/runtime/templates/report-writer-prompt-preamble.md +3 -1
  321. package/runtime/templates/reports/brief.template.md +6 -2
  322. package/runtime/templates/reports/error-analysis-input.template.md +2 -0
  323. package/runtime/templates/reports/final-verification-input.template.md +2 -0
  324. package/runtime/templates/reports/implementation-input.template.md +7 -1
  325. package/runtime/templates/reports/implementation-planning-input.template.md +4 -0
  326. package/runtime/templates/reports/quick-input.template.md +2 -0
  327. package/runtime/templates/reports/release-handoff-input.template.md +6 -1
  328. package/runtime/templates/reports/report.js +20 -3
  329. package/runtime/templates/reports/schedule.template.md +2 -0
  330. package/runtime/templates/reports/settings.template.json +0 -10
  331. package/runtime/templates/reports/task-brief.template.md +3 -0
  332. package/runtime/templates/reports/user-response.template.md +7 -3
  333. package/runtime/validators/checks/fixtures-01.py +57 -0
  334. package/runtime/validators/checks/fixtures-02.py +565 -0
  335. package/runtime/validators/checks/runners-01.py +108 -0
  336. package/runtime/validators/checks/validate-assets-01.py +60 -0
  337. package/runtime/validators/checks/validate-prompt-metadata-01.py +261 -0
  338. package/runtime/validators/checks/validate-tasks-01.py +46 -0
  339. package/runtime/validators/checks/validate-tasks-02.py +85 -0
  340. package/runtime/validators/checks/validate-tasks-03.py +61 -0
  341. package/runtime/validators/checks/validate-tasks-04.py +118 -0
  342. package/runtime/validators/forbidden_actions.py +73 -3
  343. package/runtime/validators/lib/common.sh +5 -0
  344. package/runtime/validators/lib/fixtures.sh +7 -591
  345. package/runtime/validators/lib/paths.sh +13 -0
  346. package/runtime/validators/lib/runners.sh +6 -104
  347. package/runtime/validators/lib/summary.sh +1 -1
  348. package/runtime/validators/lib/validate-assets.sh +6 -56
  349. package/runtime/validators/lib/validate-prompt-metadata.sh +6 -257
  350. package/runtime/validators/lib/validate-tasks.sh +9 -294
  351. package/runtime/validators/validate-implementation-plan-stages.py +4 -4
  352. package/runtime/validators/validate-run.py +1363 -2643
  353. package/runtime/validators/validate-workflow.sh +56 -16
  354. package/runtime/validators/validate_improvement_report.py +2 -1
  355. package/runtime/validators/validate_session_conformance.py +295 -49
  356. package/dist/commands/execute/agent-prompt.d.mts +0 -1
  357. package/dist/commands/execute/agent-prompt.mjs +0 -24
  358. package/dist/commands/execute/agent-prompt.mjs.map +0 -1
  359. package/dist/commands/execute/codex-dispatch.d.mts +0 -3
  360. package/dist/commands/execute/codex-dispatch.mjs +0 -6
  361. package/dist/commands/execute/codex-dispatch.mjs.map +0 -1
  362. package/dist/commands/execute/codex-run.d.mts +0 -3
  363. package/dist/commands/execute/codex-run.mjs +0 -62
  364. package/dist/commands/execute/codex-run.mjs.map +0 -1
  365. package/dist/commands/execute/convergence.d.mts +0 -1
  366. package/dist/commands/execute/convergence.mjs +0 -38
  367. package/dist/commands/execute/convergence.mjs.map +0 -1
  368. package/dist/commands/execute/error-log.d.mts +0 -1
  369. package/dist/commands/execute/error-log.mjs +0 -18
  370. package/dist/commands/execute/error-log.mjs.map +0 -1
  371. package/dist/commands/execute/git-reconcile.d.mts +0 -1
  372. package/dist/commands/execute/git-reconcile.mjs +0 -30
  373. package/dist/commands/execute/git-reconcile.mjs.map +0 -1
  374. package/dist/commands/execute/handoff.d.mts +0 -1
  375. package/dist/commands/execute/handoff.mjs +0 -31
  376. package/dist/commands/execute/handoff.mjs.map +0 -1
  377. package/dist/commands/execute/incremental-carry.d.mts +0 -1
  378. package/dist/commands/execute/incremental-carry.mjs +0 -20
  379. package/dist/commands/execute/incremental-carry.mjs.map +0 -1
  380. package/dist/commands/execute/incremental-scope.d.mts +0 -1
  381. package/dist/commands/execute/incremental-scope.mjs +0 -29
  382. package/dist/commands/execute/incremental-scope.mjs.map +0 -1
  383. package/dist/commands/execute/integrate-stages.d.mts +0 -1
  384. package/dist/commands/execute/integrate-stages.mjs +0 -24
  385. package/dist/commands/execute/integrate-stages.mjs.map +0 -1
  386. package/dist/commands/execute/pane-title.d.mts +0 -1
  387. package/dist/commands/execute/pane-title.mjs +0 -20
  388. package/dist/commands/execute/pane-title.mjs.map +0 -1
  389. package/dist/commands/execute/plan-items.d.mts +0 -1
  390. package/dist/commands/execute/plan-items.mjs +0 -9
  391. package/dist/commands/execute/plan-items.mjs.map +0 -1
  392. package/dist/commands/execute/plan-validate.d.mts +0 -1
  393. package/dist/commands/execute/plan-validate.mjs +0 -68
  394. package/dist/commands/execute/plan-validate.mjs.map +0 -1
  395. package/dist/commands/execute/plan-verify.d.mts +0 -1
  396. package/dist/commands/execute/plan-verify.mjs +0 -43
  397. package/dist/commands/execute/plan-verify.mjs.map +0 -1
  398. package/dist/commands/execute/spawn-followups.d.mts +0 -1
  399. package/dist/commands/execute/spawn-followups.mjs +0 -22
  400. package/dist/commands/execute/spawn-followups.mjs.map +0 -1
  401. package/dist/commands/execute/team.d.mts +0 -3
  402. package/dist/commands/execute/team.mjs +0 -66
  403. package/dist/commands/execute/team.mjs.map +0 -1
  404. package/dist/commands/execute/token-usage.d.mts +0 -1
  405. package/dist/commands/execute/token-usage.mjs +0 -19
  406. package/dist/commands/execute/token-usage.mjs.map +0 -1
  407. package/dist/commands/execute/worker-audit-check.d.mts +0 -1
  408. package/dist/commands/execute/worker-audit-check.mjs +0 -34
  409. package/dist/commands/execute/worker-audit-check.mjs.map +0 -1
  410. package/dist/commands/execute/worker-dispatch.d.mts +0 -7
  411. package/dist/commands/execute/worker-dispatch.mjs +0 -64
  412. package/dist/commands/execute/worker-dispatch.mjs.map +0 -1
  413. package/dist/commands/execute/worker-state.d.mts +0 -1
  414. package/dist/commands/execute/worker-state.mjs +0 -28
  415. package/dist/commands/execute/worker-state.mjs.map +0 -1
  416. package/dist/commands/execute/worktree-lookup.d.mts +0 -1
  417. package/dist/commands/execute/worktree-lookup.mjs +0 -92
  418. package/dist/commands/execute/worktree-lookup.mjs.map +0 -1
  419. package/dist/commands/execute/worktree-status.d.mts +0 -1
  420. package/dist/commands/execute/worktree-status.mjs +0 -121
  421. package/dist/commands/execute/worktree-status.mjs.map +0 -1
  422. package/dist/commands/inspect/code-review.d.mts +0 -1
  423. package/dist/commands/inspect/code-review.mjs +0 -32
  424. package/dist/commands/inspect/code-review.mjs.map +0 -1
  425. package/dist/commands/inspect/container.d.mts +0 -1
  426. package/dist/commands/inspect/container.mjs +0 -25
  427. package/dist/commands/inspect/container.mjs.map +0 -1
  428. package/dist/commands/inspect/context-cost.d.mts +0 -1
  429. package/dist/commands/inspect/context-cost.mjs +0 -25
  430. package/dist/commands/inspect/context-cost.mjs.map +0 -1
  431. package/dist/commands/inspect/design-prep.d.mts +0 -1
  432. package/dist/commands/inspect/design-prep.mjs +0 -22
  433. package/dist/commands/inspect/design-prep.mjs.map +0 -1
  434. package/dist/commands/inspect/error-report.d.mts +0 -1
  435. package/dist/commands/inspect/error-report.mjs +0 -25
  436. package/dist/commands/inspect/error-report.mjs.map +0 -1
  437. package/dist/commands/inspect/error-zip.d.mts +0 -1
  438. package/dist/commands/inspect/error-zip.mjs +0 -24
  439. package/dist/commands/inspect/error-zip.mjs.map +0 -1
  440. package/dist/commands/inspect/log-report.d.mts +0 -1
  441. package/dist/commands/inspect/log-report.mjs +0 -26
  442. package/dist/commands/inspect/log-report.mjs.map +0 -1
  443. package/dist/commands/inspect/model-io.d.mts +0 -1
  444. package/dist/commands/inspect/model-io.mjs +0 -25
  445. package/dist/commands/inspect/model-io.mjs.map +0 -1
  446. package/dist/commands/inspect/profile-show.d.mts +0 -1
  447. package/dist/commands/inspect/profile-show.mjs +0 -28
  448. package/dist/commands/inspect/profile-show.mjs.map +0 -1
  449. package/dist/commands/inspect/recap.d.mts +0 -1
  450. package/dist/commands/inspect/recap.mjs +0 -30
  451. package/dist/commands/inspect/recap.mjs.map +0 -1
  452. package/dist/commands/inspect/resolve-task-key.d.mts +0 -1
  453. package/dist/commands/inspect/resolve-task-key.mjs +0 -24
  454. package/dist/commands/inspect/resolve-task-key.mjs.map +0 -1
  455. package/dist/commands/inspect/rollup.d.mts +0 -1
  456. package/dist/commands/inspect/rollup.mjs +0 -25
  457. package/dist/commands/inspect/rollup.mjs.map +0 -1
  458. package/dist/commands/inspect/run-audit.d.mts +0 -1
  459. package/dist/commands/inspect/run-audit.mjs +0 -25
  460. package/dist/commands/inspect/run-audit.mjs.map +0 -1
  461. package/dist/commands/inspect/set-work-status.d.mts +0 -1
  462. package/dist/commands/inspect/set-work-status.mjs +0 -29
  463. package/dist/commands/inspect/set-work-status.mjs.map +0 -1
  464. package/dist/commands/inspect/stage-map.d.mts +0 -1
  465. package/dist/commands/inspect/stage-map.mjs +0 -131
  466. package/dist/commands/inspect/stage-map.mjs.map +0 -1
  467. package/dist/commands/inspect/task-list.d.mts +0 -1
  468. package/dist/commands/inspect/task-list.mjs +0 -149
  469. package/dist/commands/inspect/task-list.mjs.map +0 -1
  470. package/dist/commands/inspect/task-show.d.mts +0 -1
  471. package/dist/commands/inspect/task-show.mjs +0 -108
  472. package/dist/commands/inspect/task-show.mjs.map +0 -1
  473. package/dist/commands/inspect/time-report.d.mts +0 -1
  474. package/dist/commands/inspect/time-report.mjs +0 -24
  475. package/dist/commands/inspect/time-report.mjs.map +0 -1
  476. package/dist/commands/inspect/usage-report.d.mts +0 -1
  477. package/dist/commands/inspect/usage-report.mjs +0 -23
  478. package/dist/commands/inspect/usage-report.mjs.map +0 -1
  479. package/dist/commands/inspect/user-response.d.mts +0 -1
  480. package/dist/commands/inspect/user-response.mjs +0 -35
  481. package/dist/commands/inspect/user-response.mjs.map +0 -1
  482. package/dist/commands/inspect/worker-liveness.d.mts +0 -1
  483. package/dist/commands/inspect/worker-liveness.mjs +0 -45
  484. package/dist/commands/inspect/worker-liveness.mjs.map +0 -1
  485. package/dist/commands/lifecycle/contract-check.d.mts +0 -1
  486. package/dist/commands/lifecycle/contract-check.mjs +0 -18
  487. package/dist/commands/lifecycle/contract-check.mjs.map +0 -1
  488. package/dist/commands/lifecycle/migrate.d.mts +0 -1
  489. package/dist/commands/lifecycle/migrate.mjs +0 -30
  490. package/dist/commands/lifecycle/migrate.mjs.map +0 -1
  491. package/dist/commands/lifecycle/model.d.mts +0 -1
  492. package/dist/commands/lifecycle/model.mjs +0 -22
  493. package/dist/commands/lifecycle/model.mjs.map +0 -1
  494. package/dist/commands/manager.d.mts +0 -3
  495. package/dist/commands/manager.mjs +0 -50
  496. package/dist/commands/manager.mjs.map +0 -1
  497. package/dist/commands/report/agent-activity.d.mts +0 -1
  498. package/dist/commands/report/agent-activity.mjs +0 -20
  499. package/dist/commands/report/agent-activity.mjs.map +0 -1
  500. package/dist/commands/report/approval-decision.d.mts +0 -1
  501. package/dist/commands/report/approval-decision.mjs +0 -21
  502. package/dist/commands/report/approval-decision.mjs.map +0 -1
  503. package/dist/commands/report/design-snapshot.d.mts +0 -1
  504. package/dist/commands/report/design-snapshot.mjs +0 -19
  505. package/dist/commands/report/design-snapshot.mjs.map +0 -1
  506. package/dist/commands/report/finalize.d.mts +0 -4
  507. package/dist/commands/report/finalize.mjs +0 -64
  508. package/dist/commands/report/finalize.mjs.map +0 -1
  509. package/dist/commands/report/inject-report-index.d.mts +0 -1
  510. package/dist/commands/report/inject-report-index.mjs +0 -21
  511. package/dist/commands/report/inject-report-index.mjs.map +0 -1
  512. package/dist/commands/report/render-final-report.d.mts +0 -1
  513. package/dist/commands/report/render-final-report.mjs +0 -23
  514. package/dist/commands/report/render-final-report.mjs.map +0 -1
  515. package/dist/commands/report/render-views.d.mts +0 -1
  516. package/dist/commands/report/render-views.mjs +0 -27
  517. package/dist/commands/report/render-views.mjs.map +0 -1
  518. package/dist/commands/report/translate.d.mts +0 -1
  519. package/dist/commands/report/translate.mjs +0 -33
  520. package/dist/commands/report/translate.mjs.map +0 -1
  521. package/runtime/bin/lib/okstra/tmux-pane.sh +0 -40
  522. package/runtime/bin/lib/okstra-ctl/cmd-batch.sh +0 -59
  523. package/runtime/bin/lib/okstra-ctl/cmd-list.sh +0 -35
  524. package/runtime/bin/lib/okstra-ctl/cmd-open.sh +0 -36
  525. package/runtime/bin/lib/okstra-ctl/cmd-projects.sh +0 -26
  526. package/runtime/bin/lib/okstra-ctl/cmd-reconcile.sh +0 -29
  527. package/runtime/bin/lib/okstra-ctl/cmd-reindex.sh +0 -38
  528. package/runtime/bin/lib/okstra-ctl/cmd-rerun.sh +0 -345
  529. package/runtime/bin/lib/okstra-ctl/cmd-show.sh +0 -27
  530. package/runtime/bin/lib/okstra-ctl/cmd-tail.sh +0 -92
  531. package/runtime/bin/lib/okstra-ctl/main.sh +0 -41
  532. package/runtime/bin/lib/okstra-ctl/prepare.sh +0 -31
  533. package/runtime/bin/lib/okstra-ctl/usage.sh +0 -23
  534. package/runtime/bin/okstra-central.sh +0 -152
  535. package/runtime/bin/okstra-incremental-carry.py +0 -10
  536. package/runtime/bin/okstra-incremental-scope.py +0 -10
  537. package/runtime/bin/okstra-team-reconcile.sh +0 -36
  538. package/runtime/python/okstra_ctl/agent_prompt_cli.py +0 -1156
  539. package/runtime/python/okstra_ctl/batch.py +0 -60
  540. package/runtime/python/okstra_ctl/clarification_items.py +0 -1050
  541. package/runtime/python/okstra_ctl/container_registry.py +0 -72
  542. package/runtime/python/okstra_ctl/improvement_assignment.py +0 -61
  543. package/runtime/python/okstra_ctl/resolver.py +0 -54
  544. package/runtime/python/okstra_ctl/team_reconcile.py +0 -275
  545. package/runtime/python/okstra_ctl/tmux.py +0 -134
  546. package/runtime/python/okstra_ctl/worktree.py +0 -1099
@@ -0,0 +1,60 @@
1
+ """validate-assets-01 — 셸 시나리오에서 꺼낸 단언 블록.
2
+
3
+ 호출부: validators/lib/validate-assets.sh:23
4
+ 규칙 R1 은 실행될 소스를 문자열/heredoc 이 아니라 실파일에 두게 한다.
5
+ 이 파일의 내용은 꺼내기 전과 같다 — 옮기기만 했다.
6
+ """
7
+ from pathlib import Path
8
+ import sys
9
+
10
+ agents_source_root = Path(sys.argv[1]) # <repo>/agents
11
+ skills_source_root = Path(sys.argv[2]) # <repo>/skills
12
+ runtime_root = Path(sys.argv[3]) # <repo>/runtime
13
+ validation_mode = sys.argv[4]
14
+ errors = []
15
+
16
+
17
+ def check(source_path: Path, target_path: Path) -> None:
18
+ if not target_path.is_file():
19
+ errors.append(f"missing build-output asset: {target_path}")
20
+ return
21
+ if validation_mode == "match" and target_path.read_bytes() != source_path.read_bytes():
22
+ errors.append(f"build-output asset does not match source: {target_path}")
23
+
24
+
25
+ # 1. Worker agent files: agents/workers/*-worker.md -> runtime/agents/workers/*-worker.md
26
+ #
27
+ workers_source = agents_source_root / "workers"
28
+ workers_target = runtime_root / "agents" / "workers"
29
+ if not workers_source.is_dir():
30
+ errors.append(f"missing agents/workers source directory: {workers_source}")
31
+ else:
32
+ for source_path in sorted(workers_source.glob("*.md")):
33
+ check(source_path, workers_target / source_path.name)
34
+
35
+ # 2. Lead contract + internal lead resources: prompts/lead/* + prompts/coding-preflight/*
36
+ # -> runtime/prompts/*. These ship as runtime resources (okstra install copies
37
+ # runtime/prompts -> ~/.okstra/prompts), no longer as agent skills.
38
+ prompts_source_root = agents_source_root.parent / "prompts"
39
+ for sub in ("lead", "coding-preflight"):
40
+ sub_root = prompts_source_root / sub
41
+ if not sub_root.is_dir():
42
+ errors.append(f"missing prompts source directory: {sub_root}")
43
+ continue
44
+ for source_path in sorted(sub_root.rglob("*.md")):
45
+ relative = source_path.relative_to(prompts_source_root)
46
+ check(source_path, runtime_root / "prompts" / relative)
47
+
48
+ # 3. Skill packages: skills/<name>/SKILL.md -> runtime/skills/<name>/SKILL.md
49
+ if not skills_source_root.is_dir():
50
+ errors.append(f"missing skills source directory: {skills_source_root}")
51
+ else:
52
+ for skill_dir in sorted(p for p in skills_source_root.iterdir() if p.is_dir()):
53
+ for source_path in sorted(skill_dir.rglob("*.md")):
54
+ relative = source_path.relative_to(skills_source_root)
55
+ check(source_path, runtime_root / "skills" / relative)
56
+
57
+ if errors:
58
+ for error in errors:
59
+ print(error, file=sys.stderr)
60
+ sys.exit(1)
@@ -0,0 +1,261 @@
1
+ """validate-prompt-metadata-01 — 셸 시나리오에서 꺼낸 단언 블록.
2
+
3
+ 호출부: validators/lib/validate-prompt-metadata.sh:10
4
+ 규칙 R1 은 실행될 소스를 문자열/heredoc 이 아니라 실파일에 두게 한다.
5
+ 이 파일의 내용은 꺼내기 전과 같다 — 옮기기만 했다.
6
+ """
7
+ from pathlib import Path
8
+ import json
9
+ import sys
10
+
11
+ project_root = Path(sys.argv[1])
12
+ task_manifest_path = project_root / sys.argv[2]
13
+ errors = []
14
+
15
+
16
+ def load_json(path: Path) -> dict:
17
+ return json.loads(path.read_text())
18
+
19
+
20
+ def validate_prompt_contract(
21
+ prefix: str,
22
+ worker_ids: list[str],
23
+ prompt_dir: str,
24
+ prompt_map: object,
25
+ required_worker_roles: object,
26
+ ) -> None:
27
+ if not prompt_dir:
28
+ errors.append(f"{prefix} is missing worker prompt directory metadata")
29
+ if not isinstance(prompt_map, dict):
30
+ errors.append(f"{prefix} worker prompt map is missing or invalid")
31
+ prompt_map = {}
32
+ if not isinstance(required_worker_roles, list):
33
+ errors.append(f"{prefix} requiredWorkerRoles is missing or invalid")
34
+ required_worker_roles = []
35
+
36
+ expected_dir_prefix = prompt_dir.rstrip("/") + "/" if prompt_dir else ""
37
+ for worker_id in worker_ids:
38
+ if worker_id not in prompt_map:
39
+ errors.append(f"{prefix} worker prompt map is missing selected worker: {worker_id}")
40
+
41
+ for worker in required_worker_roles:
42
+ if not isinstance(worker, dict):
43
+ errors.append(f"{prefix} requiredWorkerRoles contains a non-object entry")
44
+ continue
45
+ worker_id = str(worker.get("workerId", "")).strip()
46
+ prompt_relative = str(worker.get("promptPath", "")).strip()
47
+ if not worker_id:
48
+ errors.append(f"{prefix} requiredWorkerRoles contains an entry without workerId")
49
+ continue
50
+ if not prompt_relative:
51
+ errors.append(
52
+ f"{prefix} required worker is missing promptPath: {worker_id}"
53
+ )
54
+ continue
55
+ if prompt_map.get(worker_id) != prompt_relative:
56
+ errors.append(
57
+ f"{prefix} worker prompt map does not match requiredWorkerRoles for {worker_id}"
58
+ )
59
+ if expected_dir_prefix and not prompt_relative.startswith(expected_dir_prefix):
60
+ errors.append(
61
+ f"{prefix} worker prompt path is outside the prompt directory: {prompt_relative}"
62
+ )
63
+
64
+
65
+ if not task_manifest_path.is_file():
66
+ errors.append(f"task manifest is missing: {task_manifest_path}")
67
+ else:
68
+ task_manifest = load_json(task_manifest_path)
69
+ selected_workers = task_manifest.get("recommendedWorkers", [])
70
+ if not isinstance(selected_workers, list):
71
+ errors.append("task manifest recommendedWorkers is missing or invalid")
72
+ selected_workers = []
73
+
74
+ task_prompt_dir = str(task_manifest.get("latestRunPromptsPath", "")).strip()
75
+ if not task_prompt_dir:
76
+ errors.append("task manifest is missing latestRunPromptsPath")
77
+
78
+ task_artifacts = task_manifest.get("artifacts", {})
79
+ if not isinstance(task_artifacts, dict):
80
+ errors.append("task manifest artifacts is missing or invalid")
81
+ task_artifacts = {}
82
+
83
+ validate_prompt_contract(
84
+ "task manifest",
85
+ selected_workers,
86
+ str(task_artifacts.get("workerPromptsDirectoryPath", "")).strip(),
87
+ task_artifacts.get("workerPromptPathByWorkerId"),
88
+ task_manifest.get("resultContract", {}).get("requiredWorkerRoles"),
89
+ )
90
+
91
+ if (
92
+ task_prompt_dir
93
+ and str(task_artifacts.get("workerPromptsDirectoryPath", "")).strip()
94
+ and task_prompt_dir
95
+ != str(task_artifacts.get("workerPromptsDirectoryPath", "")).strip()
96
+ ):
97
+ errors.append(
98
+ "task manifest latestRunPromptsPath does not match artifacts.workerPromptsDirectoryPath"
99
+ )
100
+
101
+ timeline_relative_path = str(
102
+ task_manifest.get("historyTimelinePath", "")
103
+ ).strip()
104
+ if not timeline_relative_path:
105
+ errors.append("task manifest is missing historyTimelinePath")
106
+ else:
107
+ timeline_path = project_root / timeline_relative_path
108
+ if not timeline_path.is_file():
109
+ errors.append(f"timeline file is missing: {timeline_path}")
110
+ else:
111
+ timeline = load_json(timeline_path)
112
+ runs = timeline.get("runs", [])
113
+ latest_run = None
114
+ if isinstance(runs, list):
115
+ for item in reversed(runs):
116
+ if isinstance(item, dict):
117
+ latest_run = item
118
+ break
119
+ if latest_run is None:
120
+ errors.append("timeline does not contain a latest run entry")
121
+ else:
122
+ latest_run_prompt_dir = str(
123
+ latest_run.get("workerPromptDirectoryPath", "")
124
+ ).strip()
125
+ if not latest_run_prompt_dir:
126
+ errors.append(
127
+ "latest timeline entry is missing workerPromptDirectoryPath"
128
+ )
129
+ if task_prompt_dir and latest_run_prompt_dir and task_prompt_dir != latest_run_prompt_dir:
130
+ errors.append(
131
+ "timeline latest run prompt directory does not match task manifest latestRunPromptsPath"
132
+ )
133
+ prompt_map = latest_run.get("workerPromptPathByWorkerId")
134
+ if not isinstance(prompt_map, dict):
135
+ errors.append(
136
+ "latest timeline entry is missing workerPromptPathByWorkerId"
137
+ )
138
+ else:
139
+ for worker_id in selected_workers:
140
+ if worker_id not in prompt_map:
141
+ errors.append(
142
+ f"latest timeline entry is missing worker prompt path for {worker_id}"
143
+ )
144
+
145
+ run_manifest_relative_path = str(
146
+ latest_run.get("runManifestPath", "")
147
+ ).strip()
148
+ if not run_manifest_relative_path:
149
+ errors.append(
150
+ "latest timeline entry is missing runManifestPath"
151
+ )
152
+ else:
153
+ run_manifest_path = project_root / run_manifest_relative_path
154
+ if not run_manifest_path.is_file():
155
+ errors.append(f"latest run manifest is missing: {run_manifest_path}")
156
+ else:
157
+ run_manifest = load_json(run_manifest_path)
158
+ run_prompt_dir = str(
159
+ run_manifest.get("workerPromptsDirectoryPath", "")
160
+ ).strip()
161
+ if task_prompt_dir and run_prompt_dir and task_prompt_dir != run_prompt_dir:
162
+ errors.append(
163
+ "run manifest workerPromptsDirectoryPath does not match task manifest latestRunPromptsPath"
164
+ )
165
+ validate_prompt_contract(
166
+ "run manifest",
167
+ selected_workers,
168
+ run_prompt_dir,
169
+ run_manifest.get("workerPromptPathByWorkerId"),
170
+ run_manifest.get("teamContract", {}).get("requiredWorkerRoles"),
171
+ )
172
+
173
+ team_state_relative_path = str(
174
+ run_manifest.get("teamStatePath")
175
+ or task_manifest.get("teamStatePath", "")
176
+ ).strip()
177
+ if not team_state_relative_path:
178
+ errors.append(
179
+ "team state relative path is missing from run/task manifest"
180
+ )
181
+ else:
182
+ team_state_path = project_root / team_state_relative_path
183
+ if not team_state_path.is_file():
184
+ errors.append(f"team-state file is missing: {team_state_path}")
185
+ else:
186
+ team_state = load_json(team_state_path)
187
+ team_artifacts = team_state.get("artifacts", {})
188
+ if not isinstance(team_artifacts, dict):
189
+ errors.append(
190
+ "team-state artifacts is missing or invalid"
191
+ )
192
+ team_artifacts = {}
193
+ team_prompt_dir = str(
194
+ team_artifacts.get(
195
+ "workerPromptsDirectoryPath", ""
196
+ )
197
+ ).strip()
198
+ if run_prompt_dir and team_prompt_dir and run_prompt_dir != team_prompt_dir:
199
+ errors.append(
200
+ "team-state worker prompt directory does not match run manifest"
201
+ )
202
+ workers = team_state.get("workers", [])
203
+ if not isinstance(workers, list):
204
+ errors.append("team-state workers is missing or invalid")
205
+ else:
206
+ team_workers = {}
207
+ for worker in workers:
208
+ if not isinstance(worker, dict):
209
+ errors.append(
210
+ "team-state workers contains a non-object entry"
211
+ )
212
+ continue
213
+ worker_id = str(worker.get("workerId", "")).strip()
214
+ if not worker_id:
215
+ errors.append(
216
+ "team-state workers contains an entry without workerId"
217
+ )
218
+ continue
219
+ team_workers[worker_id] = worker
220
+
221
+ run_prompt_map = run_manifest.get(
222
+ "workerPromptPathByWorkerId", {}
223
+ )
224
+ if not isinstance(run_prompt_map, dict):
225
+ run_prompt_map = {}
226
+
227
+ for worker_id in selected_workers:
228
+ worker = team_workers.get(worker_id)
229
+ if worker is None:
230
+ errors.append(
231
+ f"team-state is missing selected worker entry: {worker_id}"
232
+ )
233
+ continue
234
+ prompt_relative = str(
235
+ worker.get("promptPath", "")
236
+ ).strip()
237
+ if not prompt_relative:
238
+ errors.append(
239
+ f"team-state worker is missing promptPath: {worker_id}"
240
+ )
241
+ continue
242
+ if run_prompt_map.get(worker_id) != prompt_relative:
243
+ errors.append(
244
+ f"team-state worker prompt path does not match run manifest for {worker_id}"
245
+ )
246
+ expected_dir_prefix = (
247
+ run_prompt_dir.rstrip("/") + "/"
248
+ if run_prompt_dir
249
+ else ""
250
+ )
251
+ if expected_dir_prefix and not prompt_relative.startswith(
252
+ expected_dir_prefix
253
+ ):
254
+ errors.append(
255
+ f"team-state worker prompt path is outside the run prompt directory: {prompt_relative}"
256
+ )
257
+
258
+ if errors:
259
+ for error in errors:
260
+ print(error, file=sys.stderr)
261
+ sys.exit(1)
@@ -0,0 +1,46 @@
1
+ """validate-tasks-01 — 셸 시나리오에서 꺼낸 단언 블록.
2
+
3
+ 호출부: validators/lib/validate-tasks.sh:8
4
+ 규칙 R1 은 실행될 소스를 문자열/heredoc 이 아니라 실파일에 두게 한다.
5
+ 이 파일의 내용은 꺼내기 전과 같다 — 옮기기만 했다.
6
+ """
7
+ from pathlib import Path
8
+ import sys
9
+
10
+ brief_path = Path(sys.argv[1])
11
+ reference_path = Path(sys.argv[2])
12
+ expected_task_key = sys.argv[3]
13
+ brief_lines = brief_path.read_text().splitlines()
14
+ section_map = {
15
+ "Configuration References and Expected Values": "config",
16
+ "Deployment Manifests and Expected Values": "deployment",
17
+ }
18
+ captured = {"config": [], "deployment": []}
19
+ current_section = None
20
+
21
+ for line in brief_lines:
22
+ if line.startswith("## "):
23
+ current_section = section_map.get(line[3:].strip())
24
+ continue
25
+ if current_section and line.strip():
26
+ captured[current_section].append(line)
27
+
28
+ errors = []
29
+
30
+ if not reference_path.is_file():
31
+ errors.append(f"reference expectations file is missing: {reference_path}")
32
+ reference_content = ""
33
+ else:
34
+ reference_content = reference_path.read_text()
35
+
36
+ for line in captured["config"] + captured["deployment"]:
37
+ if line not in reference_content:
38
+ errors.append(f"reference expectations file is missing brief line: {line}")
39
+
40
+ if f"- Task Key: `{expected_task_key}`" not in reference_content:
41
+ errors.append("reference expectations file is missing the task key header")
42
+
43
+ if errors:
44
+ for error in errors:
45
+ print(error, file=sys.stderr)
46
+ sys.exit(1)
@@ -0,0 +1,85 @@
1
+ """validate-tasks-02 — 셸 시나리오에서 꺼낸 단언 블록.
2
+
3
+ 호출부: validators/lib/validate-tasks.sh:22
4
+ 규칙 R1 은 실행될 소스를 문자열/heredoc 이 아니라 실파일에 두게 한다.
5
+ 이 파일의 내용은 꺼내기 전과 같다 — 옮기기만 했다.
6
+ """
7
+ from pathlib import Path
8
+ import json
9
+ import sys
10
+
11
+ project_root = Path(sys.argv[1])
12
+ expected_task_key = sys.argv[2]
13
+ task_manifest_relative_path = sys.argv[3]
14
+ expected_reference_relative_path = sys.argv[4]
15
+ expected_task_catalog_relative_path = sys.argv[5]
16
+ errors = []
17
+
18
+ task_manifest_path = project_root / task_manifest_relative_path
19
+ if not task_manifest_path.is_file():
20
+ errors.append(f"task manifest is missing: {task_manifest_path}")
21
+ else:
22
+ task_manifest = json.loads(task_manifest_path.read_text())
23
+
24
+ if task_manifest.get("taskKey") != expected_task_key:
25
+ errors.append("task manifest does not contain the expected task key")
26
+
27
+ if task_manifest.get("referenceExpectationsPath") != expected_reference_relative_path:
28
+ errors.append("task manifest does not expose referenceExpectationsPath")
29
+
30
+ if task_manifest.get("taskCatalogPath") != expected_task_catalog_relative_path:
31
+ errors.append("task manifest does not expose taskCatalogPath")
32
+
33
+ if (
34
+ task_manifest.get("artifacts", {}).get("referenceExpectationsPath")
35
+ != expected_reference_relative_path
36
+ ):
37
+ errors.append("task manifest artifacts do not expose referenceExpectationsPath")
38
+
39
+ timeline_relative_path = task_manifest.get("historyTimelinePath", "")
40
+ if not timeline_relative_path:
41
+ errors.append("task manifest is missing historyTimelinePath")
42
+ else:
43
+ timeline_path = project_root / timeline_relative_path
44
+ if not timeline_path.is_file():
45
+ errors.append(f"timeline file is missing: {timeline_path}")
46
+ else:
47
+ timeline = json.loads(timeline_path.read_text())
48
+ runs = timeline.get("runs", [])
49
+ latest_run = None
50
+ if isinstance(runs, list):
51
+ for item in reversed(runs):
52
+ if isinstance(item, dict):
53
+ latest_run = item
54
+ break
55
+ if latest_run is None:
56
+ errors.append("timeline does not contain a latest run entry")
57
+ else:
58
+ run_manifest_relative_path = latest_run.get("runManifestPath", "")
59
+ if not run_manifest_relative_path:
60
+ errors.append("latest timeline entry is missing runManifestPath")
61
+ else:
62
+ run_manifest_path = project_root / run_manifest_relative_path
63
+ if not run_manifest_path.is_file():
64
+ errors.append(f"latest run manifest is missing: {run_manifest_path}")
65
+ else:
66
+ run_manifest = json.loads(run_manifest_path.read_text())
67
+ if run_manifest.get("taskKey") != expected_task_key:
68
+ errors.append("run manifest does not contain the expected task key")
69
+ if (
70
+ run_manifest.get("referenceExpectationsPath")
71
+ != expected_reference_relative_path
72
+ ):
73
+ errors.append(
74
+ "run manifest does not expose referenceExpectationsPath"
75
+ )
76
+ if (
77
+ run_manifest.get("taskCatalogPath")
78
+ != expected_task_catalog_relative_path
79
+ ):
80
+ errors.append("run manifest does not expose taskCatalogPath")
81
+
82
+ if errors:
83
+ for error in errors:
84
+ print(error, file=sys.stderr)
85
+ sys.exit(1)
@@ -0,0 +1,61 @@
1
+ """validate-tasks-03 — 셸 시나리오에서 꺼낸 단언 블록.
2
+
3
+ 호출부: validators/lib/validate-tasks.sh:36
4
+ 규칙 R1 은 실행될 소스를 문자열/heredoc 이 아니라 실파일에 두게 한다.
5
+ 이 파일의 내용은 꺼내기 전과 같다 — 옮기기만 했다.
6
+ """
7
+ from pathlib import Path
8
+ import json
9
+ import sys
10
+
11
+ project_root = Path(sys.argv[1])
12
+ discovery_path = Path(sys.argv[2])
13
+ expected_task_key = sys.argv[3]
14
+ expected_task_manifest_relative_path = sys.argv[4]
15
+ expected_reference_relative_path = sys.argv[5]
16
+ expected_task_catalog_relative_path = sys.argv[6]
17
+ errors = []
18
+
19
+ if not discovery_path.is_file():
20
+ errors.append(f"latest-task discovery file is missing: {discovery_path}")
21
+ else:
22
+ discovery = json.loads(discovery_path.read_text())
23
+
24
+ if discovery.get("taskKey") != expected_task_key:
25
+ errors.append("latest-task discovery does not point to the expected task key")
26
+
27
+ if discovery.get("taskManifestPath") != expected_task_manifest_relative_path:
28
+ errors.append("latest-task discovery does not point to the expected task manifest")
29
+
30
+ if discovery.get("referenceExpectationsPath") != expected_reference_relative_path:
31
+ errors.append("latest-task discovery does not expose the expected reference expectations path")
32
+
33
+ if discovery.get("taskCatalogPath") != expected_task_catalog_relative_path:
34
+ errors.append("latest-task discovery does not expose taskCatalogPath")
35
+
36
+ latest_run_prompts_relative_path = discovery.get("latestRunPromptsPath", "")
37
+ if not latest_run_prompts_relative_path:
38
+ errors.append("latest-task discovery is missing latestRunPromptsPath")
39
+
40
+ latest_run_manifest_relative_path = discovery.get("latestRunManifestPath", "")
41
+ if not latest_run_manifest_relative_path:
42
+ errors.append("latest-task discovery is missing latestRunManifestPath")
43
+ else:
44
+ latest_run_manifest_path = project_root / latest_run_manifest_relative_path
45
+ if not latest_run_manifest_path.is_file():
46
+ errors.append(f"latest run manifest is missing: {latest_run_manifest_path}")
47
+ else:
48
+ run_manifest = json.loads(latest_run_manifest_path.read_text())
49
+ if (
50
+ latest_run_prompts_relative_path
51
+ and run_manifest.get("workerPromptsDirectoryPath")
52
+ != latest_run_prompts_relative_path
53
+ ):
54
+ errors.append(
55
+ "latest-task discovery latestRunPromptsPath does not match the latest run manifest"
56
+ )
57
+
58
+ if errors:
59
+ for error in errors:
60
+ print(error, file=sys.stderr)
61
+ sys.exit(1)
@@ -0,0 +1,118 @@
1
+ """validate-tasks-04 — 셸 시나리오에서 꺼낸 단언 블록.
2
+
3
+ 호출부: validators/lib/validate-tasks.sh:44
4
+ 규칙 R1 은 실행될 소스를 문자열/heredoc 이 아니라 실파일에 두게 한다.
5
+ 이 파일의 내용은 꺼내기 전과 같다 — 옮기기만 했다.
6
+ """
7
+ from pathlib import Path
8
+ import json
9
+ import sys
10
+
11
+ project_root = Path(sys.argv[1])
12
+ catalog_path = Path(sys.argv[2])
13
+ expected_latest_task_key = sys.argv[3]
14
+ expected_latest_task_relative_path = sys.argv[4]
15
+ expected_task_keys = sys.argv[5:]
16
+ errors = []
17
+
18
+ if not catalog_path.is_file():
19
+ errors.append(f"task catalog is missing: {catalog_path}")
20
+ else:
21
+ catalog = json.loads(catalog_path.read_text())
22
+ tasks = catalog.get("tasks", [])
23
+
24
+ if catalog.get("latestTaskKey") != expected_latest_task_key:
25
+ errors.append("task catalog does not record the expected latestTaskKey")
26
+
27
+ if catalog.get("latestTaskDiscoveryPath") != expected_latest_task_relative_path:
28
+ errors.append("task catalog does not expose latestTaskDiscoveryPath")
29
+
30
+ if catalog.get("taskCount") != len(expected_task_keys):
31
+ errors.append("task catalog taskCount does not match the expected number of tasks")
32
+
33
+ if not isinstance(tasks, list):
34
+ errors.append("task catalog tasks entry is not a list")
35
+ else:
36
+ catalog_by_key = {}
37
+ for entry in tasks:
38
+ if not isinstance(entry, dict):
39
+ errors.append("task catalog contains a non-object entry")
40
+ continue
41
+ task_key = entry.get("taskKey", "")
42
+ if not task_key:
43
+ errors.append("task catalog contains an entry without taskKey")
44
+ continue
45
+ if task_key in catalog_by_key:
46
+ errors.append(f"task catalog contains a duplicate task key: {task_key}")
47
+ continue
48
+ catalog_by_key[task_key] = entry
49
+
50
+ for expected_task_key in expected_task_keys:
51
+ entry = catalog_by_key.get(expected_task_key)
52
+ if entry is None:
53
+ errors.append(f"task catalog is missing task key: {expected_task_key}")
54
+ continue
55
+ task_key_parts = expected_task_key.split(":", 2)
56
+ if len(task_key_parts) != 3:
57
+ errors.append(f"expected task key is malformed: {expected_task_key}")
58
+ continue
59
+ _, expected_task_group, expected_task_id = task_key_parts
60
+
61
+ if entry.get("taskGroup") != expected_task_group:
62
+ errors.append(f"task catalog entry is missing the expected taskGroup: {expected_task_key}")
63
+
64
+ if entry.get("taskId") != expected_task_id:
65
+ errors.append(f"task catalog entry is missing the expected taskId: {expected_task_key}")
66
+
67
+ task_manifest_relative_path = entry.get("taskManifestPath", "")
68
+ if not task_manifest_relative_path:
69
+ errors.append(f"task catalog entry is missing taskManifestPath: {expected_task_key}")
70
+ else:
71
+ task_manifest_path = project_root / task_manifest_relative_path
72
+ if not task_manifest_path.is_file():
73
+ errors.append(f"task catalog points to a missing task manifest: {task_manifest_path}")
74
+
75
+ reference_relative_path = entry.get("referenceExpectationsPath", "")
76
+ if not reference_relative_path:
77
+ errors.append(
78
+ f"task catalog entry is missing referenceExpectationsPath: {expected_task_key}"
79
+ )
80
+ else:
81
+ reference_path = project_root / reference_relative_path
82
+ if not reference_path.is_file():
83
+ errors.append(
84
+ f"task catalog points to a missing reference expectations file: {reference_path}"
85
+ )
86
+
87
+ latest_run_manifest_relative_path = entry.get("latestRunManifestPath", "")
88
+ if not latest_run_manifest_relative_path:
89
+ errors.append(
90
+ f"task catalog entry is missing latestRunManifestPath: {expected_task_key}"
91
+ )
92
+ else:
93
+ latest_run_manifest_path = project_root / latest_run_manifest_relative_path
94
+ if not latest_run_manifest_path.is_file():
95
+ errors.append(
96
+ f"task catalog points to a missing latest run manifest: {latest_run_manifest_path}"
97
+ )
98
+ else:
99
+ run_manifest = json.loads(latest_run_manifest_path.read_text())
100
+ latest_run_prompts_relative_path = entry.get(
101
+ "latestRunPromptsPath", ""
102
+ )
103
+ if not latest_run_prompts_relative_path:
104
+ errors.append(
105
+ f"task catalog entry is missing latestRunPromptsPath: {expected_task_key}"
106
+ )
107
+ elif (
108
+ run_manifest.get("workerPromptsDirectoryPath")
109
+ != latest_run_prompts_relative_path
110
+ ):
111
+ errors.append(
112
+ f"task catalog entry latestRunPromptsPath does not match the latest run manifest: {expected_task_key}"
113
+ )
114
+
115
+ if errors:
116
+ for error in errors:
117
+ print(error, file=sys.stderr)
118
+ sys.exit(1)