okstra 0.202.0 → 0.205.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 (263) hide show
  1. package/README.md +7 -6
  2. package/dist/cli-registry.mjs +7 -7
  3. package/dist/cli-registry.mjs.map +1 -1
  4. package/dist/commands/lifecycle/install.mjs +50 -124
  5. package/dist/commands/lifecycle/install.mjs.map +1 -1
  6. package/dist/commands/memory/memory.mjs +41 -8
  7. package/dist/commands/memory/memory.mjs.map +1 -1
  8. package/dist/lib/install-assets.mjs +3 -0
  9. package/dist/lib/install-assets.mjs.map +1 -1
  10. package/dist/lib/runtime-manifest.mjs +2 -1
  11. package/dist/lib/runtime-manifest.mjs.map +1 -1
  12. package/dist/lib/types.d.mts +2 -1
  13. package/docs/architecture/storage-model.md +14 -11
  14. package/docs/architecture.md +26 -20
  15. package/docs/cli.md +15 -12
  16. package/docs/contributor-change-matrix.md +3 -2
  17. package/docs/performance-improvement-plan-v2.md +3 -9
  18. package/docs/project-structure-overview.md +39 -11
  19. package/docs/task-process/README.md +1 -1
  20. package/docs/task-process/common-flow.md +1 -1
  21. package/docs/task-process/final-verification.md +3 -1
  22. package/docs/task-process/implementation-option-selection.md +1 -1
  23. package/docs/task-process/implementation.md +1 -1
  24. package/docs/task-process/release-handoff.md +36 -39
  25. package/package.json +1 -2
  26. package/runtime/BUILD.json +2 -2
  27. package/runtime/agents/common.json +28 -0
  28. package/runtime/agents/operations/code-review.json +6 -0
  29. package/runtime/agents/operations/report-translation.json +6 -0
  30. package/runtime/agents/operations/schedule-verification.json +6 -0
  31. package/runtime/agents/roles/analyser.json +18 -0
  32. package/runtime/agents/roles/critic.json +18 -0
  33. package/runtime/agents/roles/designer.json +18 -0
  34. package/runtime/agents/roles/implementer.json +20 -0
  35. package/runtime/agents/roles/leader.json +20 -0
  36. package/runtime/agents/roles/planner.json +18 -0
  37. package/runtime/agents/roles/report-writer.json +19 -0
  38. package/runtime/agents/roles/translator.json +19 -0
  39. package/runtime/agents/roles/verifier.json +18 -0
  40. package/runtime/bin/lib/okstra/usage.sh +5 -5
  41. package/runtime/prompts/duties/acceptance-critic.json +32 -0
  42. package/runtime/prompts/duties/acceptance-verifier.json +32 -0
  43. package/runtime/prompts/duties/analysis-worker.json +32 -0
  44. package/runtime/prompts/duties/code-reviewer.json +32 -0
  45. package/runtime/prompts/duties/diagnosis-worker.json +32 -0
  46. package/runtime/prompts/duties/direction-selection-worker.json +32 -0
  47. package/runtime/prompts/duties/discovery-worker.json +32 -0
  48. package/runtime/prompts/duties/implementation-executor.json +32 -0
  49. package/runtime/prompts/duties/implementation-verifier.json +32 -0
  50. package/runtime/prompts/duties/lead.json +32 -0
  51. package/runtime/prompts/duties/planning-worker.json +36 -0
  52. package/runtime/prompts/duties/report-writer.json +32 -0
  53. package/runtime/prompts/duties/reverification-worker.json +32 -0
  54. package/runtime/prompts/duties/schedule-verifier.json +32 -0
  55. package/runtime/prompts/duties/scope-critic.json +32 -0
  56. package/runtime/prompts/duties/technical-verification-worker.json +32 -0
  57. package/runtime/prompts/duties/translator.json +32 -0
  58. package/runtime/prompts/launch.template.md +2 -1
  59. package/runtime/prompts/lead/adapters/cmux.md +1 -1
  60. package/runtime/prompts/lead/convergence.md +4 -4
  61. package/runtime/prompts/lead/okstra-lead-contract.md +115 -6
  62. package/runtime/prompts/lead/plan-body-verification.md +6 -6
  63. package/runtime/prompts/lead/report-writer.md +3 -3
  64. package/runtime/prompts/profiles/_common-contract.md +2 -2
  65. package/runtime/prompts/profiles/_implementation-diff-review.md +1 -1
  66. package/runtime/prompts/profiles/_implementation-executor.md +4 -1
  67. package/runtime/prompts/profiles/_implementation-self-check.md +1 -1
  68. package/runtime/prompts/profiles/_implementation-verifier.md +2 -2
  69. package/runtime/prompts/profiles/change-impact-analysis.json +31 -0
  70. package/runtime/prompts/profiles/change-impact-analysis.md +0 -20
  71. package/runtime/prompts/profiles/error-analysis.json +39 -0
  72. package/runtime/prompts/profiles/error-analysis.md +0 -25
  73. package/runtime/prompts/profiles/feature-analysis.json +31 -0
  74. package/runtime/prompts/profiles/feature-analysis.md +0 -20
  75. package/runtime/prompts/profiles/final-verification.json +30 -0
  76. package/runtime/prompts/profiles/final-verification.md +4 -23
  77. package/runtime/prompts/profiles/forbidden-actions.json +4 -3
  78. package/runtime/prompts/profiles/implementation-option-selection.json +31 -0
  79. package/runtime/prompts/profiles/implementation-option-selection.md +0 -20
  80. package/runtime/prompts/profiles/implementation-planning.json +40 -0
  81. package/runtime/prompts/profiles/implementation-planning.md +4 -29
  82. package/runtime/prompts/profiles/implementation.json +30 -0
  83. package/runtime/prompts/profiles/implementation.md +1 -20
  84. package/runtime/prompts/profiles/improvement-discovery.json +31 -0
  85. package/runtime/prompts/profiles/improvement-discovery.md +0 -20
  86. package/runtime/prompts/profiles/project-analysis.json +31 -0
  87. package/runtime/prompts/profiles/project-analysis.md +0 -20
  88. package/runtime/prompts/profiles/release-handoff.json +5 -0
  89. package/runtime/prompts/profiles/release-handoff.md +74 -74
  90. package/runtime/prompts/profiles/requirements-discovery.json +39 -0
  91. package/runtime/prompts/profiles/requirements-discovery.md +0 -25
  92. package/runtime/prompts/profiles/technical-verification.json +39 -0
  93. package/runtime/prompts/profiles/technical-verification.md +0 -25
  94. package/runtime/prompts/wizard/prompts.ko.json +14 -18
  95. package/runtime/python/okstra_ctl/adapters/hosts/antigravity/relay.md +1 -0
  96. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/adapter.py +3 -0
  97. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/manifest.json +1 -1
  98. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/relay.md +4 -3
  99. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/worker-session.md +108 -0
  100. package/runtime/python/okstra_ctl/adapters/hosts/codex/relay.md +1 -0
  101. package/runtime/python/okstra_ctl/adapters/hosts/grok/relay.md +2 -0
  102. package/runtime/python/okstra_ctl/adapters/hosts/kimi/relay.md +2 -0
  103. package/runtime/python/okstra_ctl/adapters/providers/antigravity/adapter.py +8 -1
  104. package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +8 -0
  105. package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +23 -6
  106. package/runtime/python/okstra_ctl/adapters/providers/grok/adapter.py +6 -2
  107. package/runtime/python/okstra_ctl/agent/invocation.py +168 -113
  108. package/runtime/python/okstra_ctl/agent/prompt_cli/cli.py +120 -0
  109. package/runtime/python/okstra_ctl/agent/prompt_cli/materialize.py +107 -2
  110. package/runtime/python/okstra_ctl/agent/prompt_cli/run_identity.py +0 -49
  111. package/runtime/python/okstra_ctl/analysis_packet.py +4 -1
  112. package/runtime/python/okstra_ctl/application/open_worker.py +6 -1
  113. package/runtime/python/okstra_ctl/assignment_resolver.py +16 -5
  114. package/runtime/python/okstra_ctl/cmux.py +69 -20
  115. package/runtime/python/okstra_ctl/code_review_target.py +16 -8
  116. package/runtime/python/okstra_ctl/conformance.py +43 -0
  117. package/runtime/python/okstra_ctl/consumers.py +23 -8
  118. package/runtime/python/okstra_ctl/container.py +31 -8
  119. package/runtime/python/okstra_ctl/context_cost.py +11 -15
  120. package/runtime/python/okstra_ctl/contract_refreeze.py +156 -0
  121. package/runtime/python/okstra_ctl/convergence_engine.py +38 -0
  122. package/runtime/python/okstra_ctl/convergence_provenance.py +7 -1
  123. package/runtime/python/okstra_ctl/design_prep.py +34 -1
  124. package/runtime/python/okstra_ctl/dispatch_core.py +53 -27
  125. package/runtime/python/okstra_ctl/domain/host.py +5 -0
  126. package/runtime/python/okstra_ctl/domain/worker_runtime.py +10 -0
  127. package/runtime/python/okstra_ctl/error_report.py +4 -3
  128. package/runtime/python/okstra_ctl/execution_manifest.py +71 -18
  129. package/runtime/python/okstra_ctl/handoff.py +384 -286
  130. package/runtime/python/okstra_ctl/handoff_verification.py +25 -6
  131. package/runtime/python/okstra_ctl/implementation_stage.py +9 -0
  132. package/runtime/python/okstra_ctl/initial_prompt_materialization.py +113 -0
  133. package/runtime/python/okstra_ctl/lead_progress.py +1 -1
  134. package/runtime/python/okstra_ctl/legacy_model_selection.py +2 -2
  135. package/runtime/python/okstra_ctl/manager_cli.py +92 -4
  136. package/runtime/python/okstra_ctl/manager_launch.py +1 -1
  137. package/runtime/python/okstra_ctl/manager_paths.py +14 -3
  138. package/runtime/python/okstra_ctl/manager_store.py +210 -3
  139. package/runtime/python/okstra_ctl/manager_sync.py +4 -1
  140. package/runtime/python/okstra_ctl/manager_view.py +2 -1
  141. package/runtime/python/okstra_ctl/model_discovery.py +30 -0
  142. package/runtime/python/okstra_ctl/model_io/lines.py +14 -1
  143. package/runtime/python/okstra_ctl/model_io/renderers.py +4 -3
  144. package/runtime/python/okstra_ctl/models.py +1 -1
  145. package/runtime/python/okstra_ctl/next_phase.py +16 -6
  146. package/runtime/python/okstra_ctl/operation_invocation.py +86 -0
  147. package/runtime/python/okstra_ctl/option_comparison.py +168 -0
  148. package/runtime/python/okstra_ctl/path_hints.py +9 -0
  149. package/runtime/python/okstra_ctl/paths.py +3 -0
  150. package/runtime/python/okstra_ctl/profile_show.py +42 -1
  151. package/runtime/python/okstra_ctl/registry/host_discovery.py +20 -12
  152. package/runtime/python/okstra_ctl/registry/host_registry.py +11 -0
  153. package/runtime/python/okstra_ctl/render.py +79 -0
  154. package/runtime/python/okstra_ctl/report_contract.py +1 -1
  155. package/runtime/python/okstra_ctl/report_html/view_models/release_handoff.py +21 -3
  156. package/runtime/python/okstra_ctl/report_synthesis_packet.py +177 -17
  157. package/runtime/python/okstra_ctl/report_translation.py +2 -1
  158. package/runtime/python/okstra_ctl/report_translation_dispatch.py +69 -9
  159. package/runtime/python/okstra_ctl/role_requirements.py +142 -129
  160. package/runtime/python/okstra_ctl/rollup.py +3 -1
  161. package/runtime/python/okstra_ctl/run.py +76 -29
  162. package/runtime/python/okstra_ctl/schedule_semantics.py +17 -6
  163. package/runtime/python/okstra_ctl/stage_fix_carry.py +23 -4
  164. package/runtime/python/okstra_ctl/stage_integrate.py +178 -18
  165. package/runtime/python/okstra_ctl/stage_map.py +16 -2
  166. package/runtime/python/okstra_ctl/stage_targets.py +209 -43
  167. package/runtime/python/okstra_ctl/team.py +22 -13
  168. package/runtime/python/okstra_ctl/time_report.py +2 -1
  169. package/runtime/python/okstra_ctl/usage_report.py +3 -1
  170. package/runtime/python/okstra_ctl/wizard/confirmation.py +3 -9
  171. package/runtime/python/okstra_ctl/wizard/ids.py +1 -1
  172. package/runtime/python/okstra_ctl/wizard/registry.py +1 -1
  173. package/runtime/python/okstra_ctl/wizard/state.py +3 -5
  174. package/runtime/python/okstra_ctl/wizard/steps_plan.py +12 -21
  175. package/runtime/python/okstra_ctl/worker_prompt_contract.py +5 -1
  176. package/runtime/python/okstra_ctl/worker_prompt_headers.py +35 -7
  177. package/runtime/python/okstra_ctl/worker_prompt_policy.py +66 -48
  178. package/runtime/python/okstra_ctl/workflow.py +1 -1
  179. package/runtime/python/okstra_ctl/worktree/__init__.py +3 -1
  180. package/runtime/python/okstra_ctl/worktree/naming.py +9 -0
  181. package/runtime/python/okstra_ctl/worktree_registry.py +38 -9
  182. package/runtime/python/okstra_token_usage/pricing.py +6 -4
  183. package/runtime/schemas/agent-common-v1.schema.json +34 -0
  184. package/runtime/schemas/agent-duty-v1.schema.json +38 -0
  185. package/runtime/schemas/agent-operation-v1.schema.json +11 -0
  186. package/runtime/schemas/agent-profile-v1.schema.json +46 -0
  187. package/runtime/schemas/agent-role-v1.schema.json +29 -0
  188. package/runtime/schemas/final-report-v2.0.schema.json +118 -97
  189. package/runtime/schemas/final-report-v3.0.schema.json +118 -97
  190. package/runtime/skills/okstra-brief-gen/SKILL.md +84 -4
  191. package/runtime/skills/okstra-chat/SKILL.md +2 -2
  192. package/runtime/skills/okstra-code-review/SKILL.md +23 -9
  193. package/runtime/skills/okstra-container-build/SKILL.md +10 -10
  194. package/runtime/skills/okstra-inspect/SKILL.md +1 -1
  195. package/runtime/skills/okstra-inspect/facets/cost.md +1 -1
  196. package/runtime/skills/okstra-inspect/facets/error-zip.md +9 -9
  197. package/runtime/skills/okstra-inspect/facets/errors.md +16 -16
  198. package/runtime/skills/okstra-inspect/facets/logs.md +7 -7
  199. package/runtime/skills/okstra-inspect/facets/recap.md +2 -2
  200. package/runtime/skills/okstra-inspect/facets/report.md +1 -1
  201. package/runtime/skills/okstra-inspect/facets/status.md +4 -3
  202. package/runtime/skills/okstra-inspect/facets/time.md +11 -10
  203. package/runtime/skills/okstra-manager/SKILL.md +18 -2
  204. package/runtime/skills/okstra-pr-gen/SKILL.md +6 -5
  205. package/runtime/skills/okstra-rollup/SKILL.md +5 -5
  206. package/runtime/skills/okstra-run/SKILL.md +31 -12
  207. package/runtime/skills/okstra-schedule-gen/SKILL.md +19 -14
  208. package/runtime/skills/okstra-setup/SKILL.md +12 -10
  209. package/runtime/skills/okstra-setup/references/project-config.md +7 -6
  210. package/runtime/skills/okstra-usage/SKILL.md +1 -1
  211. package/runtime/skills/okstra-user-response/SKILL.md +1 -1
  212. package/runtime/templates/manager/view.template.html +1 -0
  213. package/runtime/templates/report-writer-prompt-preamble.md +8 -0
  214. package/runtime/templates/reports/brief.template.md +14 -4
  215. package/runtime/templates/reports/html/i18n/en.json +5 -4
  216. package/runtime/templates/reports/html/i18n/ko.json +5 -4
  217. package/runtime/templates/reports/html/tasks/release-handoff.template.html +8 -5
  218. package/runtime/templates/reports/i18n/en.json +1 -1
  219. package/runtime/templates/reports/md/tasks/release-handoff.template.md +1 -1
  220. package/runtime/templates/reports/release-handoff-input.template.md +6 -4
  221. package/runtime/templates/translator-prompt-preamble.md +36 -0
  222. package/runtime/validators/checks/validate-assets-01.py +7 -8
  223. package/runtime/validators/validate-brief.py +70 -0
  224. package/runtime/validators/validate-implementation-plan-stages.py +2 -1
  225. package/runtime/validators/validate-run.py +72 -15
  226. package/runtime/validators/validate-schedule.py +9 -0
  227. package/docs/for-ai/README.md +0 -68
  228. package/docs/for-ai/skills/okstra-brief-gen.md +0 -262
  229. package/docs/for-ai/skills/okstra-chat.md +0 -34
  230. package/docs/for-ai/skills/okstra-code-review.md +0 -57
  231. package/docs/for-ai/skills/okstra-container-build.md +0 -129
  232. package/docs/for-ai/skills/okstra-inspect.md +0 -262
  233. package/docs/for-ai/skills/okstra-manager.md +0 -86
  234. package/docs/for-ai/skills/okstra-memory.md +0 -126
  235. package/docs/for-ai/skills/okstra-pr-gen.md +0 -49
  236. package/docs/for-ai/skills/okstra-rollup.md +0 -114
  237. package/docs/for-ai/skills/okstra-run.md +0 -250
  238. package/docs/for-ai/skills/okstra-schedule-gen.md +0 -240
  239. package/docs/for-ai/skills/okstra-setup.md +0 -167
  240. package/docs/for-ai/skills/okstra-usage.md +0 -29
  241. package/docs/for-ai/skills/okstra-user-response.md +0 -72
  242. package/runtime/agents/workers/claude-worker.md +0 -128
  243. package/runtime/agents/workers/report-writer-worker.md +0 -37
  244. package/runtime/agents/workers/translator-worker.md +0 -63
  245. package/runtime/prompts/duties/acceptance-critic.md +0 -44
  246. package/runtime/prompts/duties/acceptance-verifier.md +0 -44
  247. package/runtime/prompts/duties/analysis-worker.md +0 -44
  248. package/runtime/prompts/duties/code-reviewer.md +0 -44
  249. package/runtime/prompts/duties/common.md +0 -39
  250. package/runtime/prompts/duties/diagnosis-worker.md +0 -44
  251. package/runtime/prompts/duties/direction-selection-worker.md +0 -44
  252. package/runtime/prompts/duties/discovery-worker.md +0 -44
  253. package/runtime/prompts/duties/implementation-executor.md +0 -44
  254. package/runtime/prompts/duties/implementation-verifier.md +0 -44
  255. package/runtime/prompts/duties/lead.md +0 -44
  256. package/runtime/prompts/duties/planning-worker.md +0 -52
  257. package/runtime/prompts/duties/report-writer.md +0 -44
  258. package/runtime/prompts/duties/reverification-worker.md +0 -44
  259. package/runtime/prompts/duties/schedule-verifier.md +0 -44
  260. package/runtime/prompts/duties/scope-critic.md +0 -44
  261. package/runtime/prompts/duties/technical-verification-worker.md +0 -44
  262. package/runtime/prompts/duties/translator.md +0 -44
  263. package/runtime/python/okstra_ctl/pane_title.py +0 -154
@@ -0,0 +1,36 @@
1
+ # Translator Prompt Preamble (canonical)
2
+
3
+ This file is the audience-specific contract for `translator`. Read it and the shared Worker Error Contract end-to-end. The task instructions in this prompt own this run's commands, paths, and target language; this file owns how you translate and what you may write.
4
+
5
+ ## Output ownership
6
+
7
+ Write only the translations file at `**Result Path:**`, the completion pointer at `**Worker Result Path:**`, and the reading audit at `**Audit sidecar path:**`. The publish command named in the task instructions owns the sidecar the renderer overlays; do not write that file yourself.
8
+
9
+ Never edit the report record, the narrative Markdown, the rendered HTML, or any project source file.
10
+
11
+ Never add, remove, or re-order the `T-NNN` items relative to the work list you were given. Never translate a value the work list did not offer you: its absence is deliberate, because the renderer reads those values as machinery and a translated copy breaks the page silently.
12
+
13
+ Never return the translated text inline. The file on disk is the artifact; your return message names the paths and the verification result.
14
+
15
+ ## Required reading
16
+
17
+ Read the complete work list before translating any item, continuing in chunks when it is long. A partial read produces a partial sidecar, and the items you never saw render in the source language with no error raised.
18
+
19
+ ## How to translate
20
+
21
+ Judge every term on whether the translation or the original carries the meaning faster to a working developer in the target language, and pick that one. The goal is a reader who understands the report sooner, not a document with no English left in it.
22
+
23
+ - **Never touch**: code identifiers, file paths, CLI commands and flags, model names, commit SHAs, URLs, and anything already inside backticks. Reproduce them character for character.
24
+ - **Keep the English word** when that is what developers in the target language actually say. Forcing a native coinage onto `commit`, `worktree`, `merge`, `lint`, `diff`, `stage`, `rollback` or `PR` makes the sentence *slower* to read, not more local.
25
+ - **Translate the explanation.** Connective prose — why something matters, what a reader should do, what a finding means — is where the translation earns its place. Carry the meaning, not the word order.
26
+ - **Do not translate literally.** A word-for-word rendering that is technically correct and unreadable has failed. Say what the sentence means the way a developer would say it.
27
+ - **Gloss on first use, once.** When a technical term does need translating, write it as `<translation>(<English>)` the first time it appears in the document, then use the translation alone. Never gloss the same term twice.
28
+ - **One claim per sentence.** Where the English stacks four clauses behind em-dashes, split it. The reader gains nothing from the original's punctuation.
29
+ - **Match the register.** A verdict line is terse; a rationale paragraph is explanatory. Do not inflate a three-word cell into a sentence, or compress a paragraph into a fragment.
30
+ - **Leave it out when you cannot do it justice.** An omitted item renders in the source language, which is a correct fallback. A confident mistranslation is not.
31
+
32
+ ## Failure handling
33
+
34
+ A failing verification check means a pointer resolves nowhere — you altered or invented one. Fix the translation and run the check again; do not return while it fails.
35
+
36
+ Record your own tool failures through the file named by `**Worker Error Contract Path:**`.
@@ -22,15 +22,14 @@ def check(source_path: Path, target_path: Path) -> None:
22
22
  errors.append(f"build-output asset does not match source: {target_path}")
23
23
 
24
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}")
25
+ # 1. Agent contracts: agents/common.json + agents/roles/* + agents/operations/*
26
+ # -> runtime/agents/*. 호스트 전역 에이전트 정의는 더 이상 없다(ADR-0017).
27
+ if not agents_source_root.is_dir():
28
+ errors.append(f"missing agents source directory: {agents_source_root}")
31
29
  else:
32
- for source_path in sorted(workers_source.glob("*.md")):
33
- check(source_path, workers_target / source_path.name)
30
+ for source_path in sorted(agents_source_root.rglob("*.json")):
31
+ relative = source_path.relative_to(agents_source_root)
32
+ check(source_path, runtime_root / "agents" / relative)
34
33
 
35
34
  # 2. Lead contract + internal lead resources: prompts/lead/* + prompts/coding-preflight/*
36
35
  # -> runtime/prompts/*. These ship as runtime resources (okstra install copies
@@ -47,6 +47,10 @@ Checks performed per brief file:
47
47
  it is checked by `okstra_ctl.group_context.validate_group_context` (four
48
48
  required sections, no template placeholder left, directory slug matches
49
49
  the frontmatter `task-group`). Any other `type` is a failure.
50
+ 16. No required section except `## Source Material` still carries the
51
+ template's `<...>` scaffolding — a paragraph wrapped in angle brackets,
52
+ a `- <...>` bullet, or a `> augmented: <label>` line. Source Material is
53
+ exempt because it holds the reporter's words verbatim.
50
54
 
51
55
  Exit code 0 on PASS, 1 on FAIL.
52
56
  """
@@ -656,6 +660,71 @@ def check_variant_required_sections(
656
660
  )
657
661
 
658
662
 
663
+ # 템플릿의 `<...>` 문구는 작성자가 바꿔 쓸 자리다. 그대로 남으면 다음 phase 가
664
+ # 그 문구를 제보 내용으로 읽는다. 문구는 여러 줄에 걸친 한 문단이라 줄 단위
665
+ # `is_template_example` 만으로는 잡히지 않는다 — 문단을 합쳐서 본다.
666
+ _AUGMENTED_LABEL_SCAFFOLD_RE = re.compile(r"^>\s*augmented:\s*<label>")
667
+
668
+
669
+ def _paragraphs_outside_fences(body: str) -> Iterable[list[str]]:
670
+ paragraph: list[str] = []
671
+ in_fence = False
672
+ for line in body.splitlines():
673
+ stripped = line.strip()
674
+ if stripped.startswith("```"):
675
+ in_fence = not in_fence
676
+ if in_fence or stripped.startswith("```") or not stripped:
677
+ if paragraph:
678
+ yield paragraph
679
+ paragraph = []
680
+ continue
681
+ paragraph.append(stripped)
682
+ if paragraph:
683
+ yield paragraph
684
+
685
+
686
+ def template_scaffold(body: str) -> list[str]:
687
+ """Template scaffolding left in a section body, one entry per leftover."""
688
+ found: list[str] = []
689
+ for paragraph in _paragraphs_outside_fences(body):
690
+ joined = " ".join(paragraph)
691
+ if joined.startswith("<") and joined.endswith(">"):
692
+ found.append(joined)
693
+ continue
694
+ found.extend(
695
+ line
696
+ for line in paragraph
697
+ if is_template_example(line) or _AUGMENTED_LABEL_SCAFFOLD_RE.match(line)
698
+ )
699
+ return found
700
+
701
+
702
+ def check_template_scaffold(text: str, scope: str, errors: list[str]) -> None:
703
+ """Required sections must not keep the template's `<...>` scaffolding.
704
+
705
+ `## Source Material` is exempt: it holds the reporter's words verbatim,
706
+ and those can legitimately contain angle-bracketed text.
707
+ """
708
+ headings = [
709
+ REQUIREMENT_SECTION,
710
+ *ALWAYS_REQUIRED_SECTIONS,
711
+ _GATE_SECTION,
712
+ *(heading for heading, _prefix in _END_STATE_SECTIONS),
713
+ ]
714
+ if scope == "codebase":
715
+ headings += ["Scan Scope", "Priority Lenses"]
716
+ else:
717
+ headings.append("Problem / Symptom")
718
+ for heading in headings:
719
+ leftover = template_scaffold(section_body(text, heading))
720
+ if leftover:
721
+ errors.append(
722
+ f"'## {heading}' still carries template text {leftover[0][:60]!r} — "
723
+ "replace it with the brief's content, or _(none)_ when the section "
724
+ "is deliberately empty. Downstream phases read this section as written"
725
+ )
726
+
727
+
659
728
  def check_reporter_confirmations(
660
729
  rc_status: str | None, reporter_rows: list[str], errors: list[str]
661
730
  ) -> None:
@@ -724,6 +793,7 @@ def validate_brief(path: Path, briefs_root: Path) -> list[str]:
724
793
  check_requirement_section(text, errors)
725
794
  check_end_state_sections(text, scope, errors)
726
795
  check_variant_required_sections(text, scope, errors)
796
+ check_template_scaffold(text, scope, errors)
727
797
 
728
798
  # 2. brief-id matches filename stem
729
799
  stem = path.stem
@@ -34,6 +34,7 @@ from okstra_ctl.stage_map import ( # noqa: E402
34
34
  parse_stage_dependencies,
35
35
  parse_stage_map_text,
36
36
  schema_v2_report,
37
+ stage_number_gap_message,
37
38
  )
38
39
 
39
40
  HARD_STEP_CAP = 8
@@ -86,7 +87,7 @@ def _stage_numbers_monotonic(
86
87
  ) -> List[ValidationError]:
87
88
  return [
88
89
  ValidationError("S2", r.stage_number,
89
- f"stage numbers must be 1..N monotonic, got {r.stage_number} at row {i}")
90
+ stage_number_gap_message(r.stage_number, i))
90
91
  for i, r in enumerate(stages, start=1)
91
92
  if r.stage_number != i
92
93
  ]
@@ -43,6 +43,7 @@ from okstra_project.resolver import resolve_architecture # noqa: E402
43
43
  from okstra_ctl.conformance import ( # noqa: E402
44
44
  conformance_result_file,
45
45
  detect_surfaces,
46
+ declared_stage_surface_gaps,
46
47
  exempt_stage_surface_conflicts,
47
48
  evaluate_conformance,
48
49
  manifest_required_surfaces,
@@ -2120,7 +2121,13 @@ def _declared_conformance_errors(
2120
2121
  and all(isinstance(value, str) for value in actual_requires)
2121
2122
  else None
2122
2123
  )
2123
- if actual_capabilities != frozenset(declaration.get("requires") or []):
2124
+ # 넓히는 것만 허용한다 — 선언보다 많은 capability 는 더 엄격한 검증이다.
2125
+ # 승인된 계획이 `requires` 를 좁게 적고 그 stage 의 diff 가 다른 표면을
2126
+ # 건드리면, diff-surface 대조는 넓힐 것을 요구하는데 정확 일치는 그것을
2127
+ # 거절해 같은 계획으로는 통과할 입력이 없었다(2026-09-22 dev-10860
2128
+ # Stage 1). 좁히는 것은 선언한 검증을 빼는 것이므로 여전히 불일치다.
2129
+ declared_capabilities = frozenset(declaration.get("requires") or [])
2130
+ if actual_capabilities is None or not actual_capabilities >= declared_capabilities:
2124
2131
  errors.append(f"stage {stage_number} requires mismatch")
2125
2132
  # 계획이 면제한 stage 에 구현이 실제 Tier 3 항목을 붙이는 것은 허용한다 —
2126
2133
  # 면제 stage 의 diff 가 db/io/http/external 표면을 건드려 diff-surface 대조에
@@ -2183,6 +2190,24 @@ def _project_surface_patterns(project_root: Path) -> object:
2183
2190
  return None
2184
2191
 
2185
2192
 
2193
+ def _implemented_stages(data_path: Path) -> frozenset[int]:
2194
+ """이 태스크에서 구현이 끝난 stage. 원장을 못 읽으면 빈 집합이다."""
2195
+ from okstra_ctl.consumers import read_stage_consumer_state
2196
+
2197
+ try:
2198
+ state = read_stage_consumer_state(data_path.parent.parent)
2199
+ except (OSError, UnicodeError, ValueError):
2200
+ return frozenset()
2201
+ return frozenset(state.done_stages)
2202
+
2203
+
2204
+ def _is_implemented_stage(stage: object, implemented: frozenset[int]) -> bool:
2205
+ number = stage.get("stage") if isinstance(stage, dict) else None
2206
+ return isinstance(number, int) and not isinstance(number, bool) and (
2207
+ number in implemented
2208
+ )
2209
+
2210
+
2186
2211
  def _validate_planning_conformance_declared(
2187
2212
  report_path: Path,
2188
2213
  failures: list[str],
@@ -2209,7 +2234,17 @@ def _validate_planning_conformance_declared(
2209
2234
  ip = data.get("implementationPlanning")
2210
2235
  if not isinstance(ip, dict):
2211
2236
  return
2212
- _planning_conformance_declarations(ip.get("stages"), failures)
2237
+ # 구현이 끝난 stage 는 이 게이트의 대상이 아니다. 그 본문은 다음 계획 run 에
2238
+ # 그대로 이월되고(ADR-0015), 이월된 본문은 고칠 수 없다 — 규칙이 그 사이에
2239
+ # 넓어졌다면 통과 가능한 값이 없는 요구가 된다(2026-09-24, dev-10860: 이월된
2240
+ # stage 2·3·5 가 오늘의 표면 패턴으로 `requires` 누락 판정).
2241
+ implemented = _implemented_stages(data_path)
2242
+ stages = [
2243
+ stage
2244
+ for stage in ip.get("stages") or ()
2245
+ if not _is_implemented_stage(stage, implemented)
2246
+ ]
2247
+ _planning_conformance_declarations(stages, failures)
2213
2248
  if ip.get("planningContract") != "selected-direction":
2214
2249
  from okstra_ctl.implementation_direction import (
2215
2250
  stage_validation_executability_errors,
@@ -2217,6 +2252,8 @@ def _validate_planning_conformance_declared(
2217
2252
 
2218
2253
  failures.extend(stage_validation_executability_errors(ip))
2219
2254
  for conflict in exempt_stage_surface_conflicts(data, surface_patterns):
2255
+ if conflict["stage"] in implemented:
2256
+ continue
2220
2257
  failures.append(
2221
2258
  "conformance gate BLOCKING: stage "
2222
2259
  f"{conflict['stage']} declares `Conformance exemption:` but its "
@@ -2229,6 +2266,19 @@ def _validate_planning_conformance_declared(
2229
2266
  "blocks the same stage after the work is done, where the approved "
2230
2267
  "plan can no longer be corrected."
2231
2268
  )
2269
+ for gap in declared_stage_surface_gaps(data, surface_patterns):
2270
+ if gap["stage"] in implemented:
2271
+ continue
2272
+ failures.append(
2273
+ "conformance gate BLOCKING: stage "
2274
+ f"{gap['stage']} declares `Conformance tests:` with "
2275
+ f"requires={gap['requires']} but its planned paths touch surface(s) "
2276
+ f"{gap['surfaces']}: {', '.join(gap['paths'])} — add "
2277
+ f"{gap['surfaces']} to that stage's `requires`, or move those paths "
2278
+ "out of it. The implementation run's diff-surface check demands "
2279
+ "the wider set after the work is done, where the approved plan can "
2280
+ "no longer be corrected."
2281
+ )
2232
2282
 
2233
2283
 
2234
2284
  def _validate_conformance_surfaces(
@@ -5728,7 +5778,7 @@ def _validate_verified_row_recorded(
5728
5778
  report_path: Path,
5729
5779
  failures: list[str],
5730
5780
  ) -> None:
5731
- """A release-ready single-stage verification must leave its `verified` row.
5781
+ """A release-ready verification must leave a `verified` row per cleared stage.
5732
5782
 
5733
5783
  `okstra handoff record-verified` validates its own inputs, but nothing
5734
5784
  checked that it ever ran. Skipping it leaves the report saying `accepted`
@@ -5737,7 +5787,8 @@ def _validate_verified_row_recorded(
5737
5787
  the only recoveries are re-running an expensive phase or hand-editing the
5738
5788
  registry.
5739
5789
  """
5740
- if str(data.get("verificationScope") or "") != "single-stage":
5790
+ scope = str(data.get("verificationScope") or "")
5791
+ if scope not in ("single-stage", "whole-task"):
5741
5792
  return
5742
5793
  if not release_handoff_allowed(data):
5743
5794
  return
@@ -5752,11 +5803,17 @@ def _validate_verified_row_recorded(
5752
5803
  if rows is None:
5753
5804
  return
5754
5805
  head = ((data.get("finalVerification") or {}).get("sourceImplementationReport") or {}).get("capturedHeadSha")
5806
+ # 전체 task 행의 `head_commit` 은 그 stage 자신의 완료 커밋이다. 검증된 head
5807
+ # 는 `verified_head_commit` 에 있으므로, 그 행을 stage 커밋으로 찾으면 모든
5808
+ # stage 가 누락으로 읽힌다.
5809
+ head_field = (
5810
+ "verified_head_commit" if scope == "whole-task" else "head_commit"
5811
+ )
5755
5812
  verified = {
5756
5813
  row.get("stage")
5757
5814
  for row in rows
5758
5815
  if isinstance(row, dict) and row.get("status") == "verified"
5759
- and head and row.get("head_commit") == head
5816
+ and head and row.get(head_field) == head
5760
5817
  and row.get("final_verdict") == data.get("finalVerdict")
5761
5818
  and _data_path_for(Path(str(row.get("report_path") or ""))).resolve() == _data_path_for(report_path).resolve()
5762
5819
  }
@@ -5766,9 +5823,9 @@ def _validate_verified_row_recorded(
5766
5823
  f"final-verification cleared stage(s) {missing} for release but "
5767
5824
  "`runs/implementation-planning/consumers.jsonl` carries no "
5768
5825
  "`verified` row matching this report and captured commit. Run `okstra handoff record-verified` "
5769
- "before finishing — without that row the report says accepted "
5770
- "while the registry says unverified, and the stage is never "
5771
- "offered for a stage-group PR "
5826
+ "before finishing — once per cleared stage — without that row the "
5827
+ "report says accepted while the registry says unverified, and the "
5828
+ "stage is never offered for a pull request "
5772
5829
  '(final-verification.md §"Verified-row recording").'
5773
5830
  )
5774
5831
 
@@ -8065,19 +8122,19 @@ def _validate_final_verification_consistency(data: dict, failures: list[str]) ->
8065
8122
  "`blocksReleaseHandoff: false`."
8066
8123
  )
8067
8124
 
8125
+ if routing_token == "final-verification" and token == "accepted":
8126
+ failures.append(
8127
+ "final-verification: routingRecommendation cites `final-verification` "
8128
+ "but the verdict is `accepted` — an accepted verdict carries no blocker "
8129
+ "to re-verify. Route to release-handoff or done."
8130
+ )
8131
+
8068
8132
  scope = data.get("verificationScope", "whole-task")
8069
8133
  if scope not in ("whole-task", "single-stage"):
8070
8134
  failures.append(
8071
8135
  f"final-verification: verificationScope must be `whole-task` or "
8072
8136
  f"`single-stage`, got {scope!r}."
8073
8137
  )
8074
- if scope == "single-stage" and routing_token == "release-handoff":
8075
- failures.append(
8076
- "final-verification: verificationScope `single-stage` cannot recommend "
8077
- "plain release-handoff routing — a single-stage accepted verdict may "
8078
- "only route to `release-handoff(stage-group)` (partial-PR mode); "
8079
- "whole-task release-handoff requires whole-task verification."
8080
- )
8081
8138
 
8082
8139
 
8083
8140
  def validate_report_views(report_path: Path, failures: list[str]) -> None:
@@ -441,6 +441,15 @@ def _validate_format(path: Path) -> list[str]:
441
441
  f"{why}; a stage block is Steps plus Exit criteria"
442
442
  )
443
443
 
444
+ # 9b. The At a Glance work column is titled in the schedule's language.
445
+ glance_header = (
446
+ f"| # | {labels['glance_work_column']} | Category | Priority | Effort | Days | Risk |"
447
+ )
448
+ if "## At a Glance" in section_positions and glance_header not in text:
449
+ violations.append(
450
+ f"`## At a Glance` requires the header literal {glance_header!r}"
451
+ )
452
+
444
453
  # 10. Days total format inside At a Glance: `**N tasks total / estimated effort: X.X ~ Y.Y days (Effort sum)**`
445
454
  if "## At a Glance" in section_positions:
446
455
  start = section_positions["## At a Glance"]
@@ -1,68 +0,0 @@
1
- # Okstra Skills AI Manuals
2
-
3
- This directory is a compressed manual for an AI to quickly select and precisely run okstra public skills. The authoritative contract is `skills/*/SKILL.md`; this document is the operational guide for the AI. When the source skills, templates, validators, or CLI registry conflict, prefer the source skills and the actual validator/CLI implementation.
4
-
5
- ## Verified Sources
6
-
7
- - Public skill list: [`src/lib/skill-catalog.mjs`](../../src/lib/skill-catalog.mjs)
8
- - Skill sources: [`skills/`](../../skills/)
9
- - CLI command surface: [`src/cli-registry.mjs`](../../src/cli-registry.mjs)
10
- - brief template: [`templates/reports/brief.template.md`](../../templates/reports/brief.template.md)
11
- - schedule template: [`templates/reports/schedule.template.md`](../../templates/reports/schedule.template.md)
12
- - brief validator: [`validators/validate-brief.py`](../../validators/validate-brief.py)
13
- - schedule validator: [`validators/validate-schedule.py`](../../validators/validate-schedule.py)
14
-
15
- ## Skill Routing
16
-
17
- | User intent | Skill to use | Manual |
18
- |---|---|---|
19
- | Install/initialize okstra on a new project or a new machine | `okstra-setup` | [`skills/okstra-setup.md`](skills/okstra-setup.md) |
20
- | Turn requirements, tickets, links, a codebase scan, or an error-zip into an okstra input brief | `okstra-brief-gen` | [`skills/okstra-brief-gen.md`](skills/okstra-brief-gen.md) |
21
- | Start an okstra run or execute the next phase in the current Claude Code session | `okstra-run` | [`skills/okstra-run.md`](skills/okstra-run.md) |
22
- | Manage okstra tasks across multiple projects — bundling, assignment, sync snapshots, child launch packets | `okstra-manager` | [`skills/okstra-manager.md`](skills/okstra-manager.md) |
23
- | Check status, history, report, time, logs, cost, errors, error-zip, run-audit, recap | `okstra-inspect` | [`skills/okstra-inspect.md`](skills/okstra-inspect.md) |
24
- | Collect and aggregate the results of multiple task runs across a task-group (or the whole project) into a synthesized summary | `okstra-rollup` | [`skills/okstra-rollup.md`](skills/okstra-rollup.md) |
25
- | Project-wide recent run coverage, tokens, known cost, CPU, and wall-clock usage by task type | `okstra-usage` | [`skills/okstra-usage.md`](skills/okstra-usage.md) |
26
- | Generate a client-facing work schedule for a whole task-group | `okstra-schedule-gen` | [`skills/okstra-schedule-gen.md`](skills/okstra-schedule-gen.md) |
27
- | Store or search conversations/decisions/preferences/requirements in the global Memory Book | `okstra-memory` | [`skills/okstra-memory.md`](skills/okstra-memory.md) |
28
- | Create or join a global room and send or read addressed messages across host sessions | `okstra-chat` | [`skills/okstra-chat.md`](skills/okstra-chat.md) |
29
- | Manage the implementation-task worktree-based docker compose user-test environment | `okstra-container-build` | [`skills/okstra-container-build.md`](skills/okstra-container-build.md) |
30
- | Answer the unresolved clarification questions an okstra run left behind in-session and record the approval gate | `okstra-user-response` | [`skills/okstra-user-response.md`](skills/okstra-user-response.md) |
31
- | Register a PR body template or generate a PR description from a branch diff (global, git repository) | `okstra-pr-gen` | [`skills/okstra-pr-gen.md`](skills/okstra-pr-gen.md) |
32
- | Review the changed code of one okstra `implementation` stage or of any branch against the coding-preflight rules, and write the result to a file | `okstra-code-review` | [`skills/okstra-code-review.md`](skills/okstra-code-review.md) |
33
-
34
- ## Shared Execution Rules
35
-
36
- 1. Run commands as separate Bash calls whenever the source skill requires it. In particular, do not wrap `okstra preflight --runtime claude-code`, `okstra wizard ...`, or `okstra container ...` calls in `&&`, `||`, `$(...)`, a leading variable assignment, `eval`, or `export`.
37
- 2. An `okstra <subcmd>` call bootstraps its own Python path. Unless a skill states otherwise, do not build `okstra paths --shell` or `export PYTHONPATH=...`.
38
- 3. Most skills except `okstra-setup` do not use an `npx` fallback. If the runtime is missing, tell the user to run `/okstra-setup` and stop. But if it fails with `unknown command: <cmd>`, the `okstra` binary on PATH is older than the skill — point the user to `npm i -g okstra@latest` rather than `/okstra-setup`, and stop.
39
- 4. Project artifacts go under `<PROJECT_ROOT>/.okstra/` by default. The exceptions are `okstra-memory` (`~/.okstra/memory-book/`) and `okstra-chat` (`~/.okstra/chat/`).
40
- 5. `runtime/` is build output. When fixing a source skill or template, edit the source under `skills/`, `templates/`, `validators/`, `scripts/`, `src/` and apply it via a build.
41
- 6. Do not guess the contents of a tracker, URL, file, report, log, zip, template, or validator. Use only what you have confirmed by reading or running with a tool.
42
- 7. Read-side skills also produce some artifacts. `okstra-inspect errors` produces an error report Markdown and `okstra-inspect error-zip` produces an anonymized zip. Even in these cases, keep the purpose-specific fixed CLI fields as the source of truth.
43
-
44
- ## The Order the AI Reads In
45
-
46
- 1. Pick a skill in this file.
47
- 2. Read only the matching `docs/for-ai/skills/<skill>.md`.
48
- 3. If the skill requires actual execution, confirm the relevant step in the source [`skills/<skill>/SKILL.md`](../../skills/).
49
- 4. When writing a brief or schedule, also confirm the template and the validator.
50
-
51
- ## Public Skill List
52
-
53
- The public skills listed in this AI manual are the following 14:
54
-
55
- - `okstra-setup`
56
- - `okstra-brief-gen`
57
- - `okstra-run`
58
- - `okstra-manager`
59
- - `okstra-memory`
60
- - `okstra-chat`
61
- - `okstra-inspect`
62
- - `okstra-rollup`
63
- - `okstra-usage`
64
- - `okstra-schedule-gen`
65
- - `okstra-container-build`
66
- - `okstra-user-response`
67
- - `okstra-pr-gen`
68
- - `okstra-code-review`