okstra 0.201.3 → 0.204.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 (273) hide show
  1. package/README.md +3 -3
  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/lifecycle/setup.mjs +15 -0
  7. package/dist/commands/lifecycle/setup.mjs.map +1 -1
  8. package/dist/commands/memory/memory.mjs +41 -8
  9. package/dist/commands/memory/memory.mjs.map +1 -1
  10. package/dist/lib/citation-guidance.d.mts +21 -0
  11. package/dist/lib/citation-guidance.mjs +79 -0
  12. package/dist/lib/citation-guidance.mjs.map +1 -0
  13. package/dist/lib/install-assets.mjs +3 -0
  14. package/dist/lib/install-assets.mjs.map +1 -1
  15. package/dist/lib/runtime-manifest.mjs +2 -1
  16. package/dist/lib/runtime-manifest.mjs.map +1 -1
  17. package/dist/lib/types.d.mts +2 -1
  18. package/docs/architecture/storage-model.md +17 -10
  19. package/docs/architecture.md +26 -20
  20. package/docs/cli.md +16 -13
  21. package/docs/contributor-change-matrix.md +3 -2
  22. package/docs/performance-improvement-plan-v2.md +2 -3
  23. package/docs/project-structure-overview.md +38 -9
  24. package/docs/task-process/README.md +1 -1
  25. package/docs/task-process/common-flow.md +1 -1
  26. package/docs/task-process/final-verification.md +3 -1
  27. package/docs/task-process/implementation.md +1 -1
  28. package/docs/task-process/release-handoff.md +36 -39
  29. package/package.json +1 -2
  30. package/runtime/BUILD.json +2 -2
  31. package/runtime/agents/common.json +28 -0
  32. package/runtime/agents/operations/code-review.json +6 -0
  33. package/runtime/agents/operations/report-translation.json +6 -0
  34. package/runtime/agents/operations/schedule-verification.json +6 -0
  35. package/runtime/agents/roles/analyser.json +18 -0
  36. package/runtime/agents/roles/critic.json +18 -0
  37. package/runtime/agents/roles/designer.json +18 -0
  38. package/runtime/agents/roles/implementer.json +20 -0
  39. package/runtime/agents/roles/leader.json +20 -0
  40. package/runtime/agents/roles/planner.json +18 -0
  41. package/runtime/agents/roles/report-writer.json +19 -0
  42. package/runtime/agents/roles/translator.json +19 -0
  43. package/runtime/agents/roles/verifier.json +18 -0
  44. package/runtime/bin/lib/okstra/usage.sh +5 -5
  45. package/runtime/prompts/duties/acceptance-critic.json +32 -0
  46. package/runtime/prompts/duties/acceptance-verifier.json +32 -0
  47. package/runtime/prompts/duties/analysis-worker.json +32 -0
  48. package/runtime/prompts/duties/code-reviewer.json +32 -0
  49. package/runtime/prompts/duties/diagnosis-worker.json +32 -0
  50. package/runtime/prompts/duties/direction-selection-worker.json +32 -0
  51. package/runtime/prompts/duties/discovery-worker.json +32 -0
  52. package/runtime/prompts/duties/implementation-executor.json +32 -0
  53. package/runtime/prompts/duties/implementation-verifier.json +32 -0
  54. package/runtime/prompts/duties/lead.json +32 -0
  55. package/runtime/prompts/duties/planning-worker.json +36 -0
  56. package/runtime/prompts/duties/report-writer.json +32 -0
  57. package/runtime/prompts/duties/reverification-worker.json +32 -0
  58. package/runtime/prompts/duties/schedule-verifier.json +32 -0
  59. package/runtime/prompts/duties/scope-critic.json +32 -0
  60. package/runtime/prompts/duties/technical-verification-worker.json +32 -0
  61. package/runtime/prompts/duties/translator.json +32 -0
  62. package/runtime/prompts/launch.template.md +3 -2
  63. package/runtime/prompts/lead/adapters/cmux.md +1 -1
  64. package/runtime/prompts/lead/convergence.md +4 -4
  65. package/runtime/prompts/lead/okstra-lead-contract.md +115 -6
  66. package/runtime/prompts/lead/plan-body-verification.md +6 -6
  67. package/runtime/prompts/lead/report-writer.md +3 -3
  68. package/runtime/prompts/profiles/_common-contract.md +2 -2
  69. package/runtime/prompts/profiles/_implementation-executor.md +4 -1
  70. package/runtime/prompts/profiles/_implementation-verifier.md +3 -3
  71. package/runtime/prompts/profiles/change-impact-analysis.json +31 -0
  72. package/runtime/prompts/profiles/change-impact-analysis.md +0 -20
  73. package/runtime/prompts/profiles/error-analysis.json +39 -0
  74. package/runtime/prompts/profiles/error-analysis.md +0 -25
  75. package/runtime/prompts/profiles/feature-analysis.json +31 -0
  76. package/runtime/prompts/profiles/feature-analysis.md +0 -20
  77. package/runtime/prompts/profiles/final-verification.json +30 -0
  78. package/runtime/prompts/profiles/final-verification.md +3 -22
  79. package/runtime/prompts/profiles/forbidden-actions.json +4 -3
  80. package/runtime/prompts/profiles/implementation-option-selection.json +31 -0
  81. package/runtime/prompts/profiles/implementation-option-selection.md +0 -20
  82. package/runtime/prompts/profiles/implementation-planning.json +40 -0
  83. package/runtime/prompts/profiles/implementation-planning.md +6 -29
  84. package/runtime/prompts/profiles/implementation.json +30 -0
  85. package/runtime/prompts/profiles/implementation.md +1 -20
  86. package/runtime/prompts/profiles/improvement-discovery.json +31 -0
  87. package/runtime/prompts/profiles/improvement-discovery.md +0 -20
  88. package/runtime/prompts/profiles/project-analysis.json +31 -0
  89. package/runtime/prompts/profiles/project-analysis.md +0 -20
  90. package/runtime/prompts/profiles/release-handoff.json +5 -0
  91. package/runtime/prompts/profiles/release-handoff.md +71 -73
  92. package/runtime/prompts/profiles/requirements-discovery.json +39 -0
  93. package/runtime/prompts/profiles/requirements-discovery.md +0 -25
  94. package/runtime/prompts/profiles/technical-verification.json +39 -0
  95. package/runtime/prompts/profiles/technical-verification.md +0 -25
  96. package/runtime/prompts/wizard/prompts.ko.json +12 -17
  97. package/runtime/python/okstra_ctl/adapters/hosts/antigravity/relay.md +1 -0
  98. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/adapter.py +3 -0
  99. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/manifest.json +1 -1
  100. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/relay.md +4 -3
  101. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/worker-session.md +108 -0
  102. package/runtime/python/okstra_ctl/adapters/hosts/codex/relay.md +1 -0
  103. package/runtime/python/okstra_ctl/adapters/hosts/grok/relay.md +2 -0
  104. package/runtime/python/okstra_ctl/adapters/hosts/kimi/relay.md +2 -0
  105. package/runtime/python/okstra_ctl/adapters/providers/antigravity/adapter.py +8 -1
  106. package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +8 -0
  107. package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +23 -6
  108. package/runtime/python/okstra_ctl/adapters/providers/grok/adapter.py +6 -2
  109. package/runtime/python/okstra_ctl/agent/invocation.py +168 -113
  110. package/runtime/python/okstra_ctl/agent/prompt_cli/cli.py +120 -0
  111. package/runtime/python/okstra_ctl/agent/prompt_cli/materialize.py +107 -2
  112. package/runtime/python/okstra_ctl/agent/prompt_cli/run_identity.py +0 -49
  113. package/runtime/python/okstra_ctl/analysis_packet.py +4 -1
  114. package/runtime/python/okstra_ctl/application/open_worker.py +6 -1
  115. package/runtime/python/okstra_ctl/assignment_resolver.py +16 -5
  116. package/runtime/python/okstra_ctl/cmux.py +69 -20
  117. package/runtime/python/okstra_ctl/code_review_target.py +16 -8
  118. package/runtime/python/okstra_ctl/conformance.py +43 -0
  119. package/runtime/python/okstra_ctl/consumers.py +6 -3
  120. package/runtime/python/okstra_ctl/container.py +31 -8
  121. package/runtime/python/okstra_ctl/context_cost.py +11 -15
  122. package/runtime/python/okstra_ctl/contract_refreeze.py +156 -0
  123. package/runtime/python/okstra_ctl/convergence_critic_prompt.py +4 -6
  124. package/runtime/python/okstra_ctl/convergence_provenance.py +81 -18
  125. package/runtime/python/okstra_ctl/design_prep.py +34 -1
  126. package/runtime/python/okstra_ctl/dispatch_core.py +53 -27
  127. package/runtime/python/okstra_ctl/domain/host.py +5 -0
  128. package/runtime/python/okstra_ctl/domain/worker_runtime.py +10 -0
  129. package/runtime/python/okstra_ctl/error_report.py +4 -3
  130. package/runtime/python/okstra_ctl/execution_manifest.py +71 -18
  131. package/runtime/python/okstra_ctl/execution_mutation_audit.py +21 -21
  132. package/runtime/python/okstra_ctl/handoff.py +167 -277
  133. package/runtime/python/okstra_ctl/implementation_stage.py +9 -0
  134. package/runtime/python/okstra_ctl/initial_prompt_materialization.py +113 -0
  135. package/runtime/python/okstra_ctl/lead_progress.py +1 -1
  136. package/runtime/python/okstra_ctl/legacy_model_selection.py +2 -2
  137. package/runtime/python/okstra_ctl/manager_cli.py +175 -14
  138. package/runtime/python/okstra_ctl/manager_launch.py +41 -19
  139. package/runtime/python/okstra_ctl/manager_paths.py +22 -3
  140. package/runtime/python/okstra_ctl/manager_split.py +474 -0
  141. package/runtime/python/okstra_ctl/manager_store.py +331 -21
  142. package/runtime/python/okstra_ctl/manager_sync.py +37 -16
  143. package/runtime/python/okstra_ctl/manager_view.py +217 -0
  144. package/runtime/python/okstra_ctl/model_discovery.py +30 -0
  145. package/runtime/python/okstra_ctl/model_io/lines.py +14 -1
  146. package/runtime/python/okstra_ctl/model_io/renderers.py +4 -3
  147. package/runtime/python/okstra_ctl/models.py +1 -1
  148. package/runtime/python/okstra_ctl/next_phase.py +16 -6
  149. package/runtime/python/okstra_ctl/operation_invocation.py +86 -0
  150. package/runtime/python/okstra_ctl/option_comparison.py +168 -0
  151. package/runtime/python/okstra_ctl/path_hints.py +9 -0
  152. package/runtime/python/okstra_ctl/paths.py +3 -0
  153. package/runtime/python/okstra_ctl/plan_items_cli.py +6 -1
  154. package/runtime/python/okstra_ctl/profile_show.py +42 -1
  155. package/runtime/python/okstra_ctl/qa_commands.py +15 -0
  156. package/runtime/python/okstra_ctl/registry/host_discovery.py +20 -12
  157. package/runtime/python/okstra_ctl/registry/host_registry.py +11 -0
  158. package/runtime/python/okstra_ctl/render.py +50 -0
  159. package/runtime/python/okstra_ctl/report_contract.py +1 -1
  160. package/runtime/python/okstra_ctl/report_finalize.py +13 -6
  161. package/runtime/python/okstra_ctl/report_html/view_models/final_verification.py +2 -21
  162. package/runtime/python/okstra_ctl/report_html/view_models/release_handoff.py +21 -3
  163. package/runtime/python/okstra_ctl/report_html/visualizations.py +0 -5
  164. package/runtime/python/okstra_ctl/report_synthesis_packet.py +177 -17
  165. package/runtime/python/okstra_ctl/report_translation.py +2 -1
  166. package/runtime/python/okstra_ctl/report_translation_dispatch.py +69 -9
  167. package/runtime/python/okstra_ctl/role_requirements.py +142 -129
  168. package/runtime/python/okstra_ctl/rollup.py +3 -1
  169. package/runtime/python/okstra_ctl/run.py +76 -29
  170. package/runtime/python/okstra_ctl/schedule_semantics.py +17 -6
  171. package/runtime/python/okstra_ctl/stage_fix_carry.py +23 -4
  172. package/runtime/python/okstra_ctl/stage_integrate.py +178 -18
  173. package/runtime/python/okstra_ctl/stage_map.py +16 -2
  174. package/runtime/python/okstra_ctl/stage_targets.py +209 -43
  175. package/runtime/python/okstra_ctl/team.py +22 -13
  176. package/runtime/python/okstra_ctl/time_report.py +2 -1
  177. package/runtime/python/okstra_ctl/usage_report.py +3 -1
  178. package/runtime/python/okstra_ctl/verification_target.py +13 -2
  179. package/runtime/python/okstra_ctl/wizard/confirmation.py +3 -9
  180. package/runtime/python/okstra_ctl/wizard/ids.py +1 -1
  181. package/runtime/python/okstra_ctl/wizard/registry.py +1 -1
  182. package/runtime/python/okstra_ctl/wizard/state.py +3 -5
  183. package/runtime/python/okstra_ctl/wizard/steps_plan.py +3 -23
  184. package/runtime/python/okstra_ctl/worker_prompt_contract.py +5 -1
  185. package/runtime/python/okstra_ctl/worker_prompt_headers.py +35 -7
  186. package/runtime/python/okstra_ctl/worker_prompt_policy.py +66 -48
  187. package/runtime/python/okstra_ctl/workflow.py +1 -1
  188. package/runtime/python/okstra_ctl/worktree/__init__.py +3 -1
  189. package/runtime/python/okstra_ctl/worktree/naming.py +9 -0
  190. package/runtime/python/okstra_ctl/worktree_registry.py +38 -9
  191. package/runtime/python/okstra_token_usage/pricing.py +6 -4
  192. package/runtime/schemas/agent-common-v1.schema.json +34 -0
  193. package/runtime/schemas/agent-duty-v1.schema.json +38 -0
  194. package/runtime/schemas/agent-operation-v1.schema.json +11 -0
  195. package/runtime/schemas/agent-profile-v1.schema.json +46 -0
  196. package/runtime/schemas/agent-role-v1.schema.json +29 -0
  197. package/runtime/schemas/final-report-v2.0.schema.json +118 -97
  198. package/runtime/schemas/final-report-v3.0.schema.json +118 -97
  199. package/runtime/skills/okstra-brief-gen/SKILL.md +84 -4
  200. package/runtime/skills/okstra-chat/SKILL.md +2 -2
  201. package/runtime/skills/okstra-code-review/SKILL.md +23 -9
  202. package/runtime/skills/okstra-container-build/SKILL.md +10 -10
  203. package/runtime/skills/okstra-inspect/SKILL.md +1 -1
  204. package/runtime/skills/okstra-inspect/facets/cost.md +1 -1
  205. package/runtime/skills/okstra-inspect/facets/error-zip.md +9 -9
  206. package/runtime/skills/okstra-inspect/facets/errors.md +16 -16
  207. package/runtime/skills/okstra-inspect/facets/logs.md +7 -7
  208. package/runtime/skills/okstra-inspect/facets/recap.md +2 -2
  209. package/runtime/skills/okstra-inspect/facets/report.md +1 -1
  210. package/runtime/skills/okstra-inspect/facets/status.md +4 -3
  211. package/runtime/skills/okstra-inspect/facets/time.md +11 -10
  212. package/runtime/skills/okstra-manager/SKILL.md +70 -5
  213. package/runtime/skills/okstra-pr-gen/SKILL.md +6 -5
  214. package/runtime/skills/okstra-rollup/SKILL.md +5 -5
  215. package/runtime/skills/okstra-run/SKILL.md +32 -13
  216. package/runtime/skills/okstra-schedule-gen/SKILL.md +19 -14
  217. package/runtime/skills/okstra-setup/SKILL.md +21 -10
  218. package/runtime/skills/okstra-setup/references/project-config.md +7 -6
  219. package/runtime/skills/okstra-usage/SKILL.md +1 -1
  220. package/runtime/skills/okstra-user-response/SKILL.md +1 -1
  221. package/runtime/templates/manager/view.template.html +109 -0
  222. package/runtime/templates/report-writer-prompt-preamble.md +8 -0
  223. package/runtime/templates/reports/brief.template.md +14 -4
  224. package/runtime/templates/reports/html/i18n/en.json +7 -4
  225. package/runtime/templates/reports/html/i18n/ko.json +7 -4
  226. package/runtime/templates/reports/html/tasks/final-verification.template.html +2 -2
  227. package/runtime/templates/reports/html/tasks/release-handoff.template.html +8 -5
  228. package/runtime/templates/reports/i18n/en.json +1 -1
  229. package/runtime/templates/reports/md/tasks/release-handoff.template.md +1 -1
  230. package/runtime/templates/reports/release-handoff-input.template.md +6 -4
  231. package/runtime/templates/translator-prompt-preamble.md +36 -0
  232. package/runtime/validators/checks/validate-assets-01.py +7 -8
  233. package/runtime/validators/validate-brief.py +77 -2
  234. package/runtime/validators/validate-implementation-plan-stages.py +2 -1
  235. package/runtime/validators/validate-run.py +59 -9
  236. package/runtime/validators/validate-schedule.py +9 -0
  237. package/docs/for-ai/README.md +0 -68
  238. package/docs/for-ai/skills/okstra-brief-gen.md +0 -262
  239. package/docs/for-ai/skills/okstra-chat.md +0 -34
  240. package/docs/for-ai/skills/okstra-code-review.md +0 -57
  241. package/docs/for-ai/skills/okstra-container-build.md +0 -129
  242. package/docs/for-ai/skills/okstra-inspect.md +0 -262
  243. package/docs/for-ai/skills/okstra-manager.md +0 -69
  244. package/docs/for-ai/skills/okstra-memory.md +0 -126
  245. package/docs/for-ai/skills/okstra-pr-gen.md +0 -49
  246. package/docs/for-ai/skills/okstra-rollup.md +0 -114
  247. package/docs/for-ai/skills/okstra-run.md +0 -250
  248. package/docs/for-ai/skills/okstra-schedule-gen.md +0 -240
  249. package/docs/for-ai/skills/okstra-setup.md +0 -158
  250. package/docs/for-ai/skills/okstra-usage.md +0 -29
  251. package/docs/for-ai/skills/okstra-user-response.md +0 -72
  252. package/runtime/agents/workers/claude-worker.md +0 -128
  253. package/runtime/agents/workers/report-writer-worker.md +0 -37
  254. package/runtime/agents/workers/translator-worker.md +0 -63
  255. package/runtime/prompts/duties/acceptance-critic.md +0 -44
  256. package/runtime/prompts/duties/acceptance-verifier.md +0 -44
  257. package/runtime/prompts/duties/analysis-worker.md +0 -44
  258. package/runtime/prompts/duties/code-reviewer.md +0 -44
  259. package/runtime/prompts/duties/common.md +0 -39
  260. package/runtime/prompts/duties/diagnosis-worker.md +0 -44
  261. package/runtime/prompts/duties/direction-selection-worker.md +0 -44
  262. package/runtime/prompts/duties/discovery-worker.md +0 -44
  263. package/runtime/prompts/duties/implementation-executor.md +0 -44
  264. package/runtime/prompts/duties/implementation-verifier.md +0 -44
  265. package/runtime/prompts/duties/lead.md +0 -44
  266. package/runtime/prompts/duties/planning-worker.md +0 -52
  267. package/runtime/prompts/duties/report-writer.md +0 -44
  268. package/runtime/prompts/duties/reverification-worker.md +0 -44
  269. package/runtime/prompts/duties/schedule-verifier.md +0 -44
  270. package/runtime/prompts/duties/scope-critic.md +0 -44
  271. package/runtime/prompts/duties/technical-verification-worker.md +0 -44
  272. package/runtime/prompts/duties/translator.md +0 -44
  273. package/runtime/python/okstra_ctl/pane_title.py +0 -154
@@ -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
  """
@@ -104,6 +108,10 @@ AUGMENTATION_LABELS = {
104
108
 
105
109
  REPORTER_CONFIRMATION_VALUES = {"complete", "partial", "pending", "skipped"}
106
110
 
111
+ # okstra-manager `task split` renders the same brief contract for each project
112
+ # it splits a tracker issue into.
113
+ GENERATORS = {"okstra-brief-gen", "okstra-manager"}
114
+
107
115
  SCOPE_VALUES = {"reporter-input", "codebase"}
108
116
 
109
117
  TASK_GRAPH_HEADER = ["From", "Relation", "To", "Direction", "Source", "Impact"]
@@ -652,6 +660,71 @@ def check_variant_required_sections(
652
660
  )
653
661
 
654
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
+
655
728
  def check_reporter_confirmations(
656
729
  rc_status: str | None, reporter_rows: list[str], errors: list[str]
657
730
  ) -> None:
@@ -693,9 +766,10 @@ def validate_brief(path: Path, briefs_root: Path) -> list[str]:
693
766
  if fm.get("type") != "brief":
694
767
  errors.append(f"frontmatter type must be 'brief', got {fm.get('type')!r}")
695
768
 
696
- if fm.get("generator") != "okstra-brief-gen":
769
+ if fm.get("generator") not in GENERATORS:
697
770
  errors.append(
698
- f"frontmatter generator must be 'okstra-brief-gen', got {fm.get('generator')!r}"
771
+ f"frontmatter generator must be one of {sorted(GENERATORS)}, "
772
+ f"got {fm.get('generator')!r}"
699
773
  )
700
774
 
701
775
  if fm.get("reporter-confirmations") not in REPORTER_CONFIRMATION_VALUES:
@@ -719,6 +793,7 @@ def validate_brief(path: Path, briefs_root: Path) -> list[str]:
719
793
  check_requirement_section(text, errors)
720
794
  check_end_state_sections(text, scope, errors)
721
795
  check_variant_required_sections(text, scope, errors)
796
+ check_template_scaffold(text, scope, errors)
722
797
 
723
798
  # 2. brief-id matches filename stem
724
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(
@@ -8065,19 +8115,19 @@ def _validate_final_verification_consistency(data: dict, failures: list[str]) ->
8065
8115
  "`blocksReleaseHandoff: false`."
8066
8116
  )
8067
8117
 
8118
+ if routing_token == "final-verification" and token == "accepted":
8119
+ failures.append(
8120
+ "final-verification: routingRecommendation cites `final-verification` "
8121
+ "but the verdict is `accepted` — an accepted verdict carries no blocker "
8122
+ "to re-verify. Route to release-handoff or done."
8123
+ )
8124
+
8068
8125
  scope = data.get("verificationScope", "whole-task")
8069
8126
  if scope not in ("whole-task", "single-stage"):
8070
8127
  failures.append(
8071
8128
  f"final-verification: verificationScope must be `whole-task` or "
8072
8129
  f"`single-stage`, got {scope!r}."
8073
8130
  )
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
8131
 
8082
8132
 
8083
8133
  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`
@@ -1,262 +0,0 @@
1
- # okstra-brief-gen AI Manual
2
-
3
- ## Source
4
-
5
- - Skill source: [`skills/okstra-brief-gen/SKILL.md`](../../../skills/okstra-brief-gen/SKILL.md)
6
- - brief template: [`templates/reports/brief.template.md`](../../../templates/reports/brief.template.md)
7
- - brief validator: [`validators/validate-brief.py`](../../../validators/validate-brief.py)
8
- - lens enum SSOT: [`scripts/okstra_ctl/improvement_lenses.py`](../../../scripts/okstra_ctl/improvement_lenses.py)
9
-
10
- ## Purpose
11
-
12
- `okstra-brief-gen` produces a task brief to feed into the okstra pipeline. A brief is a pre-discovery artifact. It is not a document that turns requirements into an implementation plan; it is a handoff document that separates the reporter's verbatim material from the AI-verified evidence/interpretation using labels, so the next phase can start without questions.
13
-
14
- Output location:
15
-
16
- ```text
17
- <PROJECT_ROOT>/.okstra/briefs/<task-group>/<brief-id>.md
18
- <PROJECT_ROOT>/.okstra/briefs/<task-group>/sub/.../<brief-id>.md
19
- ```
20
-
21
- ## Three variants
22
-
23
- | Variant | Input | Recommended next phase |
24
- |---|---|---|
25
- | Reporter input | files, tickets, URLs, conversation/free text | `requirements-discovery` or `error-analysis` |
26
- | Codebase scan | scan scope, priority lenses, candidate cap, context | `improvement-discovery` |
27
- | Error feedback | a single error cluster from the zip produced by `okstra error-zip` | `error-analysis` |
28
-
29
- ## Core invariants
30
-
31
- 1. Source Material is a verbatim-preservation area. Do not paraphrase, summarize, or reorder.
32
- 2. The AI's interpretation, file links, terminology mapping, and format conversion all go under `Augmentation` or a `> augmented:` blockquote.
33
- 3. An augmentation carries one of four labels: `evidence-link`, `format-conversion`, `terminology-mapping`, `intent-inference`.
34
- 4. `intent-inference` is paired with `intent-check:` in `Open Questions`. This relationship is checked by `validators/validate-brief.py`.
35
- 5. A `terminology-mapping` augmentation is paired with `terminology:` in `Open Questions` (validator-checked). Exception: the Step 4.5 result markers `applied glossary:` / `skipped glossary:` need no paired row.
36
- 6. Questions only the reporter can answer are collected in Step 6.5 and recorded verbatim under `## Reporter Confirmations`.
37
- 7. Ticket split/link/order relations go in the structured table of `## Related Task Graph`. Do not infer work order from parent-id alone.
38
- 8. Every okstra-owned write stays inside `<PROJECT_ROOT>/.okstra/`. External files are read only when the reporter explicitly cited them as source.
39
- 9. Every row in `Open Questions` starts with one of five prefixes: `general:`, `terminology:`, `intent-check:`, `conversion-block:`, `adr-candidate:` (validator-enforced). `adr-candidate:` is only a signal — the decision file is written by `implementation-planning` into `<PROJECT_ROOT>/.okstra/decisions/`.
40
-
41
- ## Preflight
42
-
43
- Run as a single call.
44
-
45
- ```bash
46
- okstra preflight --runtime claude-code
47
- ```
48
-
49
- On `Okstra preflight: ready`, carry the fixed `Project root` line. On
50
- `Okstra preflight: failed`, show `Reason` and `Recovery`, then stop. This skill
51
- does not use an `npx` fallback.
52
-
53
- ## Input collection
54
-
55
- ### Reporter input
56
-
57
- More than one source type is allowed, but each source is stored as a separate block under `Source Material`.
58
-
59
- - File: read the entire file and insert it as-is.
60
- - Issue tracker ticket: detect Linear/Jira/GitHub/Notion and use MCP or the `gh` CLI. If no access tool is available, ask the user to paste the body or skip.
61
- - Link URL: fetch it. On failure / login wall / body truncation, ask the user to paste.
62
- - User input: if conversation context is sufficient, use conversation synthesis; if thin, take a single free-text input.
63
-
64
- If a ticket has children/sub-tasks, ask once at the parent how to handle the tree.
65
-
66
- - Full tree: generate a brief per descendant.
67
- - Parent only: put child keys/URLs in Related Artifacts and leave a `parent-of` edge in `Related Task Graph`.
68
- - Selected: recurse only into the chosen direct-child branch.
69
-
70
- During recursion, manage the visited set as `<tracker>:<ticket-id>`, and on re-run reseed from the existing brief frontmatter's `ticket-id` + `source-type`.
71
- When Full tree or Selected produces multiple briefs, copy the same `Related Task Graph` into every generated brief. That way, even if only one child brief is passed to a downstream phase, the split topology, predecessor/successor relations, and de-duplication signals are preserved.
72
-
73
- `Related Task Graph` table schema:
74
-
75
- | Column | Meaning |
76
- |---|---|
77
- | From | task key, brief id, tracker id, or URL |
78
- | Relation | `parent-of`, `child-of`, `depends-on`, `blocks`, `blocked-by`, `follow-up-of`, `split-from`, `duplicates`, `related-to` |
79
- | To | task key, brief id, tracker id, or URL |
80
- | Direction | `directed` or `undirected` |
81
- | Source | tracker linked issue, task-list checkbox, reporter statement, manual split, prior okstra task |
82
- | Impact | meaning the downstream phase must preserve |
83
-
84
- `depends-on`, `blocks`, parent/child, follow-up, and split relations are `directed`. `duplicates` and `related-to` are `undirected`. Do not create a relation with no source.
85
-
86
- ### Codebase scan
87
-
88
- Collected values:
89
-
90
- - `scan_scope`: a list of real paths inside the project.
91
- - `priority_lenses`: 1–4 of the `LENSES` enum.
92
- - `out_of_scope`: optional.
93
- - `candidate_cap`: 1–12, default 8.
94
- - context, desired outcome, constraints.
95
-
96
- Verify path existence, the lens enum subset, and the candidate-cap range before writing. Final validation is done by `validate-brief.py`, which checks `scope: codebase`, `Scan Scope`, and `Priority Lenses`.
97
-
98
- ### Error feedback
99
-
100
- The input is the zip produced by `okstra error-zip --out <path>`.
101
-
102
- Processing:
103
-
104
- 1. Confirm the zip contains `report.md` and `errors/anonymized.jsonl`.
105
- 2. Pick exactly one cluster from the frequent-cluster table.
106
- 3. Move only the chosen cluster's anonymized records into Source Material.
107
- 4. Do not mix different errorTypes into one brief.
108
- 5. Set the next-step guidance to `error-analysis`.
109
-
110
- ## task-group and filename
111
-
112
- For task-group, show existing-group recommendations first. Call `okstra task-list --text`, read the distinct fixed `Task group` values in `Updated at` order, and offer the 2 most recent + enter-directly. If `Status` is `error`, report `Failure stage` and `Failure reason`, then stop. If `Task count` is `0`, ask for free text. In tracker recursion, task-group must be obtained before building any child path.
113
-
114
- File path rule:
115
-
116
- ```text
117
- depth 0: .okstra/briefs/<task-group>/<ticket-id>-<file-title>.md
118
- depth 1: .okstra/briefs/<task-group>/sub/<ticket-id>-<file-title>.md
119
- depth N: .okstra/briefs/<task-group>/<sub/ repeated N>/<ticket-id>-<file-title>.md
120
- ```
121
-
122
- The frontmatter's `depth` must equal the number of `sub/` segments in the path. The validator checks this.
123
-
124
- On collision, the default is Skip. You may offer Append suffix or Overwrite. Do not silently perform a bulk overwrite in tracker multi-generation.
125
-
126
- ## Domain alignment
127
-
128
- First look at okstra's internal memory.
129
-
130
- - `<PROJECT_ROOT>/.okstra/glossary.md`
131
- - `<PROJECT_ROOT>/.okstra/decisions/`
132
- - the related task's `history/fix-cycles.jsonl`
133
-
134
- Read external domain docs only when the reporter explicitly cited them as source material. Record conflicting/ambiguous terms under `Augmentation > Domain alignment` with `terminology-mapping`, and put a `terminology:` row in `Open Questions`.
135
-
136
- When a file path or symbol is mentioned, find the actual in-repo reference with `Read`/`Grep` and record it as `evidence-link`. If it cannot be mapped, do not guess — leave a `conversion-block:` row.
137
-
138
- ## Sharpening pass
139
-
140
- Do not run a full interview. Ask only about gaps that source and codebase cannot fill.
141
-
142
- Default budget:
143
-
144
- - at most 1 question per section the source skill designates as fill-in.
145
- - at most 2 questions for terminology/fuzzy disambiguation.
146
- - at most 6 questions overall.
147
- - codebase-scan up to 8 questions.
148
-
149
- Prefer codebase-first checks over questions. Put remaining gaps in `_(none)_` or `Open Questions`.
150
-
151
- ## template writing rules
152
-
153
- The template `templates/reports/brief.template.md` is the SSOT. Follow the section order, frontmatter keys, top blockquote shape, and HTML comment guidance.
154
-
155
- Reporter input and Error feedback:
156
-
157
- - keep `## Source Material`.
158
- - keep `## Problem / Symptom`.
159
- - omit `## Scan Scope`, `## Priority Lenses`.
160
-
161
- Codebase scan:
162
-
163
- - `scope: codebase` in frontmatter.
164
- - omit `## Source Material`, `## Problem / Symptom`.
165
- - keep `## Scan Scope`, `## Priority Lenses`.
166
-
167
- Do not fabricate empty sections. When there is no value, use `_(none)_`.
168
-
169
- ## frontmatter key
170
-
171
- Every brief carries the following keys. The key set is checked by `validate-brief.py`.
172
-
173
- - `type`
174
- - `brief-id`
175
- - `parent-id`
176
- - `ticket-id`
177
- - `source-type`
178
- - `task-group`
179
- - `depth`
180
- - `created`
181
- - `generator`
182
- - `reporter-confirmations`
183
-
184
- `brief-id` must equal the filename stem. At depth 0 the `parent-id` is `self`; a descendant's `parent-id` is its direct parent's `brief-id`.
185
-
186
- ## Recommended next phase
187
-
188
- Write it into the `Recommended next phase:` of the brief body's top blockquote.
189
-
190
- - observable error, repro, stack trace, error-zip record: `error-analysis`
191
- - a requirement with ambiguity or large Open Questions: `requirements-discovery`
192
- - `scope: codebase`: `improvement-discovery`
193
- - if ambiguous: `requirements-discovery`
194
-
195
- Do not auto-start `okstra-run`.
196
-
197
- ## Reporter Confirmations
198
-
199
- Collect the rows in `Open Questions` that only the reporter can answer.
200
-
201
- - `intent-check:`
202
- - `conversion-block:`
203
-
204
- If a `[CONFIRMED <date> → RC-N]` marker already exists, exclude it from pending. Ask the user whether to answer now; if they answer, record it verbatim under `## Reporter Confirmations`. Do not delete the row — attach a marker.
205
-
206
- At most 12 questions per run. If pending exceeds 12, ask only the top 12 in `conversion-block:` → `intent-check:` order, leave the rest as `partial`, then tell the user which rows remain.
207
-
208
- Status values:
209
-
210
- - `complete`: all pending reporter-only rows are answered. The validator checks that every `intent-check:`/`conversion-block:` row has a `[CONFIRMED …]` marker.
211
- - `partial`: only some are answered. The validator checks that at least one row has a `[CONFIRMED …]` marker (if nothing was received, `skipped`).
212
- - `skipped`: the user chose to defer to a downstream phase.
213
- - `pending`: treated as a pre-handoff state; do not proceed.
214
-
215
- ## Validation
216
-
217
- After writing, run the validator before emitting the handoff message.
218
-
219
- Installed copy:
220
-
221
- ```bash
222
- ~/.okstra/lib/validators/validate-brief.sh "<PROJECT_ROOT>/.okstra/briefs" --briefs-root "<PROJECT_ROOT>/.okstra/briefs"
223
- ```
224
-
225
- repo checkout:
226
-
227
- ```bash
228
- validators/validate-brief.sh "<PROJECT_ROOT>/.okstra/briefs" --briefs-root "<PROJECT_ROOT>/.okstra/briefs"
229
- ```
230
-
231
- On failure, fix the cited brief and re-run. Fall back to a manual checklist only when the validator is absent.
232
- When a `Related Task Graph` is present, the validator also checks the table header, relation enum, direction enum, and directed/undirected mismatch.
233
-
234
- ## Completion message
235
-
236
- Single brief:
237
-
238
- ```text
239
- brief saved: <abs-path>
240
- next: /okstra-run (recommended task-type: <phase>)
241
- ```
242
-
243
- Multi-brief:
244
-
245
- ```text
246
- briefs saved (N):
247
- - <abs>/<task-group>/<brief>.md (depth 0, parent, recommended: <phase>)
248
- - <abs>/<task-group>/sub/<brief>.md (depth 1, child, recommended: <phase>)
249
- next: /okstra-run
250
- ```
251
-
252
- Before the hand-off block, once per task-group (Step 7a): if `<PROJECT_ROOT>/.okstra/briefs/<task-group>/group-context.md` is absent, ask whether to create the skeleton (`okstra group-context init --project-root <PROJECT_ROOT> --task-group <task-group>`; recommended for a new group) or skip. Never fill it from the tickets. When created, add `group context skeleton: <abs>/<task-group>/group-context.md (fill before /okstra-run)` to the block — preparation refuses the group's tasks while a `<...>` placeholder line remains. The file's trailing `## Task Memory` region is okstra's (rewritten by `report-finalize` with the group's start order and each task's latest conclusion); `init` inserts the human sections above an existing region. Brief ordinals (`<TICKET>-<n>-<slug>`) are the start order okstra reads; `Related Task Graph` edges are quoted beside it as `waits for`.
253
-
254
- ## Forbidden patterns
255
-
256
- - Summarizing or tidying Source Material before inserting it.
257
- - Guessing tracker/URL content without tool verification.
258
- - Writing unlabelled augmentation.
259
- - Leaving `intent-inference` without `intent-check:`.
260
- - Writing a decision file into external docs/ADR. okstra decisions belong only in `<PROJECT_ROOT>/.okstra/decisions/`.
261
- - Silently overwriting an entire child tree.
262
- - Auto-starting `okstra-run` right after brief generation.
@@ -1,34 +0,0 @@
1
- # okstra-chat AI Manual
2
-
3
- ## Source
4
-
5
- - Skill source: [`skills/okstra-chat/SKILL.md`](../../../skills/okstra-chat/SKILL.md)
6
- - CLI: [`src/commands/chat/chat.mts`](../../../src/commands/chat/chat.mts)
7
-
8
- ## Purpose
9
-
10
- Global rooms under the okstra home so host sessions from different providers can send and read messages. Not a project `.okstra/` artifact.
11
-
12
- ## CLI
13
-
14
- ```bash
15
- okstra chat rooms
16
- okstra chat create --room <name>
17
- okstra chat join --room <name> --name <display>
18
- okstra chat members --room <name>
19
- okstra chat send --room <name> --as <display> (--to <all|name> | --reply-to <id>) (--body <text> | --body-file <path>)
20
- okstra chat unread --room <name> --as <display>
21
- okstra chat inbox --room <name> --as <display>
22
- okstra chat log --room <name> --as <display>
23
- okstra chat ack --room <name> --as <display> --through <id>
24
- ```
25
-
26
- Display names are typed. The CLI does not generate them.
27
-
28
- Unread is the inbox after the read cursor minus messages whose `from` equals `--as`. It does not move the cursor. `inbox` and `log` keep those messages. Rows are `id @from YYYY-MM-DD HH:MM body`. A reply inserts `↑parentId` after the time. Recipient is not on the line. A body with several lines continues on rows indented by two spaces; those rows carry no id.
29
-
30
- `send --to` may equal `--as`. `--to` and `--reply-to` are exactly one. `--body` and `--body-file` are exactly one; either may hold several lines, and only an all-blank body is rejected. A reply inherits `to` from the parent. `members` is the full roster. `ack --through` rejects an id behind the current cursor. `.` and `..` are reserved names. A stale `.lock` (dead owner pid, or older than 5 s) is reclaimed by the next writer.
31
-
32
- The skill picker is `all` plus `members` minus the current display name. Skill send and reply use `--body`, not `--body-file`. Before joining an existing room the skill runs `members`; if the typed display name is already listed, it asks whether this session is already in the room under that name (a re-entry after context loss) and, if so, continues with `--as` without joining. After showing unread rows, the skill runs `ack --through` with the id of the last row that starts with an id, unless the output is `no unread`. The Step 3 menu is send, unread, inbox, log, reply, done. Reply takes a free-input id and body; there is no recipient picker and no `okstra chat reply` subcommand.
33
-
34
- Read the fixed text rows. Do not parse JSON.