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
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
# Final Report Language Configuration — Design Spec
|
|
2
|
+
|
|
3
|
+
- Date: 2026-05-20
|
|
4
|
+
- Status: Approved (pending writing-plans)
|
|
5
|
+
- Owner: Claude lead (this session)
|
|
6
|
+
- Related: `templates/reports/final-report.template.md`, `scripts/okstra-render-final-report.py`, `skills/okstra-setup/SKILL.md`, `skills/okstra-report-writer/SKILL.md`, `agents/SKILL.md`
|
|
7
|
+
|
|
8
|
+
## 1. Problem
|
|
9
|
+
|
|
10
|
+
The okstra final report is currently hardcoded to Korean in three places:
|
|
11
|
+
|
|
12
|
+
1. `skills/okstra-report-writer/SKILL.md` Writing Guidelines — `Write the final report body in Korean.`
|
|
13
|
+
2. `templates/reports/final-report.template.md` — ~30–40 lines of Korean fixed text (section intros, empty-state lines, column headers, token-summary "읽는 법" block, release-handoff 4.6.x labels, etc.).
|
|
14
|
+
3. `agents/SKILL.md` line 322 — lead's post-persistence reply hardcoded to Korean.
|
|
15
|
+
|
|
16
|
+
There is no way to opt into English (or any other language) without manually patching skill / template files. The user request: add a setup step that selects the final-report language, defaulting to English.
|
|
17
|
+
|
|
18
|
+
## 2. Goals & non-goals
|
|
19
|
+
|
|
20
|
+
### Goals
|
|
21
|
+
|
|
22
|
+
- One project-level setting (`reportLanguage`) decides the language of (a) the prose authored by the report-writer worker and (b) the fixed labels rendered from the template.
|
|
23
|
+
- Default for **new** setups is English. Default for **existing** projects whose `project.json` predates this change is `auto` (no surprise switch to English for Korean-speaking users).
|
|
24
|
+
- `auto` resolves to `en` or `ko` based on the task brief's main prose language.
|
|
25
|
+
- Validator-checked English identifiers (`Option Candidates`, `Verdict Token`, `accepted` / `conditional-accept` / `blocked`, etc.) remain English in both languages.
|
|
26
|
+
|
|
27
|
+
### Non-goals (this spec)
|
|
28
|
+
|
|
29
|
+
- Worker analysis prose, lead user-facing messages outside the final-report flow, `okstra-status` / `okstra-schedule` skill responses, and `prompts/profiles/*.md` Korean preferences are **out of scope**.
|
|
30
|
+
- Languages other than `en` and `ko`. (Adding a third language later requires only a new `i18n/<lang>.yaml` file plus extending the enum.)
|
|
31
|
+
- Worker-results audit files under `runs/.../worker-results/*.md` stay in their current language (Korean prose by default).
|
|
32
|
+
|
|
33
|
+
## 3. Data model
|
|
34
|
+
|
|
35
|
+
### 3.1 `project.json` — new optional field
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"projectId": "...",
|
|
40
|
+
"projectRoot": "...",
|
|
41
|
+
"reportLanguage": "auto" | "en" | "ko"
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
- Listed as a user-managed field in `scripts/okstra_project/resolver.py` so runtime `upsert_project_json` preserves it across `okstra setup` / `okstra run` invocations (same treatment as `worktreeSyncDirs`, `qaCommands`, `prTemplatePath`).
|
|
46
|
+
- Absent field ⇒ runtime treats as `"auto"`.
|
|
47
|
+
|
|
48
|
+
### 3.2 `~/.okstra/config.json` — optional global fallback
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{ "reportLanguage": "auto" | "en" | "ko" }
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Same enum, used only when `project.json` doesn't have the field.
|
|
55
|
+
|
|
56
|
+
### 3.3 `final-report-v1.0.schema.json` — audit field
|
|
57
|
+
|
|
58
|
+
Add required `meta.reportLanguage` ∈ `{"en", "ko"}` (no `"auto"` — the lead resolves before dispatching).
|
|
59
|
+
|
|
60
|
+
Rationale: the renderer needs an SSOT inside the data.json so re-rendering after the fact (e.g. someone re-runs `okstra-render-final-report.py` without a `--report-language` flag) produces the same artifact.
|
|
61
|
+
|
|
62
|
+
### 3.4 Resolution priority (lead)
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
CLI flag `--report-language`
|
|
66
|
+
> project.json.reportLanguage
|
|
67
|
+
> ~/.okstra/config.json.reportLanguage
|
|
68
|
+
> "auto"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
If the resolved value is `"auto"`, the lead inspects the task brief and picks `en` or `ko` based on its main prose language. Default to `en` when the brief is mostly code/identifiers and the language is ambiguous. The lead writes the resolved literal `en`/`ko` into the report-writer dispatch prompt's `**Report Language:**` line and into `data.json.meta.reportLanguage`.
|
|
72
|
+
|
|
73
|
+
## 4. Setup flow
|
|
74
|
+
|
|
75
|
+
### 4.1 `skills/okstra-setup/SKILL.md` — add Step 4.9
|
|
76
|
+
|
|
77
|
+
Insert between current Step 4.8 (PR body template) and Step 5 (`okstra doctor`).
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
## Step 4.9 (optional): choose final report language
|
|
81
|
+
|
|
82
|
+
Skip-friendly. Default behaviour when this step is skipped is `auto`
|
|
83
|
+
(report-writer infers from the task brief, falling back to English).
|
|
84
|
+
|
|
85
|
+
AskUserQuestion (fixed options):
|
|
86
|
+
- Question: "Final report를 어느 언어로 작성할까요?"
|
|
87
|
+
- Options:
|
|
88
|
+
1. English (recommended) → reportLanguage: "en"
|
|
89
|
+
2. 한국어 → reportLanguage: "ko"
|
|
90
|
+
3. Auto (task brief 언어로 추론, 불분명하면 영어) → reportLanguage: "auto"
|
|
91
|
+
|
|
92
|
+
After selection:
|
|
93
|
+
okstra config set report-language <en|ko|auto> --scope project
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Project scope only at this step. Global scope is mentioned in README but not prompted during setup (advanced).
|
|
97
|
+
|
|
98
|
+
### 4.2 New CLI subcommands
|
|
99
|
+
|
|
100
|
+
Same handler pattern as the existing `okstra config set pr-template-path`:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
okstra config set report-language <en|ko|auto> --scope <project|global>
|
|
104
|
+
okstra config get report-language --scope <project|global>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Validation:
|
|
108
|
+
- Value must be one of `en`, `ko`, `auto`. Any other value exits `1` with a clear error.
|
|
109
|
+
- `--scope` is required and must be `project` or `global`.
|
|
110
|
+
- Atomic write (`config-write` path used by `pr-template-path`).
|
|
111
|
+
- Output: JSON to stdout naming which file was updated, same shape as the existing `pr-template-path` command.
|
|
112
|
+
|
|
113
|
+
Confirm during implementation that `okstra config get` already exists for `pr-template-path`; if not, extend it to support both keys.
|
|
114
|
+
|
|
115
|
+
## 5. Template i18n
|
|
116
|
+
|
|
117
|
+
### 5.1 Dictionary location
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
templates/reports/i18n/en.yaml
|
|
121
|
+
templates/reports/i18n/ko.yaml
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
YAML chosen because the Korean help text (e.g. the "읽는 법" block) is multi-line and benefits from `|` literal blocks; JSON would require escaped `\n` everywhere. If PyYAML is not already a runtime dependency of okstra Python (to be confirmed during implementation), fall back to JSON with `\n` escapes.
|
|
125
|
+
|
|
126
|
+
### 5.2 Key naming
|
|
127
|
+
|
|
128
|
+
Dot-namespaced groups. Jinja accesses via `t.section.subkey`.
|
|
129
|
+
|
|
130
|
+
```yaml
|
|
131
|
+
verdictCard:
|
|
132
|
+
intro: >-
|
|
133
|
+
At-a-glance verdict card. Every value in this table MUST exactly match
|
|
134
|
+
the authoritative values in `## 2. Final Verdict` and `## 6.
|
|
135
|
+
Recommended Next Steps`.
|
|
136
|
+
|
|
137
|
+
tokenSummary:
|
|
138
|
+
heading: "Token Usage Summary"
|
|
139
|
+
columns:
|
|
140
|
+
item: "Item"
|
|
141
|
+
raw: "Raw tokens"
|
|
142
|
+
billable: "Billable tokens (input-equiv.)"
|
|
143
|
+
cost: "Cost (USD)"
|
|
144
|
+
rows:
|
|
145
|
+
lead: "Lead"
|
|
146
|
+
workerTotal: "Worker subtotal"
|
|
147
|
+
grandTotal: "**Grand total**"
|
|
148
|
+
cliExtra: "Codex/Gemini CLI add-on"
|
|
149
|
+
howToRead: |
|
|
150
|
+
**How to read**: "Raw tokens" is the sum of input + output +
|
|
151
|
+
cache_creation + cache_read processed by the model …
|
|
152
|
+
|
|
153
|
+
emptyState:
|
|
154
|
+
consensusItems: "- No consensus items."
|
|
155
|
+
contestedItems: "- No items missing consensus."
|
|
156
|
+
primaryEvidence: "- No primary evidence."
|
|
157
|
+
secondaryEvidence: "- No secondary evidence or alternate interpretations."
|
|
158
|
+
risks: "- No missing information or risks."
|
|
159
|
+
dependencyRisk: "- No dependency / migration risks."
|
|
160
|
+
dissent: "- No dissenting opinions."
|
|
161
|
+
outOfPlanEdits: "- No out-of-plan edits."
|
|
162
|
+
noFollowUp: "- No follow-up tasks. The next phase for this run is in §6 (Recommended Next Steps)."
|
|
163
|
+
noClarification: "- No additional information requested. The Section 2 verdict stands as-is."
|
|
164
|
+
|
|
165
|
+
sectionAside:
|
|
166
|
+
dependencyRisk: "Dependency / Migration Risk"
|
|
167
|
+
validationChecklist: "Validation Checklist"
|
|
168
|
+
rollbackStrategy: "Rollback Strategy"
|
|
169
|
+
planBodyVerification: "Plan Body Verification"
|
|
170
|
+
recommendedOption: "Recommended Option"
|
|
171
|
+
optionCandidates: "Option Candidates"
|
|
172
|
+
tradeOffMatrix: "Trade-off Matrix"
|
|
173
|
+
stepwiseExecutionOrder: "Stepwise Execution Order"
|
|
174
|
+
|
|
175
|
+
# ... and similar groups for release-handoff 4.6.x, evidence column
|
|
176
|
+
# headers, etc.
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
The `ko.yaml` mirror keeps Korean strings; **both files must have identical key sets** (enforced by a unit test — see §8).
|
|
180
|
+
|
|
181
|
+
### 5.3 Validator-checked English substrings
|
|
182
|
+
|
|
183
|
+
These remain English in both `en.yaml` and `ko.yaml` (i.e. `sectionAside.optionCandidates` in `ko.yaml` is still the English string `Option Candidates`):
|
|
184
|
+
|
|
185
|
+
- Phase-specific heading anchors: `Option Candidates`, `Trade-off`, `Recommended Option`, `Stepwise Execution Order`, `Dependency`, `Validation Checklist`, `Rollback`, `User Approval Request`, `Plan Body Verification`, `Gate result:`
|
|
186
|
+
- Verdict tokens: `accepted`, `conditional-accept`, `blocked`, `not-applicable`
|
|
187
|
+
- Direction tokens: `continue-investigation`, `begin-implementation`, `approve`, `reject`, `hold`
|
|
188
|
+
|
|
189
|
+
Korean parenthetical aside is i18n'd. For Korean reports this renders as `### Recommended Option (권장 옵션)`; for English reports it renders as `### Recommended Option (Recommended Option)` — which looks silly. **Decision:** when Korean and English would produce the same string, the template omits the parenthetical entirely. Template form:
|
|
190
|
+
|
|
191
|
+
```jinja
|
|
192
|
+
### Recommended Option{% if t.sectionAside.recommendedOption != "Recommended Option" %} ({{ t.sectionAside.recommendedOption }}){% endif %}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### 5.4 Missing-key policy
|
|
196
|
+
|
|
197
|
+
Jinja `Environment(undefined=StrictUndefined)` — referencing a missing key raises `UndefinedError` at render time. No silent fallback to the key name. This makes "I forgot to translate X" fail loudly during e2e instead of shipping `{{ t.foo.bar }}` literal in production reports.
|
|
198
|
+
|
|
199
|
+
### 5.5 Template conversion scope
|
|
200
|
+
|
|
201
|
+
Run `grep -P '[\x{AC00}-\x{D7A3}]'` (Korean Unicode range) against `templates/reports/final-report.template.md` until 0 matches remain. Estimated 50–70 i18n keys across the categories:
|
|
202
|
+
|
|
203
|
+
1. Section intro prose (lines 35, 49, 54, 84, 131, 243, 275, 525)
|
|
204
|
+
2. Empty-state lines (lines 122, 136, 162, 176, 188, 248, 299, 424, 449, 495, 527, 530, 570)
|
|
205
|
+
3. Column headers (line 56 "한 줄 요약 / 출처", line 86 "처리 토큰 / 환산 토큰 / 비용", line 267 "확인 방법")
|
|
206
|
+
4. Heading Korean aside (lines 245, 257, 273, the 4.5.x series)
|
|
207
|
+
5. The token-summary "읽는 법" blockquote
|
|
208
|
+
6. release-handoff 4.6.x Korean labels (lines 325, 329, 448, 473, etc.)
|
|
209
|
+
|
|
210
|
+
Identifier strings (`Verdict Token`, JSON code blocks, model names, file paths) stay verbatim.
|
|
211
|
+
|
|
212
|
+
## 6. Renderer changes
|
|
213
|
+
|
|
214
|
+
### 6.1 `scripts/okstra-render-final-report.py`
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
import argparse, json, yaml
|
|
218
|
+
from pathlib import Path
|
|
219
|
+
import jinja2
|
|
220
|
+
|
|
221
|
+
def main():
|
|
222
|
+
ap = argparse.ArgumentParser()
|
|
223
|
+
ap.add_argument("data_json", type=Path)
|
|
224
|
+
ap.add_argument("--report-language", choices=["en", "ko"], default=None)
|
|
225
|
+
args = ap.parse_args()
|
|
226
|
+
|
|
227
|
+
data = json.loads(args.data_json.read_text())
|
|
228
|
+
lang = (
|
|
229
|
+
args.report_language
|
|
230
|
+
or data.get("meta", {}).get("reportLanguage")
|
|
231
|
+
or "en"
|
|
232
|
+
)
|
|
233
|
+
if lang not in {"en", "ko"}:
|
|
234
|
+
raise SystemExit(f"reportLanguage must be 'en' or 'ko', got {lang!r}")
|
|
235
|
+
|
|
236
|
+
i18n_path = Path(__file__).parent.parent / "templates" / "reports" / "i18n" / f"{lang}.yaml"
|
|
237
|
+
i18n = yaml.safe_load(i18n_path.read_text())
|
|
238
|
+
|
|
239
|
+
env = jinja2.Environment(
|
|
240
|
+
loader=jinja2.FileSystemLoader(...),
|
|
241
|
+
undefined=jinja2.StrictUndefined,
|
|
242
|
+
autoescape=False,
|
|
243
|
+
keep_trailing_newline=True,
|
|
244
|
+
)
|
|
245
|
+
tmpl = env.get_template("final-report.template.md")
|
|
246
|
+
out_path = args.data_json.with_suffix("").with_suffix(".md")
|
|
247
|
+
out_path.write_text(tmpl.render(**data, t=i18n))
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
(Sketch — actual file structure follows the existing renderer's conventions; the changes are: `--report-language` flag, `meta.reportLanguage` read, YAML loader, `t=i18n` context key, `StrictUndefined`.)
|
|
251
|
+
|
|
252
|
+
### 6.2 `scripts/okstra-render-report-views.py`
|
|
253
|
+
|
|
254
|
+
Reads the rendered markdown — no logic change needed. The HTML view inherits whatever language the markdown was rendered in.
|
|
255
|
+
|
|
256
|
+
## 7. Worker / lead contract changes
|
|
257
|
+
|
|
258
|
+
### 7.1 `agents/SKILL.md` (Claude lead)
|
|
259
|
+
|
|
260
|
+
Add to the Phase 6 preparation checklist:
|
|
261
|
+
|
|
262
|
+
```
|
|
263
|
+
- Resolve report language: read `project.json.reportLanguage`
|
|
264
|
+
(fallback `~/.okstra/config.json.reportLanguage`, then literal `auto`).
|
|
265
|
+
If the resolved value is `auto`, inspect the task brief and pick `en`
|
|
266
|
+
or `ko` based on its main prose language (default `en` when the brief
|
|
267
|
+
is mostly code/identifiers). Pass the final `en`/`ko` value as
|
|
268
|
+
`**Report Language:**` in the report-writer dispatch prompt and ensure
|
|
269
|
+
the worker writes the same value into `data.json.meta.reportLanguage`.
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Replace line 322:
|
|
273
|
+
|
|
274
|
+
```diff
|
|
275
|
+
- After persistence, reply briefly in Korean with: completion status, ...
|
|
276
|
+
+ After persistence, reply briefly in the resolved Report Language with:
|
|
277
|
+
+ completion status, ...
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### 7.2 `skills/okstra-report-writer/SKILL.md`
|
|
281
|
+
|
|
282
|
+
Add a new entry to the Phase 6 dispatch prompt's required-header list. The list currently has 11 items; insert the new entry immediately after the convergence-classifications item (current item 9) and renumber the remaining items:
|
|
283
|
+
|
|
284
|
+
```
|
|
285
|
+
**Report Language:** <en|ko> # auto must be pre-resolved by the lead;
|
|
286
|
+
# the worker writes this verbatim into
|
|
287
|
+
# data.json.meta.reportLanguage
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Replace the two hardcoded "Korean" lines (Writing Guidelines + Response after Persistence):
|
|
291
|
+
|
|
292
|
+
```diff
|
|
293
|
+
- - Write the final report body in Korean.
|
|
294
|
+
+ - Write the final report body in the language passed as **Report Language**
|
|
295
|
+
+ in the dispatch prompt. The template's fixed labels (section asides,
|
|
296
|
+
+ empty-states, token summary, etc.) are i18n-rendered by
|
|
297
|
+
+ `okstra-render-final-report.py` from `templates/reports/i18n/<lang>.yaml`;
|
|
298
|
+
+ focus on the prose you author (Section 1 categories, Section 3 evidence
|
|
299
|
+
+ narratives, Section 4 risks, Section 6 recommendations, etc.).
|
|
300
|
+
+ Code identifiers, file paths, model names, status tokens, and the
|
|
301
|
+
+ validator-checked English substrings stay in English regardless of
|
|
302
|
+
+ Report Language.
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
```diff
|
|
306
|
+
- Provide a concise report in Korean covering the following:
|
|
307
|
+
+ Provide a concise report in the Report Language covering the following:
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
Add to the data.json contract (alongside the token-cell-null paragraph):
|
|
311
|
+
|
|
312
|
+
```
|
|
313
|
+
- Set `meta.reportLanguage` to the resolved `en` or `ko` value passed in
|
|
314
|
+
**Report Language**. `auto` is forbidden here — the lead has already
|
|
315
|
+
resolved it. The renderer reads this field as the SSOT when no CLI
|
|
316
|
+
`--report-language` flag is given.
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### 7.3 `agents/workers/report-writer-worker.md`
|
|
320
|
+
|
|
321
|
+
Add `templates/reports/i18n/en.yaml` and `templates/reports/i18n/ko.yaml` to the worker's reading set. One-line reminder that the `Report Language` header value goes into `data.json.meta.reportLanguage` verbatim.
|
|
322
|
+
|
|
323
|
+
## 8. Tests
|
|
324
|
+
|
|
325
|
+
### 8.1 Unit (`tests/`)
|
|
326
|
+
|
|
327
|
+
- `test_report_language_resolver.py` — resolution priority (CLI flag > project.json > global config > `"auto"`).
|
|
328
|
+
- `test_report_language_config_set.py` — `okstra config set report-language` accepts `en`/`ko`/`auto`, rejects others; writes to project.json or `~/.okstra/config.json` per scope.
|
|
329
|
+
- `test_i18n_keysets_match.py` — `en.yaml` and `ko.yaml` have **identical key sets** (set diff must be empty in both directions).
|
|
330
|
+
- `test_i18n_missing_key_raises.py` — referencing an undefined `t.foo.bar` from the template raises `jinja2.UndefinedError`.
|
|
331
|
+
- `test_render_meta_report_language.py` — renderer reads `data.json.meta.reportLanguage` as SSOT when no `--report-language` flag is given.
|
|
332
|
+
- `test_template_no_korean_glyphs.py` — `grep -P '[\x{AC00}-\x{D7A3}]'` against `templates/reports/final-report.template.md` returns zero matches. (Regression guard for "someone re-introduced Korean fixed text".)
|
|
333
|
+
|
|
334
|
+
### 8.2 E2E (`tests-e2e/`)
|
|
335
|
+
|
|
336
|
+
- `scenario-N-final-report-en.sh` — full okstra run with `reportLanguage: "en"`. Asserts the rendered markdown contains the English `Token Usage Summary` heading and does NOT contain Korean characters in template-owned regions.
|
|
337
|
+
- `scenario-M-final-report-ko.sh` — same with `reportLanguage: "ko"`. Asserts the Korean `토큰 사용량 요약` heading is present.
|
|
338
|
+
|
|
339
|
+
## 9. Migration / rollout
|
|
340
|
+
|
|
341
|
+
- pre-v1 → no compat shims. Existing reports are not re-rendered.
|
|
342
|
+
- Existing `project.json` files have no `reportLanguage` field → runtime treats as `"auto"`. Korean-speaking users writing Korean briefs continue to get Korean reports without any action.
|
|
343
|
+
- New `okstra setup` runs see Step 4.9 with `English` as the recommended default — users explicitly opt into the new default through that prompt.
|
|
344
|
+
- `CHANGES.md` entry:
|
|
345
|
+
|
|
346
|
+
```
|
|
347
|
+
### feat(setup): final report language is now configurable
|
|
348
|
+
- 사용자 영향: 신규 `okstra setup` 의 final report 기본 언어가 영어로 바뀝니다.
|
|
349
|
+
기존 프로젝트(`project.json.reportLanguage` 미설정)는 `auto` 로 동작하여
|
|
350
|
+
task brief 의 주 서술 언어를 따라가므로, 한국어 brief 를 쓰던 사용자에게
|
|
351
|
+
재설정 없이 종전과 같은 한국어 보고서가 출력됩니다.
|
|
352
|
+
- 새 CLI: `okstra config set report-language <en|ko|auto> --scope <project|global>`.
|
|
353
|
+
- i18n 사전: `templates/reports/i18n/{en,ko}.yaml`.
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
## 10. Files touched (final list)
|
|
357
|
+
|
|
358
|
+
| File | Change |
|
|
359
|
+
|---|---|
|
|
360
|
+
| `templates/reports/final-report.template.md` | Korean fixed text → `{{ t.* }}` i18n references |
|
|
361
|
+
| `templates/reports/i18n/en.yaml` | NEW |
|
|
362
|
+
| `templates/reports/i18n/ko.yaml` | NEW |
|
|
363
|
+
| `scripts/okstra-render-final-report.py` | `--report-language` flag, YAML loader, `StrictUndefined`, `t=i18n` |
|
|
364
|
+
| `schemas/final-report-v1.0.schema.json` | Add required `meta.reportLanguage` ∈ `{en, ko}` |
|
|
365
|
+
| `scripts/okstra_project/resolver.py` | `reportLanguage` added to preserved user fields list |
|
|
366
|
+
| `src/config.mjs` (or wherever `pr-template-path` lives) | `set/get report-language` subcommands |
|
|
367
|
+
| `skills/okstra-setup/SKILL.md` | Step 4.9 |
|
|
368
|
+
| `skills/okstra-report-writer/SKILL.md` | Dispatch prompt header + Writing Guidelines + data.json contract |
|
|
369
|
+
| `agents/SKILL.md` | Phase 6 prep checklist + line 322 |
|
|
370
|
+
| `agents/workers/report-writer-worker.md` | Reading set + `meta.reportLanguage` reminder |
|
|
371
|
+
| `tests/test_*.py` (6 new) | See §8.1 |
|
|
372
|
+
| `tests-e2e/scenario-N-final-report-en.sh` | NEW |
|
|
373
|
+
| `tests-e2e/scenario-M-final-report-ko.sh` | NEW |
|
|
374
|
+
| `CHANGES.md` | New entry per §9 |
|
|
375
|
+
|
|
376
|
+
## 11. Open implementation questions
|
|
377
|
+
|
|
378
|
+
To be resolved during writing-plans / implementation:
|
|
379
|
+
|
|
380
|
+
1. Whether PyYAML is already a runtime dependency of okstra Python (otherwise fall back to JSON dictionaries).
|
|
381
|
+
2. Whether `okstra config get` exists today for `pr-template-path` — extend if yes, add if no.
|
|
382
|
+
3. Exact i18n key namespacing for the release-handoff 4.6.x labels (largest single chunk of Korean text outside §4.5).
|
|
383
|
+
4. Test scenario sequencing — pick free `scenario-NN` numbers in `tests-e2e/`.
|