okstra 0.34.0 → 0.36.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.
- package/README.kr.md +26 -16
- package/README.md +26 -16
- package/docs/kr/architecture.md +59 -45
- package/docs/kr/cli.md +61 -18
- package/docs/pr-template-usage.md +65 -0
- package/docs/project-structure-overview.md +358 -354
- package/docs/superpowers/plans/2026-05-12-ticket-id-in-reports.md +1 -1
- package/docs/superpowers/plans/2026-05-14-convergence-queue-pruning.md +1 -1
- package/docs/superpowers/plans/2026-05-17-dual-format-final-report.md +1 -1
- package/docs/superpowers/plans/2026-05-20-final-report-language.md +1501 -0
- package/docs/superpowers/plans/2026-05-20-implementation-planning-multi-stage.md +1267 -0
- package/docs/superpowers/plans/2026-05-20-okstra-run-prompt-sot-b1.md +1007 -0
- package/docs/superpowers/plans/2026-05-20-wizard-messages-json-sot.md +720 -0
- package/docs/superpowers/plans/2026-05-20-wizard-prompt-json-sot-a1.md +681 -0
- package/docs/superpowers/plans/2026-05-21-improvement-discovery-task-type.md +1691 -0
- package/docs/superpowers/specs/2026-05-20-final-report-language-design.md +383 -0
- package/docs/superpowers/specs/2026-05-20-implementation-planning-multi-stage-design.md +320 -0
- package/docs/superpowers/specs/2026-05-20-okstra-run-prompt-sot-design.md +299 -0
- package/docs/superpowers/specs/2026-05-21-improvement-discovery-task-type-design.md +335 -0
- package/docs/task-process/README.md +74 -0
- package/docs/task-process/common-flow.md +166 -0
- package/docs/task-process/error-analysis.md +101 -0
- package/docs/task-process/final-verification.md +167 -0
- package/docs/task-process/implementation-planning.md +128 -0
- package/docs/task-process/implementation.md +149 -0
- package/docs/task-process/release-handoff.md +206 -0
- package/docs/task-process/requirements-discovery.md +115 -0
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/SKILL.md +29 -13
- package/runtime/agents/workers/claude-worker.md +26 -0
- package/runtime/agents/workers/codex-worker.md +27 -1
- package/runtime/agents/workers/gemini-worker.md +27 -1
- package/runtime/agents/workers/report-writer-worker.md +8 -1
- package/runtime/bin/okstra-central.sh +6 -6
- package/runtime/bin/okstra-codex-exec.sh +49 -28
- package/runtime/bin/okstra-gemini-exec.sh +39 -21
- package/runtime/bin/okstra-render-final-report.py +13 -2
- package/runtime/bin/okstra-wrapper-status.py +155 -0
- package/runtime/bin/okstra.sh +2 -2
- package/runtime/prompts/profiles/_common-contract.md +11 -6
- package/runtime/prompts/profiles/error-analysis.md +3 -7
- package/runtime/prompts/profiles/implementation-planning.md +22 -21
- package/runtime/prompts/profiles/implementation.md +28 -11
- package/runtime/prompts/profiles/improvement-discovery.md +42 -0
- package/runtime/prompts/profiles/kr/_common-contract.md +92 -0
- package/runtime/prompts/profiles/kr/error-analysis.md +36 -0
- package/runtime/prompts/profiles/kr/final-verification.md +48 -0
- package/runtime/prompts/profiles/kr/implementation-planning.md +90 -0
- package/runtime/prompts/profiles/kr/implementation.md +144 -0
- package/runtime/prompts/profiles/kr/improvement-discovery.md +42 -0
- package/runtime/prompts/profiles/kr/release-handoff.md +104 -0
- package/runtime/prompts/profiles/kr/requirements-discovery.md +42 -0
- package/runtime/prompts/profiles/release-handoff.md +1 -1
- package/runtime/prompts/profiles/requirements-discovery.md +8 -12
- package/runtime/prompts/wizard/prompts.ko.json +230 -0
- package/runtime/python/lib/okstra/cli.sh +2 -49
- package/runtime/python/lib/okstra/globals.sh +21 -21
- package/runtime/python/lib/okstra/interactive.sh +7 -7
- package/runtime/python/okstra_ctl/clarification_items.py +3 -9
- package/runtime/python/okstra_ctl/consumers.py +53 -0
- package/runtime/python/okstra_ctl/final_report_schema.py +0 -7
- package/runtime/python/okstra_ctl/i18n.py +73 -0
- package/runtime/python/okstra_ctl/improvement_lenses.py +44 -0
- package/runtime/python/okstra_ctl/index.py +1 -1
- package/runtime/python/okstra_ctl/paths.py +23 -20
- package/runtime/python/okstra_ctl/render.py +147 -202
- package/runtime/python/okstra_ctl/render_final_report.py +53 -10
- package/runtime/python/okstra_ctl/run.py +292 -107
- package/runtime/python/okstra_ctl/run_context.py +22 -0
- package/runtime/python/okstra_ctl/seeding.py +186 -0
- package/runtime/python/okstra_ctl/wizard.py +348 -127
- package/runtime/python/okstra_ctl/workflow.py +21 -2
- package/runtime/python/okstra_ctl/worktree.py +54 -1
- package/runtime/python/okstra_project/resolver.py +4 -3
- package/runtime/python/okstra_token_usage/report.py +2 -2
- package/runtime/schemas/final-report-v1.0.schema.json +22 -16
- package/runtime/skills/okstra-brief/SKILL.md +124 -31
- package/runtime/skills/okstra-convergence/SKILL.md +2 -3
- package/runtime/skills/okstra-report-writer/SKILL.md +35 -15
- package/runtime/skills/okstra-run/SKILL.md +5 -4
- package/runtime/skills/okstra-schedule/SKILL.md +4 -4
- package/runtime/skills/okstra-setup/SKILL.md +27 -0
- package/runtime/skills/okstra-team-contract/SKILL.md +1 -1
- package/runtime/templates/okstra.CLAUDE.md +104 -0
- package/runtime/templates/reports/final-report.template.md +93 -98
- package/runtime/templates/reports/i18n/en.json +135 -0
- package/runtime/templates/reports/i18n/ko.json +135 -0
- package/runtime/templates/reports/implementation-planning-input.template.md +18 -0
- package/runtime/templates/reports/improvement-discovery-input.template.md +78 -0
- package/runtime/templates/reports/task-brief.template.md +2 -2
- package/runtime/validators/lib/fixtures.sh +30 -0
- package/runtime/validators/lib/runners.sh +1 -1
- package/runtime/validators/validate-implementation-plan-stages.py +211 -0
- package/runtime/validators/validate-run.py +121 -26
- package/runtime/validators/validate-workflow.sh +2 -2
- package/runtime/validators/validate_improvement_report.py +275 -0
- package/src/config.mjs +18 -0
- package/src/install.mjs +41 -14
- package/src/setup.mjs +133 -1
- package/src/uninstall.mjs +21 -1
|
@@ -20,6 +20,7 @@ PHASE_SEQUENCE = [
|
|
|
20
20
|
|
|
21
21
|
DEFAULT_NEXT_PHASE = {
|
|
22
22
|
"requirements-discovery": "pending-routing-decision",
|
|
23
|
+
"improvement-discovery": "pending-routing-decision",
|
|
23
24
|
"error-analysis": "implementation-planning",
|
|
24
25
|
"implementation-planning": "implementation",
|
|
25
26
|
"implementation": "final-verification",
|
|
@@ -47,6 +48,24 @@ PHASE_RULES: dict[str, dict[str, str]] = {
|
|
|
47
48
|
" - starting `error-analysis`, `implementation-planning`, or `implementation` inside this run (each must be a separate run, and `implementation` additionally requires an approved `implementation-planning` deliverable)"
|
|
48
49
|
),
|
|
49
50
|
},
|
|
51
|
+
"improvement-discovery": {
|
|
52
|
+
"allowed": (
|
|
53
|
+
" - improvement candidate discovery within the lens whitelist defined in `scripts/okstra_ctl/improvement_lenses.py`\n"
|
|
54
|
+
" - top-N ranking (default 8, brief `candidate-cap` overrides within 1..12)\n"
|
|
55
|
+
" - per-candidate columns Lens / Scope / Severity / Effort / Consensus / Source workers / Recommended next-phase / Evidence (path:line)\n"
|
|
56
|
+
" - Phase 1.5 reflect-back grilling log at `runs/improvement-discovery/<seq>/state/phase-1.5-grilling.md`\n"
|
|
57
|
+
" - Phase 5.5 consensus classification (full / partial / contested / worker-unique)"
|
|
58
|
+
),
|
|
59
|
+
"forbidden": (
|
|
60
|
+
" - source code edits of any kind\n"
|
|
61
|
+
" - implementation planning, root-cause analysis, builds, migrations, or deployments\n"
|
|
62
|
+
" - starting `implementation-planning`, `implementation`, `error-analysis`, or any other lifecycle phase inside this run\n"
|
|
63
|
+
" - generating candidates outside the lens whitelist (Lens enum violation rejects the report)\n"
|
|
64
|
+
" - exceeding the candidate cap (absolute cap 12)\n"
|
|
65
|
+
" - free external data fetch beyond the brief's Source Material or Phase 1.5 resolved scope\n"
|
|
66
|
+
" - interpreting user phrases like `다음 단계 진행해` as authorisation to enter another phase"
|
|
67
|
+
),
|
|
68
|
+
},
|
|
50
69
|
"error-analysis": {
|
|
51
70
|
"allowed": (
|
|
52
71
|
" - symptom and trigger evidence\n"
|
|
@@ -69,7 +88,7 @@ PHASE_RULES: dict[str, dict[str, str]] = {
|
|
|
69
88
|
" - bite-sized stepwise execution order for the recommended option (each step ~2-5 min, exact file paths and commands, TDD ordering when applicable, no placeholders)\n"
|
|
70
89
|
" - dependency / migration risk assessment, validation checklist (pre / mid / post with exact commands), rollback strategy with revert path and trigger signal\n"
|
|
71
90
|
" - every unresolved ambiguity registered as a `Blocks=approval` row in the `## 5. Clarification Items` table (do NOT create a separate `Open Questions` block under `4.5.x` — the unified table is the single home)\n"
|
|
72
|
-
" -
|
|
91
|
+
" - YAML frontmatter line `approved: false` awaiting human flip to `true`\n"
|
|
73
92
|
" - self-review confirmation (spec coverage, placeholder scan, internal consistency, ambiguity, scope)"
|
|
74
93
|
),
|
|
75
94
|
"forbidden": (
|
|
@@ -95,7 +114,7 @@ PHASE_RULES: dict[str, dict[str, str]] = {
|
|
|
95
114
|
" - routing recommendation for `final-verification` (ready / needs new error-analysis or planning loop)"
|
|
96
115
|
),
|
|
97
116
|
"forbidden": (
|
|
98
|
-
" - any Edit/Write or state-mutating Bash before the pre-implementation gate passes (gate requires --approved-plan pointing to a final-report.md
|
|
117
|
+
" - any Edit/Write or state-mutating Bash before the pre-implementation gate passes (gate requires --approved-plan pointing to a final-report.md whose frontmatter has `approved: true`)\n"
|
|
99
118
|
" - `git push` of any kind, `npm publish` / `cargo publish` / `pip publish`, `gh release`, `docker push`\n"
|
|
100
119
|
" - real database migrations, schema changes against shared environments, or writes to non-local datastores\n"
|
|
101
120
|
" - production credentials, deploy commands, infra mutation (`terraform apply`, `kubectl apply` against non-local cluster, etc.)\n"
|
|
@@ -43,7 +43,14 @@ from typing import Optional
|
|
|
43
43
|
|
|
44
44
|
from .ids import _safe_fs_segment
|
|
45
45
|
from . import worktree_registry
|
|
46
|
-
from .seeding import
|
|
46
|
+
from .seeding import (
|
|
47
|
+
AgentsMdLinkError,
|
|
48
|
+
ClaudeMdLinkError,
|
|
49
|
+
SettingsLinkError,
|
|
50
|
+
ensure_project_agents_md,
|
|
51
|
+
ensure_project_claude_md,
|
|
52
|
+
ensure_project_settings_symlink,
|
|
53
|
+
)
|
|
47
54
|
|
|
48
55
|
|
|
49
56
|
# Project-root directories that hold okstra task state, ignored by git, or
|
|
@@ -390,6 +397,48 @@ def _seed_worktree_settings_symlink(worktree_path: Path) -> None:
|
|
|
390
397
|
)
|
|
391
398
|
|
|
392
399
|
|
|
400
|
+
def _seed_worktree_claude_md(worktree_path: Path) -> None:
|
|
401
|
+
"""Seed `.project-docs/okstra/CLAUDE.md` symlink + `<worktree>/CLAUDE.md`
|
|
402
|
+
import block in the worker worktree so dispatched Claude sessions auto-load
|
|
403
|
+
okstra's runtime guidance. Mirrors `_seed_worktree_settings_symlink` —
|
|
404
|
+
needed because the worktree's `CLAUDE.md` comes from the git checkout (no
|
|
405
|
+
marker block unless committed) and `.project-docs/` is only dir-symlinked,
|
|
406
|
+
not its contents.
|
|
407
|
+
"""
|
|
408
|
+
try:
|
|
409
|
+
link = ensure_project_claude_md(project_root=worktree_path)
|
|
410
|
+
except ClaudeMdLinkError as exc:
|
|
411
|
+
print(
|
|
412
|
+
f"okstra-claude-md: failed to seed worker worktree CLAUDE.md at "
|
|
413
|
+
f"{worktree_path} — dispatched Claude sessions will not auto-load "
|
|
414
|
+
f"okstra guidance. ({exc})",
|
|
415
|
+
file=__import__("sys").stderr,
|
|
416
|
+
)
|
|
417
|
+
return
|
|
418
|
+
if link is None:
|
|
419
|
+
print(
|
|
420
|
+
"okstra-claude-md: ~/.okstra/templates/okstra.CLAUDE.md missing — "
|
|
421
|
+
"re-run 'npx okstra@latest install' to provision the symlink target.",
|
|
422
|
+
file=__import__("sys").stderr,
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def _seed_worktree_agents_md(worktree_path: Path) -> None:
|
|
427
|
+
"""Seed `<worktree>/AGENTS.md` symlink so codex / aider sessions dispatched
|
|
428
|
+
into this worktree auto-load okstra's guidance. Only acts when AGENTS.md
|
|
429
|
+
is absent — never overwrites user content.
|
|
430
|
+
"""
|
|
431
|
+
try:
|
|
432
|
+
ensure_project_agents_md(project_root=worktree_path)
|
|
433
|
+
except AgentsMdLinkError as exc:
|
|
434
|
+
print(
|
|
435
|
+
f"okstra-agents-md: failed to seed worker worktree AGENTS.md at "
|
|
436
|
+
f"{worktree_path} — dispatched codex / aider sessions will not "
|
|
437
|
+
f"auto-load okstra guidance. ({exc})",
|
|
438
|
+
file=__import__("sys").stderr,
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
|
|
393
442
|
def _copy_snapshot_files(source_root: Path, worktree_path: Path) -> list[str]:
|
|
394
443
|
"""Copy fixture files from MAIN → task worktree as read-only snapshots
|
|
395
444
|
(FU-V3).
|
|
@@ -515,6 +564,8 @@ def provision_task_worktree(
|
|
|
515
564
|
if existing is not None and existing.status == "active":
|
|
516
565
|
worktree_registry.touch_phase(safe_project, safe_group, safe_task, task_type)
|
|
517
566
|
_seed_worktree_settings_symlink(Path(existing.worktree_path))
|
|
567
|
+
_seed_worktree_claude_md(Path(existing.worktree_path))
|
|
568
|
+
_seed_worktree_agents_md(Path(existing.worktree_path))
|
|
518
569
|
return WorktreeProvision(
|
|
519
570
|
status="reused",
|
|
520
571
|
path=existing.worktree_path,
|
|
@@ -617,6 +668,8 @@ def provision_task_worktree(
|
|
|
617
668
|
raise
|
|
618
669
|
|
|
619
670
|
_seed_worktree_settings_symlink(worktree_path)
|
|
671
|
+
_seed_worktree_claude_md(worktree_path)
|
|
672
|
+
_seed_worktree_agents_md(worktree_path)
|
|
620
673
|
|
|
621
674
|
base_label = (
|
|
622
675
|
f"{base_origin} @ {resolved_base_ref[:12]}"
|
|
@@ -118,9 +118,10 @@ def upsert_project_json(project_root: Path, project_id: str, *,
|
|
|
118
118
|
f"under a different id. "
|
|
119
119
|
f"(projectId 불일치: 한 PROJECT_ROOT 에는 하나의 projectId 만 허용됩니다.)")
|
|
120
120
|
# Preserve any user-managed fields (e.g. `worktreeSyncDirs`,
|
|
121
|
-
# `mcpServers`) so
|
|
122
|
-
#
|
|
123
|
-
#
|
|
121
|
+
# `qaCommands`, `prTemplatePath`, `reportLanguage`, `mcpServers`) so
|
|
122
|
+
# manual edits to project.json are not wiped by the per-run
|
|
123
|
+
# self-registration upsert. Only the canonical identity/timestamp
|
|
124
|
+
# fields below are owned by this function.
|
|
124
125
|
result = dict(data) if isinstance(data, dict) else {}
|
|
125
126
|
result["projectId"] = project_id
|
|
126
127
|
result["projectRoot"] = abs_root
|
|
@@ -15,7 +15,7 @@ if str(_HERE) not in sys.path:
|
|
|
15
15
|
sys.path.insert(0, str(_HERE))
|
|
16
16
|
|
|
17
17
|
from okstra_ctl.render_final_report import ( # noqa: E402
|
|
18
|
-
|
|
18
|
+
FinalReportRenderError,
|
|
19
19
|
render_to_file,
|
|
20
20
|
)
|
|
21
21
|
|
|
@@ -171,6 +171,6 @@ def populate_and_render(
|
|
|
171
171
|
|
|
172
172
|
try:
|
|
173
173
|
bytes_written = render_to_file(data_path, output_path)
|
|
174
|
-
except
|
|
174
|
+
except FinalReportRenderError as exc:
|
|
175
175
|
raise SubstituteRefusedError(f"render after substitute failed: {exc}") from exc
|
|
176
176
|
return changes, bytes_written
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"type": "object",
|
|
7
7
|
"required": [
|
|
8
8
|
"schemaVersion",
|
|
9
|
+
"meta",
|
|
9
10
|
"frontmatter",
|
|
10
11
|
"header",
|
|
11
12
|
"verdictCard",
|
|
@@ -27,6 +28,19 @@
|
|
|
27
28
|
"description": "Schema version. Renderer refuses to process unknown versions."
|
|
28
29
|
},
|
|
29
30
|
|
|
31
|
+
"meta": {
|
|
32
|
+
"type": "object",
|
|
33
|
+
"additionalProperties": true,
|
|
34
|
+
"required": ["reportLanguage"],
|
|
35
|
+
"properties": {
|
|
36
|
+
"reportLanguage": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"enum": ["en", "ko"],
|
|
39
|
+
"description": "Resolved language used for prose + i18n dictionary. 'auto' must be resolved to 'en' or 'ko' by the lead before the report-writer worker writes data.json."
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
|
|
30
44
|
"frontmatter": {
|
|
31
45
|
"type": "object",
|
|
32
46
|
"required": [
|
|
@@ -40,7 +54,8 @@
|
|
|
40
54
|
"taskGroup",
|
|
41
55
|
"projectId",
|
|
42
56
|
"taskType",
|
|
43
|
-
"workerId"
|
|
57
|
+
"workerId",
|
|
58
|
+
"approved"
|
|
44
59
|
],
|
|
45
60
|
"additionalProperties": false,
|
|
46
61
|
"properties": {
|
|
@@ -64,7 +79,11 @@
|
|
|
64
79
|
"taskGroup": { "type": "string", "minLength": 1 },
|
|
65
80
|
"projectId": { "type": "string", "minLength": 1 },
|
|
66
81
|
"taskType": { "$ref": "#/$defs/TaskType" },
|
|
67
|
-
"workerId": { "const": "report-writer" }
|
|
82
|
+
"workerId": { "const": "report-writer" },
|
|
83
|
+
"approved": {
|
|
84
|
+
"type": "boolean",
|
|
85
|
+
"description": "사용자 승인 플래그. report-writer 는 항상 false 로 발행하고, 사용자가 `--approve` 또는 직접 편집으로 true 로 토글합니다. `implementation` task-type 의 prepare 단계가 `--approved-plan` 으로 지정된 보고서의 이 필드를 읽어 진입 여부를 결정합니다. 다른 task-type 에서는 의미 없이 false 로 유지됩니다."
|
|
86
|
+
}
|
|
68
87
|
}
|
|
69
88
|
},
|
|
70
89
|
|
|
@@ -94,19 +113,6 @@
|
|
|
94
113
|
}
|
|
95
114
|
},
|
|
96
115
|
|
|
97
|
-
"approvalBlock": {
|
|
98
|
-
"type": "object",
|
|
99
|
-
"description": "RENDER_IF taskType == implementation-planning. Renderer emits the User Approval Request section.",
|
|
100
|
-
"required": ["approved"],
|
|
101
|
-
"additionalProperties": false,
|
|
102
|
-
"properties": {
|
|
103
|
-
"approved": {
|
|
104
|
-
"type": "boolean",
|
|
105
|
-
"description": "When true, renders `- [x] Approved`; when false, `- [ ] Approved`. Plan Body Verification gate decides which."
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
},
|
|
109
|
-
|
|
110
116
|
"clarificationCarryIn": {
|
|
111
117
|
"type": "object",
|
|
112
118
|
"description": "RENDER_IF non-empty. Carry-in clarifications from the previous run.",
|
|
@@ -593,7 +599,7 @@
|
|
|
593
599
|
"required": ["header"]
|
|
594
600
|
},
|
|
595
601
|
"then": {
|
|
596
|
-
"required": ["implementationPlanning"
|
|
602
|
+
"required": ["implementationPlanning"]
|
|
597
603
|
}
|
|
598
604
|
},
|
|
599
605
|
{
|
|
@@ -41,12 +41,19 @@ cross-verification and would conflict with anything decided here.
|
|
|
41
41
|
## Intended chain
|
|
42
42
|
|
|
43
43
|
```
|
|
44
|
-
okstra-brief
|
|
44
|
+
okstra-brief (reporter-input variant)
|
|
45
45
|
→ okstra-run (requirements-discovery | error-analysis)
|
|
46
46
|
→ okstra-run (implementation-planning)
|
|
47
47
|
→ okstra-run (implementation)
|
|
48
48
|
→ okstra-run (final-verification)
|
|
49
49
|
→ okstra-run (release-handoff)
|
|
50
|
+
|
|
51
|
+
okstra-brief (codebase-scan variant)
|
|
52
|
+
→ okstra-run (improvement-discovery)
|
|
53
|
+
→ okstra-run (implementation-planning)
|
|
54
|
+
→ okstra-run (implementation)
|
|
55
|
+
→ okstra-run (final-verification)
|
|
56
|
+
→ okstra-run (release-handoff)
|
|
50
57
|
```
|
|
51
58
|
|
|
52
59
|
## When to use
|
|
@@ -70,8 +77,7 @@ okstra-brief
|
|
|
70
77
|
|
|
71
78
|
**All okstra-generated artifacts live under `<PROJECT_ROOT>/.project-docs/okstra/`.**
|
|
72
79
|
This includes briefs, run manifests, reports, worker results, status,
|
|
73
|
-
sessions, and any other run output.
|
|
74
|
-
or other project paths.
|
|
80
|
+
sessions, and any other run output.
|
|
75
81
|
|
|
76
82
|
All writes by this skill stay inside `.project-docs/okstra/`. When domain
|
|
77
83
|
alignment (Step 3b / Step 4.5) yields a glossary change that the user
|
|
@@ -81,12 +87,11 @@ approves inline, the change is written to:
|
|
|
81
87
|
glossary. Created if absent; appended to a `## Glossary` section
|
|
82
88
|
otherwise.
|
|
83
89
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
writes
|
|
87
|
-
also live inside okstra's subtree at
|
|
88
|
-
`<PROJECT_ROOT>/.project-docs/okstra/decisions/<NNNN>-<slug>.md
|
|
89
|
-
at external `docs/adr/`.
|
|
90
|
+
Paths outside `<PROJECT_ROOT>/.project-docs/okstra/**` are not okstra
|
|
91
|
+
memory. This skill reads them only when the reporter explicitly cited them
|
|
92
|
+
as source material, and never writes them. Decision files (when raised by
|
|
93
|
+
`implementation-planning`) also live inside okstra's subtree at
|
|
94
|
+
`<PROJECT_ROOT>/.project-docs/okstra/decisions/<NNNN>-<slug>.md`.
|
|
90
95
|
|
|
91
96
|
## Authority files
|
|
92
97
|
|
|
@@ -128,6 +133,19 @@ Parse the JSON from stdout:
|
|
|
128
133
|
|
|
129
134
|
## Step 1: Choose input source
|
|
130
135
|
|
|
136
|
+
### 1.0. brief variant
|
|
137
|
+
|
|
138
|
+
`AskUserQuestion` (single-select):
|
|
139
|
+
|
|
140
|
+
- **Label**: `"Brief variant?"`
|
|
141
|
+
- **Options**:
|
|
142
|
+
1. `Reporter input` — reporter 발화 / 티켓 / 링크 / 자유 텍스트를 verbatim 으로 흡수. 기존 4-source 흐름.
|
|
143
|
+
2. `Codebase scan` — 코드베이스 범위 + lens 우선순위만 받아 `improvement-discovery` phase 의 입력을 생성.
|
|
144
|
+
|
|
145
|
+
### 1.A. Reporter input (variant 1)
|
|
146
|
+
|
|
147
|
+
If the user picked `Reporter input`, proceed to Step 1.A's sub-flow below — this is the existing 4-source flow. Choose ONE of:
|
|
148
|
+
|
|
131
149
|
`AskUserQuestion` (tool constraint: max 4 options):
|
|
132
150
|
|
|
133
151
|
- **Label**: "Source of this brief?"
|
|
@@ -291,6 +309,34 @@ Two sub-modes combined under one option.
|
|
|
291
309
|
When both are used, record them as two separate sub-sources under Source
|
|
292
310
|
Material.
|
|
293
311
|
|
|
312
|
+
### 1.B. Codebase scan (variant 2)
|
|
313
|
+
|
|
314
|
+
If the user picked `Codebase scan`, gather the codebase-scan-specific inputs:
|
|
315
|
+
|
|
316
|
+
1. `AskUserQuestion` (free text):
|
|
317
|
+
`"Scan scope — comma-separated paths inside the project (e.g. src/foo/, src/bar/baz.py)"` → `scan_scope` (CSV).
|
|
318
|
+
2. `AskUserQuestion` (multi-select, options = the 8 lens enum values from `scripts/okstra_ctl/improvement_lenses.py`'s `LENSES`):
|
|
319
|
+
`"Priority lenses (pick 1–4)"` → `priority_lenses` (1..4 values from the enum).
|
|
320
|
+
Enum values: `performance`, `security`, `readability`, `architecture`, `test-coverage`, `dx`, `observability`, `accessibility`.
|
|
321
|
+
3. `AskUserQuestion` (free text):
|
|
322
|
+
`"Out-of-scope paths (optional, comma-separated)"` → `out_of_scope` (CSV, empty allowed).
|
|
323
|
+
4. `AskUserQuestion` (free text):
|
|
324
|
+
`"Candidate cap (1–12, default 8)"` → `candidate_cap` (integer; empty → 8).
|
|
325
|
+
5. `AskUserQuestion` (free text):
|
|
326
|
+
`"Context — why is this scope being scanned now? One short paragraph."` → `context`.
|
|
327
|
+
6. `AskUserQuestion` (free text):
|
|
328
|
+
`"Desired outcome — what kinds of improvements do you want surfaced? Anti-goals?"` → `desired_outcome`.
|
|
329
|
+
7. `AskUserQuestion` (free text):
|
|
330
|
+
`"Constraints — untouchable areas, deadlines, compatibility (optional)"` → `constraints`.
|
|
331
|
+
|
|
332
|
+
Validation (before Step 4 sharpening):
|
|
333
|
+
|
|
334
|
+
- `scan_scope` 의 각 path 가 `<PROJECT_ROOT>` 안에 실제 존재하는지 `ls` 로 확인 — 없으면 한 질문으로 정정.
|
|
335
|
+
- `priority_lenses` 가 `scripts/okstra_ctl/improvement_lenses.py` 의 `LENSES` 부분집합 (1–4) 인지 확인 — 위반 시 enum 표시 + 재선택.
|
|
336
|
+
- `candidate_cap` 이 1–12 정수인지 확인.
|
|
337
|
+
|
|
338
|
+
Once validation passes, jump to Step 2 (task key).
|
|
339
|
+
|
|
294
340
|
## Step 2: Identify task key & filename
|
|
295
341
|
|
|
296
342
|
### 2a. Task group
|
|
@@ -344,7 +390,7 @@ to Source Material body, not to the filename):
|
|
|
344
390
|
3. Lowercase (Hangul untouched) — **filename normalization only**.
|
|
345
391
|
The Source Material section MUST preserve the original title's case
|
|
346
392
|
byte-for-byte; lowercase applies strictly to the on-disk filename.
|
|
347
|
-
4. Cut to 60 chars at a word boundary (
|
|
393
|
+
4. Cut to 60 chars at a word boundary (cut at 60 if no boundary)
|
|
348
394
|
5. Trim leading/trailing `-`
|
|
349
395
|
- Example: Linear `LIN-1234 "Fix flaky login retry on 5xx"` →
|
|
350
396
|
`LIN-1234-fix-flaky-login-retry-on-5xx.md`
|
|
@@ -385,12 +431,9 @@ never error:
|
|
|
385
431
|
1. **okstra-internal (authoritative)** — always check first:
|
|
386
432
|
- `<PROJECT_ROOT>/.project-docs/okstra/glossary.md` if present
|
|
387
433
|
- `<PROJECT_ROOT>/.project-docs/okstra/decisions/` titles if present
|
|
388
|
-
2. **
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
- `<PROJECT_ROOT>/docs/adr/` titles
|
|
392
|
-
- `<PROJECT_ROOT>/.scratch/CONTEXT.md` (output of external skills like
|
|
393
|
-
grill-with-docs, if any)
|
|
434
|
+
2. **Explicit source material only** — if the reporter cited a path outside
|
|
435
|
+
okstra's subtree, read it as source evidence only; do not treat it as
|
|
436
|
+
okstra memory.
|
|
394
437
|
|
|
395
438
|
If none of these exist, skip 3b/3c silently.
|
|
396
439
|
|
|
@@ -398,7 +441,7 @@ If none of these exist, skip 3b/3c silently.
|
|
|
398
441
|
|
|
399
442
|
For each domain-significant noun in Source Material, classify:
|
|
400
443
|
|
|
401
|
-
- **conflict** — the source uses a term that
|
|
444
|
+
- **conflict** — the source uses a term that okstra memory defines
|
|
402
445
|
differently. Example: source says "cancellation" meaning refund, glossary
|
|
403
446
|
says "cancellation" means order-state transition.
|
|
404
447
|
- **fuzzy / overloaded** — a term that has no canonical definition yet but
|
|
@@ -415,7 +458,7 @@ on a project-internal concrete object whenever possible.
|
|
|
415
458
|
(so the next phase can resolve it during `requirements-discovery`).
|
|
416
459
|
- One line under `Augmentation > Domain alignment` with the
|
|
417
460
|
`terminology-mapping` label (Step 4 label rules), recording the
|
|
418
|
-
observation (what the source said vs. what
|
|
461
|
+
observation (what the source said vs. what okstra memory says).
|
|
419
462
|
- **File paths and symbols are resolved to absolute, in-repo references.**
|
|
420
463
|
When the source mentions a module / class / endpoint / config key, run
|
|
421
464
|
`Read` / `Grep` to locate the concrete file path (relative to
|
|
@@ -434,8 +477,7 @@ on a project-internal concrete object whenever possible.
|
|
|
434
477
|
knows to query the reporter directly rather than infer.
|
|
435
478
|
- See Step 4.5 for the approval-gated path to actually write the
|
|
436
479
|
okstra-internal glossary at
|
|
437
|
-
`<PROJECT_ROOT>/.project-docs/okstra/glossary.md`.
|
|
438
|
-
`CONTEXT.md` / `CONTEXT-MAP.md` / `docs/adr/` are never edited.
|
|
480
|
+
`<PROJECT_ROOT>/.project-docs/okstra/glossary.md`.
|
|
439
481
|
|
|
440
482
|
Skip 3b/3c for purely external request material with no overlap to the
|
|
441
483
|
project's domain.
|
|
@@ -473,7 +515,7 @@ The following rules absorb the useful parts of `grill-me` /
|
|
|
473
515
|
draft, then ask the next.
|
|
474
516
|
4. **Bounded budget** — at most **1** sharpening question per empty
|
|
475
517
|
required section, plus **at most 2** disambiguation questions arising
|
|
476
|
-
from Step 3b (terminology conflicts / fuzzy terms).
|
|
518
|
+
from Step 3b (terminology conflicts / fuzzy terms). Cap: **6
|
|
477
519
|
questions total** across the whole brief. Anything beyond the cap is
|
|
478
520
|
recorded under `Open Questions` instead of asked.
|
|
479
521
|
5. **Scenario probe (optional)** — when `Desired Outcome` is empty or one
|
|
@@ -491,6 +533,23 @@ or to a `> augmented: <label>` blockquote inside the required section, so
|
|
|
491
533
|
it is clear that the content is the skill's / user's added interpretation
|
|
492
534
|
rather than the original source.
|
|
493
535
|
|
|
536
|
+
### codebase-scan variant 전용 강화 규칙 (improvement-discovery)
|
|
537
|
+
|
|
538
|
+
이 5개 규칙은 `scope: codebase` brief 에 한해 적용. budget 은 기본 6 → **8** 로 확대.
|
|
539
|
+
|
|
540
|
+
1. **scan-scope 경로 존재 검증.** 각 path 를 `ls` / `Read` 로 확인. 없으면 한 질문으로 정정 (path 의 가장 가까운 후보를 `Recommended:` 로 제시).
|
|
541
|
+
2. **모호 path narrowing.** `"백엔드"`, `"결제 모듈"` 같은 추상 path 는 구체 디렉토리 1개 이상으로 narrowing. codebase-first 추측 후 한 질문으로 확정.
|
|
542
|
+
3. **priority-lenses 화이트리스트 검증.** `scripts/okstra_ctl/improvement_lenses.py` 의 `LENSES` 부분집합인지 확인. out-of-enum 이면 enum 내 가장 가까운 값을 `Recommended:` 로 제시.
|
|
543
|
+
4. **out-of-scope 일관성.** `out-of-scope` 의 각 path 가 `scan-scope` 의 부분집합인지 확인. 무관한 path 면 한 질문으로 제거 또는 scan-scope 에 흡수.
|
|
544
|
+
5. **lens 우선순위 근거 1줄.** 각 priority lens 가 *왜* 이 scope 에서 우선인지 brief 본문에 한 줄 없으면, codebase 1차 훑은 결과를 `Recommended:` 로 제시 후 한 질문.
|
|
545
|
+
|
|
546
|
+
stop conditions (codebase-scan 한정 추가):
|
|
547
|
+
|
|
548
|
+
- `scan-scope` 의 모든 path 가 codebase 에 존재
|
|
549
|
+
- `priority-lenses` 가 valid enum 부분집합 (1–4개)
|
|
550
|
+
|
|
551
|
+
위 두 조건이 모두 만족되면 budget 이 남아 있어도 sharpening 종료 가능.
|
|
552
|
+
|
|
494
553
|
### Augmentation labels (REQUIRED — no unlabelled augmentation)
|
|
495
554
|
|
|
496
555
|
Every augmentation — both inline `> augmented: …` blockquotes and
|
|
@@ -501,7 +560,7 @@ labels. Unlabelled augmentation is rejected as half-formed translation.
|
|
|
501
560
|
|---|---|---|
|
|
502
561
|
| `evidence-link` | Cross-reference / file path / symbol resolved from the source against the actual codebase. Pure fact, verified by `Read` / `Grep`. | Trust without verification. |
|
|
503
562
|
| `format-conversion` | Format-only transform (Jira ADF → Markdown, HTML → Markdown, etc.). Semantics unchanged. | Trust without verification. |
|
|
504
|
-
| `terminology-mapping` | Reporter's word mapped to
|
|
563
|
+
| `terminology-mapping` | Reporter's word mapped to an okstra-canonical term from Step 3b. | Verify against `.project-docs/okstra/glossary.md`; if mismatch, treat as a clarification candidate. |
|
|
505
564
|
| `intent-inference` | Reporter did NOT literally state this — the skill inferred meaning from context (e.g. classifying "가끔 안 됨" as "intermittent failure on a specific path"). Qualitative only — **never** invent quantitative thresholds (numbers, latencies, percentages, counts). | **Verify with the reporter before acting.** Auto-mirrored into `Open Questions`. |
|
|
506
565
|
|
|
507
566
|
**Inline form** — `> augmented: intent-inference — <one line>`.
|
|
@@ -559,8 +618,7 @@ For each `conflict` / `fuzzy` term collected in Step 3b that *was not*
|
|
|
559
618
|
resolved by a budgeted Step 4 question, draft a glossary proposal and
|
|
560
619
|
offer it to the user. This step writes to the **okstra-internal
|
|
561
620
|
glossary** at `<PROJECT_ROOT>/.project-docs/okstra/glossary.md` only —
|
|
562
|
-
|
|
563
|
-
by this skill.
|
|
621
|
+
the skill does not write outside okstra's subtree.
|
|
564
622
|
|
|
565
623
|
> **Decision scope**: this skill does NOT evaluate decision candidates
|
|
566
624
|
> and does NOT draft decision files. Decision creation requires context
|
|
@@ -569,8 +627,7 @@ by this skill.
|
|
|
569
627
|
> goes to `Open Questions` with the `adr-candidate:` prefix and is
|
|
570
628
|
> evaluated by `implementation-planning` against the three-criteria
|
|
571
629
|
> gate. Approved decision files land at
|
|
572
|
-
> `<PROJECT_ROOT>/.project-docs/okstra/decisions/<NNNN>-<slug>.md
|
|
573
|
-
> never at external `<PROJECT_ROOT>/docs/adr/`.
|
|
630
|
+
> `<PROJECT_ROOT>/.project-docs/okstra/decisions/<NNNN>-<slug>.md`.
|
|
574
631
|
|
|
575
632
|
### 4.5a. Draft glossary proposals
|
|
576
633
|
|
|
@@ -635,6 +692,12 @@ depth: 0 # 0=parent/single, 1=child, 2=grand
|
|
|
635
692
|
created: <YYYY-MM-DD>
|
|
636
693
|
generator: okstra-brief
|
|
637
694
|
reporter-confirmations: <complete | partial | pending | skipped> # set by Step 6.5
|
|
695
|
+
# codebase-scan variant frontmatter (omit for reporter-input briefs):
|
|
696
|
+
scope: <reporter-input | codebase> # 'codebase' for codebase-scan variant; omit for reporter-input variant
|
|
697
|
+
priority-lenses: [] # codebase-scan only: lens enum subset, size 1..4
|
|
698
|
+
scan-scope: [] # codebase-scan only: 1+ paths
|
|
699
|
+
out-of-scope: [] # codebase-scan only: optional
|
|
700
|
+
candidate-cap: 8 # codebase-scan only: 1..12, default 8
|
|
638
701
|
---
|
|
639
702
|
|
|
640
703
|
# Task Brief: <task_group>/<filename-without-ext>
|
|
@@ -698,6 +761,20 @@ between current and desired.>
|
|
|
698
761
|
<Deadlines, compatibility, technical/operational limits. Use _(none)_ if
|
|
699
762
|
none.>
|
|
700
763
|
|
|
764
|
+
## Scan Scope
|
|
765
|
+
|
|
766
|
+
<!-- codebase-scan variant only — omit this section for reporter-input briefs. -->
|
|
767
|
+
<!-- Author guidance: one bullet per `scan-scope` path with a short description of what lives there. -->
|
|
768
|
+
|
|
769
|
+
- <path>: <one-line description of contents / responsibility>
|
|
770
|
+
|
|
771
|
+
## Priority Lenses
|
|
772
|
+
|
|
773
|
+
<!-- codebase-scan variant only — omit this section for reporter-input briefs. -->
|
|
774
|
+
<!-- Author guidance: one bullet per priority lens explaining why it is a priority for THIS scope. -->
|
|
775
|
+
|
|
776
|
+
- <lens>: <short rationale tying this lens to the scope's risk surface>
|
|
777
|
+
|
|
701
778
|
## Related Artifacts
|
|
702
779
|
|
|
703
780
|
- <file path / URL / issue / prior task-key>
|
|
@@ -810,6 +887,22 @@ Use `_(none)_` if none. -->
|
|
|
810
887
|
- <fill in one entry per conversion, or replace with `_(none)_`>
|
|
811
888
|
````
|
|
812
889
|
|
|
890
|
+
**Variant note:** The template above is the canonical reporter-input shape. For the codebase-scan variant (`scope: codebase` in frontmatter), OMIT the `## Source Material` and `## Problem / Symptom` headings entirely — do NOT include them with `_(none)_` bodies. Instead, ADD `## Scan Scope` and `## Priority Lenses` sections (already present in the template above, marked with HTML comments). The remaining sections (Context / Desired Outcome / Constraints / Related Artifacts / Open Questions / Reporter Confirmations / Augmentation) apply to both variants.
|
|
891
|
+
|
|
892
|
+
### Required sections by variant
|
|
893
|
+
|
|
894
|
+
| Section | `reporter-input` variant | `codebase` variant |
|
|
895
|
+
|---|---|---|
|
|
896
|
+
| `## Source Material` | Required | Not required — omit |
|
|
897
|
+
| `## Problem / Symptom` | Required | Not required — omit |
|
|
898
|
+
| `## Context` | Required | Required |
|
|
899
|
+
| `## Desired Outcome` | Required | Required |
|
|
900
|
+
| `## Constraints` | Required | Required |
|
|
901
|
+
| `## Related Artifacts` | Required | Required |
|
|
902
|
+
| `## Open Questions` | Required | Required |
|
|
903
|
+
| `## Scan Scope` | Not applicable — omit | Required — one bullet per `scan-scope` path with a short description of what lives there |
|
|
904
|
+
| `## Priority Lenses` | Not applicable — omit | Required — one bullet per priority lens with a short rationale for why that lens applies to this scope |
|
|
905
|
+
|
|
813
906
|
### Frontmatter rules
|
|
814
907
|
|
|
815
908
|
- Every brief starts on line 1 with a YAML frontmatter delimited by `---`.
|
|
@@ -842,6 +935,7 @@ Inspect the finalized brief and recommend the next `okstra-run` task-type:
|
|
|
842
935
|
|---|---|
|
|
843
936
|
| `Problem / Symptom` describes a repro / log / stack trace / observable error | `error-analysis` |
|
|
844
937
|
| `Open Questions` is large or `Desired Outcome` is ambiguous / needs classification | `requirements-discovery` |
|
|
938
|
+
| `scope: codebase` frontmatter | `improvement-discovery` |
|
|
845
939
|
| Both / ambiguous | `requirements-discovery` (safe default — the phase itself decides branching) |
|
|
846
940
|
|
|
847
941
|
Write the chosen recommendation into the `Recommended next phase:` header
|
|
@@ -886,7 +980,7 @@ For each pending row, formulate one question. Because the
|
|
|
886
980
|
`AskUserQuestion` tool caps options at 4 per call and questions per call
|
|
887
981
|
also at 4, split into batches of ≤ 4 questions.
|
|
888
982
|
|
|
889
|
-
**
|
|
983
|
+
**Cap — 12 questions per Step 6.5 run.** When the pending list
|
|
890
984
|
exceeds 12 rows, sort by priority and ask only the top 12 this round:
|
|
891
985
|
|
|
892
986
|
1. `conversion-block:` rows first (translation failure — highest
|
|
@@ -983,10 +1077,9 @@ started.
|
|
|
983
1077
|
`<PROJECT_ROOT>/.project-docs/okstra/`. This skill's brief files go
|
|
984
1078
|
under `.project-docs/okstra/briefs/`; its glossary writes go to
|
|
985
1079
|
`.project-docs/okstra/glossary.md` (Step 4.5 approval flow).
|
|
986
|
-
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
never writes to them. Absent external files are the normal state.
|
|
1080
|
+
- Paths outside `<PROJECT_ROOT>/.project-docs/okstra/**` are read-only
|
|
1081
|
+
source material only when explicitly cited by the reporter. This skill
|
|
1082
|
+
never writes outside okstra's subtree.
|
|
990
1083
|
- **Verbatim source**: never paraphrase, summarize, restructure, or reorder
|
|
991
1084
|
the Source Material section. Only format conversion (ADF → MD, HTML → MD)
|
|
992
1085
|
is allowed, and the conversion must be annotated in the `format:` meta.
|
|
@@ -465,7 +465,7 @@ Plan-body verification is configured under `convergence.planBodyVerification` in
|
|
|
465
465
|
| Setting | Default | Description |
|
|
466
466
|
|---------|---------|-------------|
|
|
467
467
|
| `enabled` | `true` | If `false`, the round is skipped and the top-of-report Approval marker is rendered unconditionally (legacy behaviour). |
|
|
468
|
-
| `maxRounds` | `1` |
|
|
468
|
+
| `maxRounds` | `1` | Upper bound. Plan-body verification is consistency / completeness checking, not fact checking — additional rounds rarely help. Range 1–3. |
|
|
469
469
|
| `gating` | `true` | If `true` (default), `majority-disagree` blocks the Approval marker. If `false`, the round is advisory-only and the marker always renders. |
|
|
470
470
|
|
|
471
471
|
Default values are emitted into the manifest by `scripts/okstra_ctl/render.py` (`_build_convergence_block`). The ctx knob `OKSTRA_PLAN_VERIFICATION=false` flips `planBodyVerification.enabled` to false.
|
|
@@ -632,5 +632,4 @@ Mirrors finding convergence (§"Worker failure handling in reverify"). Concretel
|
|
|
632
632
|
|
|
633
633
|
- A dispatch that returns terminal non-result MUST NOT be aggregated as `DISAGREE`.
|
|
634
634
|
- If at least one dispatch was issued AND **all** plan-body dispatches return non-result, the Gate result is `aborted-non-result`. Record one `contract-violation` event per non-result dispatch.
|
|
635
|
-
-
|
|
636
|
-
|
|
635
|
+
- When the gate is `aborted-non-result`, report-writer MUST keep the frontmatter `approved: false` (publishing `approved: true` under this gate result is a validator failure). A single row is added to `## 5. Clarification Items` with `Statement="plan-body verification could not run — all workers returned non-result"`, `Kind=decision`, `Blocks=approval`, allowing the user to either retry the phase or override by manually flipping the frontmatter to `approved: true` (or running `--approve` on the resume command).
|