okstra 0.218.0 → 0.219.1

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 (92) hide show
  1. package/README.md +5 -5
  2. package/dist/cli-registry.mjs +0 -10
  3. package/dist/cli-registry.mjs.map +1 -1
  4. package/dist/commands/lifecycle/config.mjs +2 -3
  5. package/dist/commands/lifecycle/config.mjs.map +1 -1
  6. package/dist/commands/pr/pr.d.mts +6 -0
  7. package/dist/commands/pr/pr.mjs +58 -0
  8. package/dist/commands/pr/pr.mjs.map +1 -1
  9. package/dist/lib/runtime-payload.mjs +1 -2
  10. package/dist/lib/runtime-payload.mjs.map +1 -1
  11. package/docs/architecture/storage-model.md +1 -1
  12. package/docs/architecture.md +9 -7
  13. package/docs/cli.md +3 -4
  14. package/docs/project-structure-overview.md +4 -5
  15. package/package.json +1 -1
  16. package/runtime/BUILD.json +2 -2
  17. package/runtime/prompts/launch.template.md +1 -1
  18. package/runtime/prompts/lead/okstra-lead-contract.md +1 -3
  19. package/runtime/prompts/lead/report-writer.md +10 -17
  20. package/runtime/prompts/lead/team-contract.md +1 -2
  21. package/runtime/prompts/wizard/prompts.ko.json +0 -1
  22. package/runtime/python/okstra_ctl/adapters/hosts/codex/relay.md +1 -1
  23. package/runtime/python/okstra_ctl/adapters/providers/antigravity/adapter.py +1 -1
  24. package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +0 -1
  25. package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +1 -1
  26. package/runtime/python/okstra_ctl/adapters/providers/grok/adapter.py +0 -1
  27. package/runtime/python/okstra_ctl/adapters/providers/kimi/adapter.py +0 -1
  28. package/runtime/python/okstra_ctl/agent/invocation.py +1 -2
  29. package/runtime/python/okstra_ctl/agent/prompt_cli/cli.py +2 -2
  30. package/runtime/python/okstra_ctl/agent/prompt_cli/jobs.py +0 -2
  31. package/runtime/python/okstra_ctl/agent/prompt_cli/materialize.py +2 -27
  32. package/runtime/python/okstra_ctl/agent/prompt_cli/run_identity.py +0 -4
  33. package/runtime/python/okstra_ctl/dispatch_core.py +3 -349
  34. package/runtime/python/okstra_ctl/dispatch_state.py +0 -13
  35. package/runtime/python/okstra_ctl/domain/provider.py +1 -1
  36. package/runtime/python/okstra_ctl/domain/role.py +0 -6
  37. package/runtime/python/okstra_ctl/final_report_paths.py +0 -16
  38. package/runtime/python/okstra_ctl/i18n.py +2 -2
  39. package/runtime/python/okstra_ctl/path_hints.py +0 -4
  40. package/runtime/python/okstra_ctl/paths.py +0 -3
  41. package/runtime/python/okstra_ctl/phases/final_verification/profile.md +2 -0
  42. package/runtime/python/okstra_ctl/phases/final_verification/spec.md +2 -0
  43. package/runtime/python/okstra_ctl/phases/final_verification/target.py +17 -1
  44. package/runtime/python/okstra_ctl/phases/implementation/entry.py +12 -0
  45. package/runtime/python/okstra_ctl/phases/implementation/instructions/_implementation-deliverable.md +1 -0
  46. package/runtime/python/okstra_ctl/phases/implementation/instructions/_implementation-executor.md +1 -0
  47. package/runtime/python/okstra_ctl/phases/implementation/spec.md +4 -0
  48. package/runtime/python/okstra_ctl/phases/release_handoff/boundary.json +1 -1
  49. package/runtime/python/okstra_ctl/phases/release_handoff/operations.py +24 -3
  50. package/runtime/python/okstra_ctl/phases/release_handoff/profile.md +11 -11
  51. package/runtime/python/okstra_ctl/phases/release_handoff/spec.md +4 -2
  52. package/runtime/python/okstra_ctl/render.py +0 -10
  53. package/runtime/python/okstra_ctl/render_final_report.py +4 -4
  54. package/runtime/python/okstra_ctl/report_finalize.py +37 -76
  55. package/runtime/python/okstra_ctl/report_html/render.py +4 -44
  56. package/runtime/python/okstra_ctl/report_language.py +3 -3
  57. package/runtime/python/okstra_ctl/report_prose_keys.py +153 -0
  58. package/runtime/python/okstra_ctl/report_synthesis_packet.py +1 -1
  59. package/runtime/python/okstra_ctl/run.py +1 -21
  60. package/runtime/python/okstra_ctl/stage_integrate.py +37 -2
  61. package/runtime/python/okstra_ctl/stage_rebase.py +189 -0
  62. package/runtime/python/okstra_ctl/stage_targets.py +29 -62
  63. package/runtime/python/okstra_ctl/team.py +1 -6
  64. package/runtime/python/okstra_ctl/wizard/confirmation.py +0 -8
  65. package/runtime/python/okstra_ctl/wizard/registry.py +2 -3
  66. package/runtime/python/okstra_ctl/wizard/sources.py +10 -0
  67. package/runtime/python/okstra_ctl/worker_prompt_policy.py +3 -12
  68. package/runtime/python/okstra_ctl/worktree/__init__.py +1 -1
  69. package/runtime/python/okstra_ctl/worktree/decisions.py +3 -4
  70. package/runtime/python/okstra_ctl/worktree/provision.py +27 -0
  71. package/runtime/python/okstra_ctl/worktree/rebase.py +108 -0
  72. package/runtime/python/okstra_ctl/worktree_registry.py +14 -0
  73. package/runtime/skills/_fragments/wizard-render-bundle.md +1 -1
  74. package/runtime/skills/okstra-code-review/SKILL.md +1 -1
  75. package/runtime/skills/okstra-discussion/SKILL.md +1 -1
  76. package/runtime/skills/okstra-pr-gen/SKILL.md +9 -0
  77. package/runtime/skills/okstra-run/SKILL.md +1 -1
  78. package/runtime/skills/okstra-setup/SKILL.md +2 -2
  79. package/runtime/skills/okstra-setup/references/project-config.md +2 -2
  80. package/runtime/templates/pr/drafting-rules.md +4 -0
  81. package/runtime/templates/report-writer-prompt-preamble.md +1 -1
  82. package/runtime/templates/reports/html/i18n/en.json +0 -1
  83. package/runtime/templates/reports/html/i18n/ko.json +0 -1
  84. package/runtime/templates/worker-prompt-preamble.md +1 -1
  85. package/runtime/validators/validate-run.py +1 -28
  86. package/runtime/agents/operations/report-translation.json +0 -6
  87. package/runtime/agents/roles/translator.json +0 -19
  88. package/runtime/bin/okstra-report-translate.py +0 -404
  89. package/runtime/prompts/duties/translator.json +0 -32
  90. package/runtime/python/okstra_ctl/report_translation.py +0 -509
  91. package/runtime/python/okstra_ctl/report_translation_dispatch.py +0 -356
  92. package/runtime/templates/translator-prompt-preamble.md +0 -36
@@ -1,404 +0,0 @@
1
- #!/usr/bin/env python3
2
- """CLI entrypoint for the Phase 7 translation sidecar.
3
-
4
- Usage:
5
- okstra-report-translate.py extract <path-to-final-report.data.json>
6
- okstra-report-translate.py check <path-to-sidecar.i18n.<lang>.json>
7
-
8
- ``extract`` writes the translator's work list — every pointer the report holds
9
- a translatable string at, paired with the English text. The translator fills
10
- in the values rather than authoring pointers, so a sidecar cannot cite a path
11
- the document does not have.
12
-
13
- ``check`` is the translator's own gate before it returns: it resolves every
14
- pointer in the sidecar against the report and reports what is still English.
15
- Without it a bad sidecar surfaces at render time, after the worker is gone.
16
-
17
- This script is the canonical single-reference-point. The Node CLI
18
- (``bin/okstra report-translate``) is a thin wrapper that spawns it.
19
- """
20
- from __future__ import annotations
21
-
22
- import argparse
23
- import hashlib
24
- import json
25
- import re
26
- import os
27
- import sys
28
- from pathlib import Path
29
-
30
- sys.path.insert(0, str(Path(__file__).resolve().parent))
31
- from okstra_bootstrap import prefer_colocated_modules # noqa: E402
32
-
33
- prefer_colocated_modules(__file__, "okstra_ctl/report_translation.py")
34
-
35
- from okstra_ctl.report_translation import ( # noqa: E402
36
- extract,
37
- group_translation_pointers,
38
- overlay,
39
- )
40
- from okstra_ctl.final_report_paths import ( # noqa: E402
41
- translation_sidecar_path,
42
- translation_source_path,
43
- )
44
- from okstra_ctl.json_boundary import ( # noqa: E402
45
- JsonBoundaryError,
46
- load_owned_object,
47
- load_owned_object_snapshot,
48
- write_owned_object_atomic,
49
- )
50
- from okstra_ctl.fixed_text import block, line # noqa: E402
51
- from okstra_ctl.convergence import ( # noqa: E402
52
- ConvergenceContractError,
53
- RunArtifactAuthority,
54
- canonical_run_report_artifact,
55
- validated_run_authority,
56
- )
57
-
58
-
59
- def _load(path: Path) -> dict:
60
- try:
61
- return load_owned_object(path, artifact="report translation artifact")
62
- except JsonBoundaryError as exc:
63
- raise SystemExit(f"error: {exc}") from exc
64
-
65
-
66
- def _translation_authority(
67
- manifest_path: Path,
68
- ) -> tuple[RunArtifactAuthority, Path]:
69
- try:
70
- authority = validated_run_authority(manifest_path)
71
- report = canonical_run_report_artifact(authority)
72
- except (ConvergenceContractError, JsonBoundaryError) as exc:
73
- raise SystemExit(f"error: {exc}") from exc
74
- return authority, report
75
-
76
-
77
- def _report_snapshot(path: Path):
78
- try:
79
- return load_owned_object_snapshot(
80
- path, artifact="report translation source"
81
- )
82
- except JsonBoundaryError as exc:
83
- raise SystemExit(f"error: {exc}") from exc
84
-
85
-
86
- def _source_payload(
87
- authority: RunArtifactAuthority, data_path: Path, raw_bytes: bytes, data: dict
88
- ) -> dict:
89
- strings = extract(data)
90
- return {
91
- "taskKey": authority.task_key,
92
- "runManifestPath": authority.manifest_ref,
93
- "sourceData": data_path.name,
94
- "sourceDataPath": data_path.relative_to(authority.project_root).as_posix(),
95
- "sourceDataSha256": hashlib.sha256(raw_bytes).hexdigest(),
96
- "lang": str((data.get("meta") or {}).get("reportLanguage") or ""),
97
- "strings": strings,
98
- "translationGroups": group_translation_pointers(data, strings),
99
- }
100
-
101
-
102
- def _validate_source_payload(
103
- source: dict, expected: dict, supplied_digest: str
104
- ) -> None:
105
- for key in (
106
- "taskKey", "runManifestPath", "sourceData", "sourceDataPath",
107
- "sourceDataSha256", "lang", "strings",
108
- ):
109
- if source.get(key) != expected.get(key):
110
- raise SystemExit(
111
- "error: report changed after translation source publication"
112
- )
113
- if supplied_digest != expected["sourceDataSha256"]:
114
- raise SystemExit(
115
- "error: report changed after translation source publication"
116
- )
117
- if "translationGroups" in source and (
118
- source["translationGroups"] != expected["translationGroups"]
119
- ):
120
- raise SystemExit("error: translation groups do not match report source")
121
-
122
-
123
- def cmd_extract(args: argparse.Namespace) -> int:
124
- data_path = Path(args.data).resolve()
125
- data = _load(data_path)
126
- strings = extract(data)
127
- out_path = translation_source_path(data_path)
128
- lang = str((data.get("meta") or {}).get("reportLanguage") or "")
129
- write_owned_object_atomic(
130
- out_path,
131
- {"lang": lang, "sourceData": data_path.name, "strings": strings},
132
- artifact="translation source",
133
- )
134
- print(
135
- json.dumps(
136
- {
137
- "ok": True,
138
- "sourcePath": str(out_path),
139
- "sidecarPath": str(translation_sidecar_path(data_path, lang)) if lang else "",
140
- "lang": lang,
141
- "stringCount": len(strings),
142
- "charCount": sum(len(v) for v in strings.values()),
143
- },
144
- ensure_ascii=False,
145
- )
146
- )
147
- return 0
148
-
149
-
150
- def cmd_source(args: argparse.Namespace) -> int:
151
- authority, data_path = _translation_authority(Path(args.run_manifest))
152
- snapshot = _report_snapshot(data_path)
153
- data = snapshot.value
154
- payload = _source_payload(authority, data_path, snapshot.raw_bytes, data)
155
- out_path = translation_source_path(data_path)
156
- if out_path.is_symlink():
157
- raise SystemExit("error: translation source path is a symlink")
158
- write_owned_object_atomic(
159
- out_path, payload, artifact="translation source"
160
- )
161
- strings = payload["strings"]
162
- print("# Translation work list")
163
- print(line("Task key", authority.task_key), end="")
164
- print(line("Report", payload["sourceDataPath"]), end="")
165
- print(line("Run manifest", authority.manifest_ref), end="")
166
- print(line("Source digest", payload["sourceDataSha256"]), end="")
167
- groups = payload["translationGroups"]
168
- print(line("Field count", len(strings)), end="")
169
- print(line("String count", len(groups)), end="")
170
- print(line("Source characters", sum(len(value) for value in strings.values())), end="")
171
- print(line("Translation characters", sum(len(strings[row[0]]) for row in groups)), end="")
172
- for index, pointers in enumerate(groups, 1):
173
- print(f"\n## T-{index:03d}\n{block(strings[pointers[0]])}")
174
- return 0
175
-
176
-
177
- def _translation_block(rows: list[str]) -> str:
178
- # Markdown 의 `\`` 는 백틱 리터럴이고, 이전 `source` 출력이 본문 백틱을 그렇게
179
- # 내보냈다. 렌더러는 Markdown 이스케이프를 모르므로 여기서 백틱으로 되돌린다.
180
- return "\n".join(rows).strip().replace("\\`", "`")
181
-
182
-
183
- _T_HEADING_RE = re.compile(r"^#{1,6}\s+T-\d{3}\b")
184
-
185
-
186
- def _translation_blocks(path: Path) -> list[str]:
187
- text = path.read_text(encoding="utf-8")
188
- blocks: list[str] = []
189
- current: list[str] | None = None
190
- for number, row in enumerate(text.splitlines(), start=1):
191
- # 헤딩 수준이 다른 `### T-NNN` 은 블록 경계로 안 보여 본문에 묻히고, 그러면
192
- # 블록 수 불일치라는 엉뚱한 메시지가 났다(실측 2026-09-08: id 164개 전부
193
- # 일치, 틀린 것은 `#` 개수뿐). 경계처럼 생긴 줄은 여기서 이름을 대고 거절한다.
194
- if _T_HEADING_RE.match(row) and not row.startswith("## T-"):
195
- raise SystemExit(
196
- f"error: translation heading must be level 2 — line {number} is "
197
- f"{row.split()[0]!r}, expected '## T-NNN' ({path.name})"
198
- )
199
- if row.startswith("## T-"):
200
- if current is not None:
201
- blocks.append(_translation_block(current))
202
- expected = f"## T-{len(blocks) + 1:03d}"
203
- if row != expected:
204
- raise SystemExit(
205
- f"error: expected translation heading {expected} at line {number}, "
206
- f"found {row!r} ({path.name})"
207
- )
208
- current = []
209
- elif current is not None:
210
- current.append(row)
211
- if current is not None:
212
- blocks.append(_translation_block(current))
213
- return blocks
214
-
215
-
216
- def cmd_write(args: argparse.Namespace) -> int:
217
- authority, data_path = _translation_authority(Path(args.run_manifest))
218
- snapshot = _report_snapshot(data_path)
219
- data = snapshot.value
220
- expected = _source_payload(
221
- authority, data_path, snapshot.raw_bytes, data
222
- )
223
- source_path = translation_source_path(data_path)
224
- if source_path.is_symlink():
225
- raise SystemExit("error: translation source path is a symlink")
226
- source = _load(source_path)
227
- _validate_source_payload(source, expected, args.source_digest)
228
- sources = expected["strings"]
229
- # 발행된 구형 작업 목록은 필드당 한 블록이므로 진행 중 번역의 번호를 보존한다.
230
- groups = source.get("translationGroups", [[pointer] for pointer in sources])
231
- translated = _translation_blocks(Path(args.translations))
232
- if len(translated) != len(groups):
233
- raise SystemExit(
234
- f"error: translation blocks must match every T-NNN item — "
235
- f"{len(translated)} blocks in {Path(args.translations).name}, "
236
- f"{len(groups)} items in the translation source"
237
- )
238
- empty = [f"T-{index + 1:03d}" for index, value in enumerate(translated) if not value]
239
- if empty:
240
- raise SystemExit(
241
- "error: translation blocks must match every T-NNN item — empty: "
242
- + ", ".join(empty[:10])
243
- )
244
- lang = expected["lang"]
245
- sidecar = translation_sidecar_path(data_path, lang)
246
- if sidecar.is_symlink():
247
- raise SystemExit("error: translation sidecar path is a symlink")
248
- strings = {
249
- pointer: value
250
- for pointers, value in zip(groups, translated)
251
- for pointer in pointers
252
- }
253
- _, report = overlay(data, strings)
254
- if report.unresolved or report.applied != len(strings):
255
- raise SystemExit("error: translations do not validate against report source")
256
- write_owned_object_atomic(
257
- sidecar,
258
- {
259
- "taskKey": authority.task_key,
260
- "runManifestPath": authority.manifest_ref,
261
- "lang": lang,
262
- "sourceData": data_path.name,
263
- "sourceDataPath": expected["sourceDataPath"],
264
- "sourceDataSha256": expected["sourceDataSha256"],
265
- "strings": strings,
266
- },
267
- artifact="report translation sidecar",
268
- )
269
- print("Translation sidecar\n" + line("Status", "ready"), end="")
270
- return 0
271
-
272
-
273
- def cmd_check_data(args: argparse.Namespace) -> int:
274
- authority, data_path = _translation_authority(Path(args.run_manifest))
275
- snapshot = _report_snapshot(data_path)
276
- expected = _source_payload(
277
- authority, data_path, snapshot.raw_bytes, snapshot.value
278
- )
279
- sidecar_path = translation_sidecar_path(data_path, expected["lang"])
280
- if sidecar_path.is_symlink():
281
- raise SystemExit("error: translation sidecar path is a symlink")
282
- sidecar = _load(sidecar_path)
283
- _validate_authority_sidecar(sidecar, expected)
284
- payload, code = _check_sidecar(sidecar_path)
285
- print("Translation check\n" + line("Status", "ready" if payload["ok"] else "error")
286
- + line("Applied strings", payload["applied"])
287
- + line("Unresolved strings", len(payload["unresolved"])), end="")
288
- return code
289
-
290
-
291
- def _validate_authority_sidecar(sidecar: dict, expected: dict) -> None:
292
- for key in (
293
- "taskKey", "runManifestPath", "lang", "sourceData", "sourceDataPath",
294
- "sourceDataSha256",
295
- ):
296
- if sidecar.get(key) != expected.get(key):
297
- raise SystemExit(
298
- "error: translation sidecar does not match run authority"
299
- )
300
-
301
-
302
- def cmd_check(args: argparse.Namespace) -> int:
303
- sidecar_file = Path(args.sidecar).resolve()
304
- payload, code = _check_sidecar(sidecar_file)
305
- print(json.dumps(payload, ensure_ascii=False))
306
- return code
307
-
308
-
309
- def _check_sidecar(sidecar_file: Path) -> tuple[dict, int]:
310
- sidecar = _load(sidecar_file)
311
- strings = sidecar.get("strings")
312
- if not isinstance(strings, dict):
313
- raise SystemExit(f"error: {sidecar_file} has no 'strings' object")
314
- source_name = str(sidecar.get("sourceData") or "")
315
- if not source_name:
316
- raise SystemExit(f"error: {sidecar_file} does not name its sourceData")
317
- data_path = sidecar_file.parent / source_name
318
- if not data_path.is_file():
319
- raise SystemExit(f"error: sourceData not found beside the sidecar: {data_path}")
320
-
321
- _, report = overlay(_load(data_path), strings)
322
- offered = report.applied + len(report.untranslated)
323
- payload = {
324
- "ok": not report.unresolved,
325
- "applied": report.applied,
326
- "offered": offered,
327
- "untranslated": list(report.untranslated),
328
- "unresolved": list(report.unresolved),
329
- }
330
- if report.unresolved:
331
- # A pointer that resolves nowhere means the sidecar was written against
332
- # a different report. Rendering it would silently drop those strings.
333
- sys.stderr.write(
334
- f"error: {len(report.unresolved)} pointer(s) do not resolve in "
335
- f"{data_path.name}\n"
336
- )
337
- return payload, 1
338
- return payload, 0
339
-
340
-
341
- _CLI_EPILOG = r"""A thin spawn shim over `scripts/okstra-report-translate.py` (installed at
342
- `$HOME/.okstra/bin/okstra-report-translate.py`).
343
-
344
- The final-report data.json is authored in English and stays the SSOT. When the
345
- resolved report language is not English, Phase 7 dispatches a translator that
346
- writes a sidecar beside the report; `render-views` overlays it so only the
347
- human HTML is localized.
348
-
349
- Usage:
350
- okstra report-translate extract <path-to-final-report.data.json>
351
- okstra report-translate source --run-manifest <path>
352
- okstra report-translate write --run-manifest <path> --source-digest <sha256> --translations <markdown>
353
- okstra report-translate check-data --run-manifest <path>
354
- Write <stem>.translation-source.json — every pointer the report holds a
355
- translatable string at, paired with its English text. The translator
356
- fills in the values, so a sidecar cannot cite a path the report lacks.
357
-
358
- okstra report-translate check <path-to-final-report.i18n.<lang>.json>
359
- Resolve every pointer in a filled sidecar against the report it names
360
- and report what is still English. Exits non-zero on a pointer that
361
- resolves nowhere — the translator's own gate before it returns.
362
- """
363
-
364
-
365
- def _parser() -> argparse.ArgumentParser:
366
- parser = argparse.ArgumentParser(
367
- epilog=_CLI_EPILOG,
368
- formatter_class=argparse.RawDescriptionHelpFormatter,
369
- prog="okstra report-translate",
370
- description="Build and verify the final-report translation sidecar.",
371
- )
372
- sub = parser.add_subparsers(dest="op", required=True)
373
-
374
- extract_cmd = sub.add_parser("extract", help="write the translator's work list")
375
- extract_cmd.add_argument("data", help="path to final-report-<type>-<seq>.data.json")
376
- extract_cmd.set_defaults(func=cmd_extract)
377
-
378
- source_view = sub.add_parser("source", help="render a fixed translation work list")
379
- source_view.add_argument("--run-manifest", required=True)
380
- source_view.set_defaults(func=cmd_source)
381
-
382
- write_cmd = sub.add_parser("write", help="publish translations from T-NNN blocks")
383
- write_cmd.add_argument("--run-manifest", required=True)
384
- write_cmd.add_argument("--source-digest", required=True)
385
- write_cmd.add_argument("--translations", required=True)
386
- write_cmd.set_defaults(func=cmd_write)
387
-
388
- check_data = sub.add_parser("check-data", help="verify the derived sidecar")
389
- check_data.add_argument("--run-manifest", required=True)
390
- check_data.set_defaults(func=cmd_check_data)
391
-
392
- check_cmd = sub.add_parser("check", help="verify a filled sidecar against its report")
393
- check_cmd.add_argument("sidecar", help="path to final-report-<type>-<seq>.i18n.<lang>.json")
394
- check_cmd.set_defaults(func=cmd_check)
395
- return parser
396
-
397
-
398
- def main(argv: list[str] | None = None) -> int:
399
- args = _parser().parse_args(argv)
400
- return int(args.func(args))
401
-
402
-
403
- if __name__ == "__main__":
404
- raise SystemExit(main())
@@ -1,32 +0,0 @@
1
- {
2
- "schemaVersion": "1.0",
3
- "id": "translator",
4
- "roleId": "translator",
5
- "responsibilities": [
6
- "Translate only the designated sidecar into the requested language as a faithful technical translator, never as an editor of the underlying decision."
7
- ],
8
- "requiredConduct": [
9
- "Read the complete designated source, preserve identifiers, code, paths, commands, data shapes, headings, links, status tokens, normative strength, and uncertainty; use consistent project terminology; and verify that no source section or material qualification was omitted."
10
- ],
11
- "decisionPrinciples": [
12
- "Translate meaning rather than word order, producing natural target-language prose that carries the same precision, tone, uncertainty, and operational force as the source. Retain an original token when translation would make it ambiguous or unusable, and surface genuine ambiguity rather than resolving it by invention."
13
- ],
14
- "authorityAndBoundaries": [
15
- "Write only the assigned translation sidecar. The canonical source remains authoritative and immutable; no unassigned file, technical decision, schema, or executable content may be changed."
16
- ],
17
- "evidenceStandards": [
18
- "The translated structure must map completely to the source structure. Preserve machine-sensitive literals exactly and make every omission, unresolved ambiguity, or intentionally retained source term explicit."
19
- ],
20
- "collaborationContract": [
21
- "Return source ambiguity to the lead or designated owner without editing the source. Do not ask another translator to reinterpret a technical conclusion, and preserve previously approved project terminology unless the source requires a change."
22
- ],
23
- "completionCriteria": [
24
- "Every source section has a meaning-equivalent target section, technical literals and links remain usable, terminology is consistent, natural-language quality has been reviewed, and no new analysis or conclusion has entered the sidecar."
25
- ],
26
- "prohibitions": [
27
- "Do not edit the source of truth, translate unassigned files, add analysis, omit inconvenient qualifications, weaken or strengthen normative language, change a technical conclusion, or localize code and identifiers that must remain exact."
28
- ],
29
- "blockedStateReporting": [
30
- "Name the ambiguous or untranslatable source passage, explain the competing interpretations and affected output, preserve the passage unchanged where safe, and wait for the responsible owner to resolve it."
31
- ]
32
- }