okstra 0.193.0 → 0.195.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/dist/commands/lifecycle/config.mjs +7 -6
- package/dist/commands/lifecycle/config.mjs.map +1 -1
- package/docs/architecture.md +1 -1
- package/docs/cli.md +2 -2
- package/docs/for-ai/skills/okstra-setup.md +1 -1
- package/docs/project-structure-overview.md +2 -2
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/translator-worker.md +1 -1
- package/runtime/bin/okstra-inject-report-index.py +3 -4
- package/runtime/bin/okstra-report-translate.py +2 -60
- package/runtime/prompts/lead/okstra-lead-contract.md +2 -2
- package/runtime/prompts/lead/plan-body-verification.md +1 -1
- package/runtime/prompts/lead/report-writer.md +8 -9
- package/runtime/python/okstra_ctl/i18n.py +11 -6
- package/runtime/python/okstra_ctl/plan_items_cli.py +48 -2
- package/runtime/python/okstra_ctl/render_final_report.py +5 -9
- package/runtime/python/okstra_ctl/report_finalize.py +9 -31
- package/runtime/python/okstra_ctl/report_html/render.py +1 -11
- package/runtime/python/okstra_ctl/report_language.py +17 -32
- package/runtime/python/okstra_ctl/report_translation.py +0 -51
- package/runtime/python/okstra_ctl/report_translation_dispatch.py +2 -6
- package/runtime/python/okstra_ctl/session_transcript.py +33 -3
- package/runtime/skills/okstra-setup/SKILL.md +3 -2
- package/runtime/skills/okstra-setup/references/project-config.md +6 -7
- package/runtime/validators/validate-run.py +6 -32
|
@@ -16,9 +16,10 @@ Supported keys (CLI alias -> JSON field):
|
|
|
16
16
|
only) relative to <project-root>.
|
|
17
17
|
|
|
18
18
|
report-language -> reportLanguage
|
|
19
|
-
Final-report language
|
|
20
|
-
|
|
21
|
-
the
|
|
19
|
+
Final-report language as a language tag
|
|
20
|
+
(en, ko, fr, pt-BR, ...). The Phase 7 translator
|
|
21
|
+
translates the human HTML into it; the data.json
|
|
22
|
+
stays English.
|
|
22
23
|
|
|
23
24
|
Usage:
|
|
24
25
|
okstra config get <key> [--scope project|global|all]
|
|
@@ -66,9 +67,9 @@ const KEYS = {
|
|
|
66
67
|
jsonField: "reportLanguage",
|
|
67
68
|
scopes: ["project", "global"],
|
|
68
69
|
validate(value) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
if (typeof value !== "string" || !/^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$/.test(value)) {
|
|
71
|
+
return ("value must be a language tag such as en, ko, fr or pt-BR " +
|
|
72
|
+
`(got ${JSON.stringify(value)})`);
|
|
72
73
|
}
|
|
73
74
|
return null;
|
|
74
75
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.mjs","sourceRoot":"","sources":["../../../src/commands/lifecycle/config.mts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"config.mjs","sourceRoot":"","sources":["../../../src/commands/lifecycle/config.mts"],"names":[],"mappings":"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"}
|
package/docs/architecture.md
CHANGED
|
@@ -863,7 +863,7 @@ The manifest-provided `lead-events-*.jsonl` file is the canonical record for str
|
|
|
863
863
|
|
|
864
864
|
`activityContractVersion: 1` is an interpretation version for new `implementation-planning` artifacts. A run without that field remains a historical run and does not require activity events or an `agentActivity[]` projection.
|
|
865
865
|
|
|
866
|
-
The shared `okstra report-finalize` entrypoint reads canonical activity before translation
|
|
866
|
+
The shared `okstra report-finalize` entrypoint reads canonical activity before translation. Under contract v3 its in-process `project-activity` step assembles the report, filtering events by run identity and validating activity ID order before `agentActivity[]` is published. A schema-invalid composed record is still published so `validate-run` can scan it; the step itself fails. A historical v2 manifest retains the in-place projection path. A failed Phase 7 step does not skip later checks: `validate-run` still runs, and only `record-group-memory` and `teardown-stages` are skipped. For a non-English report, the `translate` step directly before `render-views` materializes and dispatches the translator worker itself (`okstra_ctl.report_translation_dispatch`) and requires the `*.i18n.<lang>.json` sidecar; the lead no longer splits the sequence around a manual dispatch. Conformance compares the resulting `agentActivity[]` IDs, order, and core fields with the canonical events for every lead host.
|
|
867
867
|
|
|
868
868
|
Approval blockers use `open`, `answered`, `resolved`, and `obsolete`. `open` blocks until the user judges. `answered` with `accept-risk` / `select` / `answer` does not block approval or the next phase; the DISAGREE votes stay on the plan item as evidence. A response sidecar with a proceeding disposition unblocks the same way. `request-revision` and `reject` still withhold the next phase until this report's `supersessionLedger` records that the answer was incorporated (`superseded` or `no-dependent-statement`).
|
|
869
869
|
|
package/docs/cli.md
CHANGED
|
@@ -801,7 +801,7 @@ The `okstra` Node CLI (`bin/okstra`) provides both installer/admin commands and
|
|
|
801
801
|
| `okstra plan-items derivations --data <data.json> --response <user-response sidecar> [--clarification C-NNN]` | List the plan statements an answered clarification may have falsified. Extracts the symbols, paths, and ids the answer names (backticked spans plus `R-001` / `DEV-10174`-style ids) and reports every string in the plan body that mentions one, as a JSON pointer plus excerpt. Advisory: it says where a decision's subject is mentioned, never which mentions are now wrong — the supersession rule (`prompts/profiles/_common-contract.md`) requires the author to enumerate before editing, and this supplies the enumeration |
|
|
802
802
|
| `okstra plan-items <prepare\|prompt\|validate-prepared> --run-manifest <path> …` | Bind the implementation-planning verification queue to the run manifest. `prepare` extracts the exact queue from `--narrative` and, when `designPreparation.mode` is `no-design-inputs` and the Stage Map has one row, flips `convergence.planBodyVerification.gating` to `false` (stdout `Gating`). `prompt` emits its fixed lossless view, ending with the parser-facing `## Response format` block so the block reaches every verifier with the queue; `validate-prepared` proves the prepared queue still matches the narrative. With `--state <plan-body-verification.json>` the round is a re-verification: `prepare` also carries each queued item's recorded votes and `selfFixNote` into the envelope as `priorRounds`, `prompt` renders them as that item's `**Prior round dissent**` block behind a re-verification preamble, and `validate-prepared` re-derives the carry and rejects an envelope that dropped it. Python resolves the convergence-owned state path, so model callers never choose it. |
|
|
803
803
|
| `okstra plan-items seed --narrative <report-narrative.md> --state <plan-body-verification.json> [--prior-state <previous plan-body-verification.json>]` | Create the convergence-owned `planBodyVerification.planItems[]` rows every verdict lands in, from the same deterministic extraction `extract` uses. The historical v2 form is `--data <data.json>`. Idempotent by id: an existing row keeps its verdicts and carried fields. Reports `seeded` / `existing` counts. `--prior-state` carries the previous **run**'s verdicts into this one: a newly seeded item whose `contentHash` equals that run's `verifiedContentHash` for the same id inherits its `verdicts[]` and is tagged `carriedForwardFromSeq` with the seq read off the prior filename, so round 1 does not re-judge text nobody changed. A matching id alone never carries — `P-*` ids are positional and shift. It requires `--state`, refuses a prior state whose task root differs from the one `--state` lives under (the state file carries no task identity, so its path is the only identity there is), and when it carries anything it rewrites the sibling `plan-items-*.json` `dispatchQueue` the way `incremental-carry` does. Adds `carried` / `carriedForwardFromSeq` to the reported counts. |
|
|
804
|
-
| `okstra plan-items apply-verdicts --state <plan-body-verification.json> --result <worker-id>=<result.md>… --round <N>` | Read each worker's Markdown verdict directly, validate every current `P-*` id, reject duplicate worker submissions, and overwrite that round's stored verdicts. The historical `--verdicts <file>` form remains automation compatibility only. Without `--append` every recorded verdict row of the queued items is replaced; when a row belongs to a round `complete-round` never closed, the command refuses before writing and names the `complete-round --round <M>` to run first. `--discard-open-rounds` replaces anyway — the recovery path when those rounds are being re-applied from their result files in order (the discarded rows are printed). |
|
|
804
|
+
| `okstra plan-items apply-verdicts --state <plan-body-verification.json> --result <worker-id>=<result.md>… --round <N>` | Read each worker's Markdown verdict directly, validate every current `P-*` id, reject duplicate worker submissions, and overwrite that round's stored verdicts. The historical `--verdicts <file>` form remains automation compatibility only. Without `--append` every recorded verdict row of the queued items is replaced; when a row belongs to a round `complete-round` never closed, the command refuses before writing and names the `complete-round --round <M>` to run first. `--discard-open-rounds` replaces anyway — the recovery path when those rounds are being re-applied from their result files in order (the discarded rows are printed); it also restores `dispatchQueue` to the items those result files answer, since the persisted queue belongs to the latest round and an earlier round's verdicts would otherwise be refused as outside it. |
|
|
805
805
|
| `okstra plan-items complete-round --state <plan-body-verification.json> --run-manifest <current-run-manifest.json> --round <N> [--self-fix-note <item-id>=<markdown-file>]… [--self-fix-group <cause-file>=<item-id>[,<item-id>...]]… [--self-fix-stop-reason <all-resolved\|no-progress\|max-rounds-reached>]` | After `plan-verify` succeeds, atomically derive and record the round's per-item votes, gate result, participant counts from the actual assigned roster, immutable completion time, convergence history, and optional self-fix notes/groups read from Markdown files. `--self-fix-group` requires `--self-fix-stop-reason` — there is no default. `--self-fix-stop-reason` alone records a stop for a round that rewrote nothing and leaves `selfFixGroups` / `selfFixRoundsApplied` untouched. Models do not write the state JSON. Stdout also carries `nextDispatch`. |
|
|
806
806
|
| `okstra plan-items next-dispatch --state <plan-body-verification.json> [--run-manifest <path>]` | After `apply-verdicts`, decide whether this round opens a worker batch. `kind: none` — missing-dependency `UNVERIFIABLE` only, no new batch. `kind: worker-correction` — re-prompt only those workers; peers stay idle. `kind: critic-tie` — unsettled analyser 1-1 on a run that rostered a critic, `critic-worker` on those item ids only. `kind: user-decision` — the same 1-1 on a run with no critic rostered: no in-band vote can break it, so open one `okstra approval-decision open` per item (classification `noncritical-dissent`) plus its `## 1. Clarification Items` row and dispatch no further verification for them. `--run-manifest` is what tells the two apart (`invocationAssignments` `critic/*`); without it the answer stays `critic-tie`. A missing path is never environment-unverifiable. |
|
|
807
807
|
| `okstra plan-items correction-prompt --state <plan-body-verification.json> --run-manifest <path> --worker <id>` | Emit the planning-time environment-gap paragraph, then the assigned queue. The environment exception is first. Exits 2 unless `next-dispatch` named that worker as a blanket-UNVERIFIABLE correction target. |
|
|
@@ -847,7 +847,7 @@ The `okstra` Node CLI (`bin/okstra`) provides both installer/admin commands and
|
|
|
847
847
|
| `okstra approval-decision <open\|resolve\|carry> --ledger <approval-decisions.json> …` | Write the lead-owned clarification and approval ledger. `open` validates classification-specific dispositions and complete option fields, `resolve` requires real `A-NNN` check references, and `carry` keeps prior resolved decisions outside the active clarification list. `carry --from-responses <instruction-set/clarification-response.md>` is the source of truth for an answer given in an earlier run: the bundle is task-level and cumulative, each response section names the report that posed the question, and `--clarification-id` repeats to carry several ids in one call. `carry --source-ledger` remains for a prior run's ledger that is still on disk and needs `--source-run-ref`. Prepare seeds `carriedDecisions[]` itself when it creates a run's ledger from a `--clarification-response` that names a report record — every row that record answered or resolved, plus rows its user-responses sidecars answered (`scripts/okstra_ctl/approval_decisions.py` `seed_carried_decisions`) — so `carry` is for ids that record does not answer. |
|
|
848
848
|
| `okstra design-snapshot --narrative <report-narrative.md> --output <design-preparation.json>` | Detect implementation-planning design surfaces and write the detector-owned snapshot consumed by final report assembly. |
|
|
849
849
|
| `okstra plan-verify --narrative <report-narrative.md> --state <plan-body-verification.json>` | Recompute the plan-body gate from the convergence-owned state before `data.json` publication. `--report <historical-data.json>` remains the v2 reader. |
|
|
850
|
-
| `okstra report-finalize --project-root <dir> --run-manifest <path> --report <final-report.md>` | Run Phase 7 in the manifest's contract order. Contract v3 collects usage into team state, assembles all single-owner inputs into `data.json` once,
|
|
850
|
+
| `okstra report-finalize --project-root <dir> --run-manifest <path> --report <final-report.md>` | Run Phase 7 in the manifest's contract order. Contract v3 collects usage into team state, assembles all single-owner inputs into `data.json` once, translates (`translate`: for a non-English `reportLanguage` it materializes and dispatches the translator worker unless the `*.i18n.<lang>.json` sidecar already exists, and fails when the worker leaves none), then renders with that sidecar overlaid, spawns follow-ups, validates, records the run's conclusion and the group's start order into the task-group's `group-context.md` (`record-group-memory`, creating the file when absent), and tears down eligible stage worktrees. Contract v2 retains its historical in-place projection sequence as a read-only compatibility path. A failed step still runs every later check through `validate-run`; `record-group-memory` and `teardown-stages` are skipped so a failed run neither hands an unvalidated conclusion to sibling tasks nor reclaims worktrees. The result carries `nextInGroup` (the first task in start order not yet started) and, for a terminal pointer, `nextCommand` closes on starting it from its brief. Reports each step and prints the ordered `--only` recovery tail from the earliest failure. This is the shared path for every lead adapter. |
|
|
851
851
|
| `okstra render-views <final-report.data.json\|final-report.md>` | The Phase 7 `render-views` step, runnable on its own. Schema v2 data is rendered directly, and schema v3 data uses the same always-generated, task-specific human HTML path. The full reading copy uses `templates/reports/final-report-v2.template.md` and is rendered on demand with `okstra render-final-report`. Passing the Markdown sibling locates the same data.json. Schema v1 and quick reports keep the legacy conditional renderer. The Node wrapper calls `scripts/okstra-render-report-views.py`; `validators/validate-report-views.py` verifies source/schema/template digests, required human fields, form controls, external assets, diagram/table ID parity, Response ID parity, and that every in-page `href="#…"` lands on an element of the page. For a non-English report the command prints two counts: `translated N string(s) into <lang> (M left in English, K unresolved)` from the sidecar overlay, and `rendered R line(s) still in English on the <lang> page` from the written page itself — the second sees fields the extractor does not offer, so `M = 0` with `R > 0` means a reader-facing key is missing from `PROSE_KEYS`. |
|
|
852
852
|
| `okstra design-prep <list\|show\|write>` | Review AI-prepared implementation design requests, inspect their effective confirmed response, or append a confirmed user/wizard response without editing the planning report |
|
|
853
853
|
| `okstra wizard <init\|step\|render-args\|confirmation\|outcome> --state-file <path>` | Interactive input state machine for okstra-run, implemented by `okstra_ctl.wizard`. Seed a state file with `init`, then repeatedly call `step --answer <val>` to receive the next `Prompt` JSON. `--answer` is **required**; use `--no-submit` to peek at the next prompt without submitting a response. A `pick` with more choices than the host picker can display keeps `kind: "pick"` but adds `presentation: "numbered-text"`; render every option as a numbered Markdown list and submit the user's 1-based number, exact value, or exact label. Invalid, out-of-range, and ambiguous answers re-prompt without dropping choices. `render-args` returns the final `render-bundle` argument map, and `confirmation` returns the user echo block. On a completed wizard, `outcome` returns `renderArgs`, `persistActions`, and `confirmationText` together; project/global release-handoff PR-template persistence appears as `persistActions[].command == "config.set"`. For an `implementation` task type, `stage_pick` follows `approved_plan_pick` and selects the stage before `executor_pick`. The brief step appears only for entry task types—requirements-discovery, error-analysis, improvement-discovery, project-analysis, feature-analysis, and change-impact-analysis. Analysis inputs use `feature_evidence_pick` / `feature_evidence`, `project_evidence_pick` / `project_evidence`, and `analysis_target_pick` / `analysis_target`; a revision-requested report prioritizes its same-task, same-type rerun. Downstream lifecycle phases automatically carry the manifest brief, with a three-option `brief_carry` fallback when none is registered; `release-handoff` has no brief and enters multi-select `handoff_stage_pick` for eligible stage groups or the whole task |
|
|
@@ -104,7 +104,7 @@ Optional settings:
|
|
|
104
104
|
a user-owned advisory when the environment is unavailable or the result is
|
|
105
105
|
non-PASS.
|
|
106
106
|
- PR body template: `okstra config set pr-template-path "<path>" --scope project|global`
|
|
107
|
-
- final report language: `okstra config set report-language <
|
|
107
|
+
- final report language: `okstra config set report-language <language-tag> --scope project` (`en`, `ko`, `fr`, `pt-BR`, …; default `en`)
|
|
108
108
|
- `architecture.style`: the project's declared architecture — `hexagonal`,
|
|
109
109
|
`layered`, or `none` (default `none` when absent, unrecognized, or
|
|
110
110
|
unreadable). `okstra setup` never writes it; hand-add it to `project.json`
|
|
@@ -345,7 +345,7 @@ Important modules:
|
|
|
345
345
|
| `lead_events.py` | Structured JSONL events emitted by artifact-accounted lead runtimes. Its locked append path assigns monotonic `A-NNN` identifiers to activity events in the same canonical event file. |
|
|
346
346
|
| `worker_prompt_headers.py` | shared rendering of phase-aware worker prompt anchors (`worker_prompt_headers`): coding-preflight only for implementation and compact target identity for final-verification |
|
|
347
347
|
| `worker_prompt_body.py` | provider-neutral initial analysis body/input renderer shared by Codex and external/team dispatch paths |
|
|
348
|
-
| `report_language.py` | report-writer `**Report Language:**` resolution (`resolve_report_language`) — precedence project config → global config →
|
|
348
|
+
| `report_language.py` | report-writer `**Report Language:**` resolution (`resolve_report_language`) — precedence project config → global config → `en`; the value is a language tag the Phase 7 translator translates into, shared by both dispatchers so the stamped language does not depend on which dispatch path ran |
|
|
349
349
|
| `worker_prompt_policy.py` | `PromptPlan` generating SSOT — resolves functional audience, equality group, packet-only input, coding-preflight eligibility, required headers, and size limits without consulting provider/model identity |
|
|
350
350
|
| `worker_prompt_contract.py` | deterministic cross-task initial-prompt validator and normalized cross-worker equality SSOT, reused by dispatch adapters and the Phase 7 persisted-artifact validator |
|
|
351
351
|
| `initial_prompt_materialization.py` | sole owner of roster-derived initial prompt rendering, request compatibility checks, contract validation, and immutable create-if-absent publication; exposes `materialize_initial_prompts(InitialPromptMaterializationRequest) -> tuple[Path, ...]` |
|
|
@@ -360,7 +360,7 @@ Important modules:
|
|
|
360
360
|
| `scope_provenance.py` | single source of truth for the scope-provenance grammar every phase-emitted requirement must declare, shared by `validators/validate-run.py` and `validators/validate_fanout.py` so the planning report and fan-out packets cannot drift |
|
|
361
361
|
| `worker_artifact_paths.py` | canonical worker artifact path derivation (e.g. `audit_sidecar_rel` inserts `-audit-` after the first `-worker-` token), so dispatch and validation agree on non-canonical-path rejection |
|
|
362
362
|
| `report_translation_dispatch.py` | Phase 7 `translate` step — for a non-English `reportLanguage` and no `*.i18n.<lang>.json` sidecar, reuses or materializes this run's translator reservation (`agent-prompt materialize --audience translator` in-process, instruction file under `state/`), runs the CLI-wrapper dispatch, and succeeds only when the sidecar exists afterwards. Replaces the manual lead sequence that was skipped in practice |
|
|
363
|
-
| `report_finalize.py` | Phase 7 post-report sequence **SSOT** — runs `
|
|
363
|
+
| `report_finalize.py` | Phase 7 post-report sequence **SSOT** — runs `translate` → `token-usage` → `render-views` → `spawn-followups` → `validate-run` → `record-group-memory` → `teardown-stages` in that load-bearing order. A non-zero exit still runs every later check through `validate-run` and names the earliest failure; `record-group-memory` (this run's conclusion into the task-group's `group-context.md`, plus `nextInGroup` for the closeout) and `teardown-stages` are skipped when any earlier step failed. Both lead paths converge here: the Codex adapter calls it in-process (`codex_dispatch`), a Claude-led run reaches it through `okstra report-finalize`. Neither reimplements the sequence |
|
|
364
364
|
| `wrapper_status.py` | worker wrapper status sidecar reader — the host-side reader of the sidecar `worker_runner.py` writes. `is_terminal` is the one question it answers for the dispatch record and the pane reclaim: does `stage` read `exited` |
|
|
365
365
|
| `worker_runner.py` | runs one worker CLI and records what happened — shared by every provider entrypoint. Owns the `selectors` pump over the child's streams, the stream-arrival idle watchdog (`killpg` on breach), the run-wide progress cap on the log copy, and the status sidecar's whole life. A run that dies after launch still closes its sidecar, so `worker_liveness` never reads a dead worker as running |
|
|
366
366
|
| `session_transcript.py` | worker session transcript — one line per event (time, speaker, body) with a run-wide progress-line cap (`LOG_LINE_CAP`, elision notice) so a single-file dispatch's tool echo cannot dominate the project's `.okstra/` bytes; the fixed shape lets a later lead write share the same file |
|
package/package.json
CHANGED
package/runtime/BUILD.json
CHANGED
|
@@ -24,7 +24,7 @@ roster.
|
|
|
24
24
|
|
|
25
25
|
## Procedure
|
|
26
26
|
|
|
27
|
-
1. Read your dispatch prompt's `**Report Language:**` header. It is
|
|
27
|
+
1. Read your dispatch prompt's `**Report Language:**` header. It is a language tag (`ko`, `fr`, `pt-BR`, …); translate into that language.
|
|
28
28
|
2. Build your work list:
|
|
29
29
|
|
|
30
30
|
```bash
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
Usage:
|
|
5
5
|
python3 scripts/okstra-inject-report-index.py \\
|
|
6
6
|
<final-report.md> \\
|
|
7
|
-
[--report-language
|
|
7
|
+
[--report-language <language-tag>]
|
|
8
8
|
|
|
9
9
|
Adds the top-of-report Index (section list + ID index) and `<a id="...">`
|
|
10
10
|
scroll anchors to a markdown report that was authored *free-form* rather
|
|
@@ -26,7 +26,6 @@ from okstra_bootstrap import prefer_colocated_modules # noqa: E402
|
|
|
26
26
|
|
|
27
27
|
prefer_colocated_modules(__file__, "okstra_ctl/render_final_report.py")
|
|
28
28
|
|
|
29
|
-
from okstra_ctl.i18n import SUPPORTED_LANGS # noqa: E402
|
|
30
29
|
from okstra_ctl.render_final_report import ( # noqa: E402
|
|
31
30
|
FinalReportRenderError,
|
|
32
31
|
inject_index_into_file,
|
|
@@ -45,9 +44,9 @@ def main(argv: list[str]) -> int:
|
|
|
45
44
|
)
|
|
46
45
|
parser.add_argument(
|
|
47
46
|
"--report-language",
|
|
48
|
-
choices=list(SUPPORTED_LANGS),
|
|
49
47
|
default="en",
|
|
50
|
-
help="Language for the index labels
|
|
48
|
+
help="Language tag for the index labels; a language without its own "
|
|
49
|
+
"dictionary gets the English labels. Default: en.",
|
|
51
50
|
)
|
|
52
51
|
args = parser.parse_args(argv)
|
|
53
52
|
|
|
@@ -8,10 +8,7 @@ Usage:
|
|
|
8
8
|
``extract`` writes the translator's work list — every pointer the report holds
|
|
9
9
|
a translatable string at, paired with the English text. The translator fills
|
|
10
10
|
in the values rather than authoring pointers, so a sidecar cannot cite a path
|
|
11
|
-
the document does not have.
|
|
12
|
-
Korean-prose limit: the work list would pair every pointer with target-language
|
|
13
|
-
text, and the translator would spend a full pass translating a document into
|
|
14
|
-
the language it is already in.
|
|
11
|
+
the document does not have.
|
|
15
12
|
|
|
16
13
|
``check`` is the translator's own gate before it returns: it resolves every
|
|
17
14
|
pointer in the sidecar against the report and reports what is still English.
|
|
@@ -35,12 +32,7 @@ from okstra_bootstrap import prefer_colocated_modules # noqa: E402
|
|
|
35
32
|
|
|
36
33
|
prefer_colocated_modules(__file__, "okstra_ctl/report_translation.py")
|
|
37
34
|
|
|
38
|
-
from okstra_ctl.report_translation import
|
|
39
|
-
HANGUL_PROSE_LIMIT,
|
|
40
|
-
extract,
|
|
41
|
-
hangul_share,
|
|
42
|
-
overlay,
|
|
43
|
-
)
|
|
35
|
+
from okstra_ctl.report_translation import extract, overlay # noqa: E402
|
|
44
36
|
from okstra_ctl.final_report_paths import ( # noqa: E402
|
|
45
37
|
translation_sidecar_path,
|
|
46
38
|
translation_source_path,
|
|
@@ -118,31 +110,9 @@ def _validate_source_payload(
|
|
|
118
110
|
)
|
|
119
111
|
|
|
120
112
|
|
|
121
|
-
def _english_source_failure(data_path: Path, data: dict) -> str | None:
|
|
122
|
-
"""The Korean-prose message for *data*, or None when it reads as English."""
|
|
123
|
-
share, _ = hangul_share(data)
|
|
124
|
-
if share < HANGUL_PROSE_LIMIT:
|
|
125
|
-
return None
|
|
126
|
-
return (
|
|
127
|
-
f"error: {data_path.name} was authored in Korean "
|
|
128
|
-
f"({share:.0%} of its prose, limit {HANGUL_PROSE_LIMIT:.0%}). "
|
|
129
|
-
"The data.json is the English SSOT every later phase reads; the "
|
|
130
|
-
"report language selects the human HTML's language and is served "
|
|
131
|
-
"by the Phase 7 translator, not by authoring the SSOT in it.\n"
|
|
132
|
-
)
|
|
133
|
-
|
|
134
|
-
|
|
135
113
|
def cmd_extract(args: argparse.Namespace) -> int:
|
|
136
114
|
data_path = Path(args.data).resolve()
|
|
137
115
|
data = _load(data_path)
|
|
138
|
-
# Refuse before building the work list. Extracting from a Korean SSOT
|
|
139
|
-
# produces a translation from the target language into itself: a
|
|
140
|
-
# full-cost artifact whose English column is not English, discovered
|
|
141
|
-
# only later when `check-source` fails the finalize step.
|
|
142
|
-
failure = _english_source_failure(data_path, data)
|
|
143
|
-
if failure is not None:
|
|
144
|
-
sys.stderr.write(failure)
|
|
145
|
-
return 1
|
|
146
116
|
strings = extract(data)
|
|
147
117
|
out_path = translation_source_path(data_path)
|
|
148
118
|
lang = str((data.get("meta") or {}).get("reportLanguage") or "")
|
|
@@ -171,10 +141,6 @@ def cmd_source(args: argparse.Namespace) -> int:
|
|
|
171
141
|
authority, data_path = _translation_authority(Path(args.run_manifest))
|
|
172
142
|
snapshot = _report_snapshot(data_path)
|
|
173
143
|
data = snapshot.value
|
|
174
|
-
failure = _english_source_failure(data_path, data)
|
|
175
|
-
if failure is not None:
|
|
176
|
-
sys.stderr.write(failure)
|
|
177
|
-
return 1
|
|
178
144
|
payload = _source_payload(authority, data_path, snapshot.raw_bytes, data)
|
|
179
145
|
out_path = translation_source_path(data_path)
|
|
180
146
|
if out_path.is_symlink():
|
|
@@ -352,24 +318,6 @@ def _check_sidecar(sidecar_file: Path) -> tuple[dict, int]:
|
|
|
352
318
|
return payload, 0
|
|
353
319
|
|
|
354
320
|
|
|
355
|
-
def cmd_check_source(args: argparse.Namespace) -> int:
|
|
356
|
-
data_path = Path(args.data).resolve()
|
|
357
|
-
data = _load(data_path)
|
|
358
|
-
share, length = hangul_share(data)
|
|
359
|
-
failure = _english_source_failure(data_path, data)
|
|
360
|
-
payload = {
|
|
361
|
-
"ok": failure is None,
|
|
362
|
-
"hangulShare": round(share, 4),
|
|
363
|
-
"limit": HANGUL_PROSE_LIMIT,
|
|
364
|
-
"proseChars": length,
|
|
365
|
-
}
|
|
366
|
-
print(json.dumps(payload, ensure_ascii=False))
|
|
367
|
-
if failure is not None:
|
|
368
|
-
sys.stderr.write(failure)
|
|
369
|
-
return 1
|
|
370
|
-
return 0
|
|
371
|
-
|
|
372
|
-
|
|
373
321
|
_CLI_EPILOG = r"""A thin spawn shim over `scripts/okstra-report-translate.py` (installed at
|
|
374
322
|
`$HOME/.okstra/bin/okstra-report-translate.py`).
|
|
375
323
|
|
|
@@ -424,12 +372,6 @@ def _parser() -> argparse.ArgumentParser:
|
|
|
424
372
|
check_cmd = sub.add_parser("check", help="verify a filled sidecar against its report")
|
|
425
373
|
check_cmd.add_argument("sidecar", help="path to final-report-<type>-<seq>.i18n.<lang>.json")
|
|
426
374
|
check_cmd.set_defaults(func=cmd_check)
|
|
427
|
-
|
|
428
|
-
source_cmd = sub.add_parser(
|
|
429
|
-
"check-source", help="verify the data.json itself was authored in English"
|
|
430
|
-
)
|
|
431
|
-
source_cmd.add_argument("data", help="path to final-report-<type>-<seq>.data.json")
|
|
432
|
-
source_cmd.set_defaults(func=cmd_check_source)
|
|
433
375
|
return parser
|
|
434
376
|
|
|
435
377
|
|
|
@@ -464,8 +464,8 @@ The detailed persistence sequence lives in [report-writer](./report-writer.md).
|
|
|
464
464
|
|
|
465
465
|
Order of operations:
|
|
466
466
|
|
|
467
|
-
1. Run `okstra report-finalize ...`. Contract v3 collects usage, assembles the role-owned inputs into `data.json` once,
|
|
468
|
-
2. When `meta.reportLanguage` is not `en`, the same call dispatches the translator: its `translate` step (
|
|
467
|
+
1. Run `okstra report-finalize ...`. Contract v3 collects usage, assembles the role-owned inputs into `data.json` once, renders views, persists follow-ups, validates the run, records this run's conclusion into the task-group's `group-context.md` for the group's sibling tasks, and performs eligible teardown in order. When the task's pointer is terminal and the group has a task not yet started, the result's `nextInGroup` names it and `nextCommand` closes on starting it from its brief — the group's start order is the brief ordinal; the briefs' Related Task Graph edges are quoted as `waits for` and do not reorder it.
|
|
468
|
+
2. When `meta.reportLanguage` is not `en`, the same call dispatches the translator: its `translate` step (directly before `render-views`) materializes the translator prompt when this run has no undispatched reservation, runs the CLI-wrapper dispatch, and requires the `*.i18n.<lang>.json` sidecar. Do not dispatch the translator by hand or split the sequence around it; if the step fails, clear the cause and resume with the `--only translate --only render-views …` hint the result prints (**Enforced:** `okstra_ctl.report_translation_dispatch`).
|
|
469
469
|
|
|
470
470
|
Keep the assigned worker prompt history paths stable in `team-state`, `run-manifest`, and `task-manifest`. Do not rewrite prompt artifacts to `/tmp` or omit prompt metadata for attempted workers.
|
|
471
471
|
|
|
@@ -427,7 +427,7 @@ round before any host or provider process starts.
|
|
|
427
427
|
- **Drop plan items whose element the round deleted.** A self-fix rewrite may remove a plan element (a validation check, a rollback row). `P-*` ids are positional, so a deletion shifts every later row and silently re-points surviving verdicts at their neighbours — and a verdict recorded against a removed element keeps blocking a gate while being unfindable in the plan, so reading the plan never reveals the cause. After each round, re-extract plan items with `okstra plan-items extract` and re-verify any item whose `subject` no longer matches; never carry the old vote forward across a shift. **Enforced:** `validators/validate-run.py` `_validate_verdicts_match_current_subjects` (re-pointing) and `_validate_plan_item_extraction_completeness` (dangling ids).
|
|
428
428
|
- **Classify each cause group before instructing it (BLOCKING).** A group is either an *authoring* defect — the plan says something wrong, incomplete, or self-contradictory, which self-fix owns — or a *citation* defect, where the plan points at an analysis artifact incorrectly. Only the first is self-fix work. For the second the finding already exists and already went through convergence, so the fix is to re-cite the converged artifact; instructing report-writer to re-derive the fact means the author reads the source material and produces a **finding that never went through convergence**, which the plan then carries as if it had. That is the role boundary the lead contract draws ("keep analysis, execution, verification, and report authoring responsibilities distinct; return defects to the role that owns them"), and report-writer is authoring-only by its own contract. `P-Req-*` items with breakage kind `f` are where this goes wrong most often: the question is usually whether a coverage row points correctly at something already measured, not whether the measurement is right. State the classification in the group's instruction so the author knows which of the two it is being asked to do.
|
|
429
429
|
- **A verdict older than the last self-fix is not a verdict unless the item's content is unchanged (BLOCKING).** A verdict cast in round 1 judged the text before the only automatic rewrite. Once that rewrite runs, a changed item's judgement is about a plan that no longer exists. `--round <N>` on `apply-verdicts` stamps each row and copies `contentHash` onto `verifiedContentHash`. `validators/validate-run.py` `_validate_verdict_rounds_outlive_self_fix` fails an in-scope item whose verdict round is at or before `selfFixRoundsApplied` **and** whose `contentHash` does not match `verifiedContentHash`. Matching hashes keep the prior verdict — that is what avoids a sweep round over unchanged stages. Deferred and observed items are out of the gate and do not need a post-self-fix verdict. **Enforced:** `_validate_verdict_rounds_outlive_self_fix`.
|
|
430
|
-
- Lead re-runs plan-body verification, then records each worker Markdown result through `okstra plan-items apply-verdicts --state <plan-body-verification.json> --result <worker>=<result.md> --round <N>`. Score the result with `okstra plan-verify --narrative <report-writer-narrative.md> --state <plan-body-verification.json>`, then call `okstra plan-items complete-round --state <plan-body-verification.json> --run-manifest <current-run-manifest.json> --round <N>`. These commands fail on an assigned item the worker left unanswered, on a verdict for an item outside the queue, and on a duplicate worker result. `apply-verdicts` without `--append` replaces every recorded row of the queued items, so it also refuses — before writing — when a row belongs to a round that `complete-round` never closed, naming the round to close first; the votes of a closed round live in `planItems[].rounds`. Skipping `complete-round` between rounds and applying the next one lost 19 items' round-1 votes (2026-09-09). `--discard-open-rounds` is only for re-applying the lost rounds from their result files in order. **Enforced:** `okstra_ctl.plan_items_cli._reject_uncompleted_round_loss`.
|
|
430
|
+
- Lead re-runs plan-body verification, then records each worker Markdown result through `okstra plan-items apply-verdicts --state <plan-body-verification.json> --result <worker>=<result.md> --round <N>`. Score the result with `okstra plan-verify --narrative <report-writer-narrative.md> --state <plan-body-verification.json>`, then call `okstra plan-items complete-round --state <plan-body-verification.json> --run-manifest <current-run-manifest.json> --round <N>`. These commands fail on an assigned item the worker left unanswered, on a verdict for an item outside the queue, and on a duplicate worker result. `apply-verdicts` without `--append` replaces every recorded row of the queued items, so it also refuses — before writing — when a row belongs to a round that `complete-round` never closed, naming the round to close first; the votes of a closed round live in `planItems[].rounds`. Skipping `complete-round` between rounds and applying the next one lost 19 items' round-1 votes (2026-09-09). `--discard-open-rounds` is only for re-applying the lost rounds from their result files in order: it also restores `dispatchQueue` to the items those result files answer, because the persisted queue is the latest round's and a verdict for an earlier, wider queue is otherwise refused as outside it (round 1 = 26 items, critic tie = 8, round 3 = 19 on that same run — only the 19 survived). Re-apply each lost round with the flag, `complete-round` it, then the next. **Enforced:** `okstra_ctl.plan_items_cli._reject_uncompleted_round_loss` and `_restore_queue_from_results`.
|
|
431
431
|
- For a self-fix, record the correction through the typed convergence command rather than writing `selfFixNote` or `selfFixGroups` JSON. A resolved item does not create a clarification.
|
|
432
432
|
- **Each round is a worker batch.** Before dispatching round N ≥ 2, reclaim the previous round's completed verifiers exactly as at any other batch boundary ([okstra-lead-contract](./okstra-lead-contract.md) "Run-scoped worker-resource lifecycle") and emit `PROGRESS: phase-batch-cleanup panes=<n>`, then announce the round with `PROGRESS: phase-5.5.9-plan-verify round=<N> items=<count>`. Saying a round will "reuse" the previous verifiers and then dispatching under fresh names leaves every prior round holding its panes — five rounds of that is what exhausts the pane budget and blocks the next dispatch. **Enforced:** `validators/validate_session_conformance.py` `_check_plan_verify_cleanup_checkpoints` requires both lines once the state file records two or more rounds.
|
|
433
433
|
- **Round completion.** A round is complete only after `okstra plan-verify` exits 0 and `okstra plan-items complete-round` succeeds. A round left with a non-zero exit carries its defect into the next round's inputs. Exit 0 with a non-empty `advisories[]` is a complete round: those findings are recorded, not round-blocking (step 5, §"`failures[]` carries only the blocking findings"). Report assembly and rendering occur only after the convergence state is terminal. **Enforced:** `validators/validate-run.py` `_validate_plan_body_state_rounds` requires one stored round per round number and a corresponding item vote.
|
|
@@ -123,23 +123,22 @@ For historical schema-v1 Markdown only, the following heading table remains a re
|
|
|
123
123
|
|
|
124
124
|
**Enforced:** `okstra_ctl.report_finalize.V3_STEP_ORDER` is the order — `report-finalize` runs the steps from that tuple, so the sequence cannot be reordered by a caller. Running the steps by hand is what this rule forbids, and that path is not reachable through the CLI.
|
|
125
125
|
|
|
126
|
-
Do not run the
|
|
126
|
+
Do not run the eight steps below manually. Invoke `okstra report-finalize`; contract 3.0 runs them in this order:
|
|
127
127
|
|
|
128
128
|
1. **`token-usage`** — collect usage into team state without touching the final record.
|
|
129
129
|
2. **`project-activity`** — report assembly validates every owner input and publishes the final record once.
|
|
130
|
-
3. **`
|
|
131
|
-
4. **`
|
|
132
|
-
5. **`
|
|
133
|
-
6. **`
|
|
134
|
-
7. **`
|
|
135
|
-
8. **`
|
|
136
|
-
9. **`teardown-stages`** — remove eligible stage worktrees after successful validation.
|
|
130
|
+
3. **`translate`** — for a non-English `reportLanguage`, materialize and dispatch the translator worker and require its `*.i18n.<lang>.json` sidecar; a no-op for English or when the sidecar already exists.
|
|
131
|
+
4. **`render-views`** — render the Markdown reading copy and human HTML, with the translation sidecar overlaid.
|
|
132
|
+
5. **`spawn-followups`** — materialize registered follow-up tasks.
|
|
133
|
+
6. **`validate-run`** — validate the record, views, run manifest, and team state.
|
|
134
|
+
7. **`record-group-memory`** — write this run's conclusion (headline, decisions, watch-outs, open follow-ups, record path, next phase) and the group's start order into the task-group's `group-context.md` okstra region, creating the file when the group has none; skipped, like teardown, when an earlier step failed. Sibling tasks read it as `## Task-Group Memory`.
|
|
135
|
+
8. **`teardown-stages`** — remove eligible stage worktrees after successful validation.
|
|
137
136
|
|
|
138
137
|
After `report-finalize` returns, the lead — not the report writer — closes the run with the launch prompt's User closeout: one command the user can run now.
|
|
139
138
|
|
|
140
139
|
### The translation sidecar: the `translate` step
|
|
141
140
|
|
|
142
|
-
`report-finalize` dispatches the translator itself. Its `translate` step runs
|
|
141
|
+
`report-finalize` dispatches the translator itself. Its `translate` step runs directly before `render-views` (which overlays the sidecar), and it is a no-op when `reportLanguage` is `en` or the `*.i18n.<lang>.json` sidecar already exists. When the sidecar is missing, the step reuses this run's undispatched translator reservation if the lead already materialized one, otherwise it materializes the prompt itself — instruction file `state/translator-instructions-<task-type>-<seq>.md` (kept when the lead wrote one), prompt `prompts/translator-worker-prompt-<task-type>-<seq>.md`, `--result worker-results/translator-translations-<task-type>-<seq>.md`, `--audit-source worker-results/translator-worker-<task-type>-<seq>.md`, invocation id `<task-type>-<seq>-translator` (`-r2`, `-r3` after a failed attempt) — then runs the CLI-wrapper dispatch, which records the dispatch and links the result. Do not run `agent-prompt materialize --audience translator` or `worker-dispatch --workers translator` by hand before `report-finalize`; the sequence used to be a manual lead step and was skipped in practice (2026-09-09, fontsninja-v3-site dev-10628-3: a `ko` run finalized in one call, zero translator reservations, English HTML). **Enforced:** `okstra_ctl.report_finalize.V3_STEP_ORDER` places the step; `okstra_ctl.report_translation_dispatch.translate_report` owns it; `_translator_job_from_reservation` in `scripts/okstra_ctl/dispatch_core.py` still refuses two undispatched reservations for one run, which only a hand-made second reservation produces.
|
|
143
142
|
|
|
144
143
|
The step succeeds only when the sidecar exists afterwards; a translator that exits 0 without publishing it fails the step. A failed `translate` does not stop the sequence: `render-views` still writes the view from the English body, `validate-run` records the missing sidecar as an advisory, and the result's resume hint starts at `--only translate --only render-views …` — run that once the cause (a host approval gate, an unavailable provider) is cleared rather than closing the run on an English view.
|
|
145
144
|
|
|
@@ -13,7 +13,7 @@ from typing import Any, Callable
|
|
|
13
13
|
|
|
14
14
|
from .json_boundary import JsonBoundaryError, load_owned_object
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
FALLBACK_LANG = "en"
|
|
17
17
|
DICTIONARY_REL = ("templates", "reports", "i18n")
|
|
18
18
|
# The human HTML has its own fixed strings — table headings, empty states,
|
|
19
19
|
# enum labels — that the AI-handoff Markdown never renders. Same loader, its
|
|
@@ -44,11 +44,16 @@ def _i18n_dir(rel: tuple[str, ...] = DICTIONARY_REL) -> Path:
|
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
def load_dictionary(lang: str, rel: tuple[str, ...] = DICTIONARY_REL) -> dict[str, Any]:
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
"""`<lang>.json` 이 있으면 그것, 없으면 영어 사전.
|
|
48
|
+
|
|
49
|
+
사전은 페이지 크롬(표 머리글·빈 상태·enum 라벨)의 고정 문자열이고 본문은
|
|
50
|
+
번역 사이드카가 덮는다. 사전이 없는 언어의 리포트는 본문은 그 언어, 크롬은
|
|
51
|
+
영어로 나온다 — 사전이 없다고 렌더를 거절하면 독자는 아무것도 못 받는다.
|
|
52
|
+
"""
|
|
53
|
+
directory = _i18n_dir(rel)
|
|
54
|
+
path = directory / f"{lang}.json"
|
|
55
|
+
if not path.is_file():
|
|
56
|
+
path = directory / f"{FALLBACK_LANG}.json"
|
|
52
57
|
try:
|
|
53
58
|
return load_owned_object(path, artifact="i18n dictionary")
|
|
54
59
|
except JsonBoundaryError as exc:
|
|
@@ -263,7 +263,9 @@ def _parser() -> argparse.ArgumentParser:
|
|
|
263
263
|
"--discard-open-rounds", action="store_true",
|
|
264
264
|
help="replace even the rows of a round that complete-round never "
|
|
265
265
|
"closed — the recovery path when those rows are being re-applied "
|
|
266
|
-
"from their result files in order; the discarded rows are listed"
|
|
266
|
+
"from their result files in order; the discarded rows are listed, "
|
|
267
|
+
"and dispatchQueue is restored to the items those result files "
|
|
268
|
+
"answer, since the persisted queue belongs to the latest round",
|
|
267
269
|
)
|
|
268
270
|
complete = commands.add_parser(
|
|
269
271
|
"complete-round",
|
|
@@ -1367,6 +1369,9 @@ def _apply_verdicts(args: argparse.Namespace) -> dict[str, Any]:
|
|
|
1367
1369
|
data["planBodyVerification"] if args.state is not None
|
|
1368
1370
|
else _planning(data)["planBodyVerification"]
|
|
1369
1371
|
)
|
|
1372
|
+
discard_open_rounds = bool(getattr(args, "discard_open_rounds", False))
|
|
1373
|
+
if discard_open_rounds and args.state is not None and args.result:
|
|
1374
|
+
_restore_queue_from_results(verification, args.result, recorded)
|
|
1370
1375
|
queue = verification.get("dispatchQueue") if isinstance(verification, Mapping) else None
|
|
1371
1376
|
assigned = (
|
|
1372
1377
|
{item_id for item_id in queue if isinstance(item_id, str)}
|
|
@@ -1399,7 +1404,7 @@ def _apply_verdicts(args: argparse.Namespace) -> dict[str, Any]:
|
|
|
1399
1404
|
if not append:
|
|
1400
1405
|
_reject_uncompleted_round_loss(
|
|
1401
1406
|
recorded, rows, data.get("roundHistory"), args.round_number, target,
|
|
1402
|
-
discard_open_rounds=
|
|
1407
|
+
discard_open_rounds=discard_open_rounds,
|
|
1403
1408
|
)
|
|
1404
1409
|
writer = _append_item_verdicts if append else _replace_item_verdicts
|
|
1405
1410
|
for item in recorded:
|
|
@@ -1459,6 +1464,47 @@ def _append_item_verdicts(
|
|
|
1459
1464
|
_remember_verified_hash(item)
|
|
1460
1465
|
|
|
1461
1466
|
|
|
1467
|
+
def _restore_queue_from_results(
|
|
1468
|
+
verification: Any,
|
|
1469
|
+
raw_results: list[str],
|
|
1470
|
+
recorded: Sequence[Mapping[str, Any]],
|
|
1471
|
+
) -> None:
|
|
1472
|
+
"""재적용하는 라운드의 큐를 그 라운드의 결과 파일이 답한 항목 집합으로 되돌린다.
|
|
1473
|
+
|
|
1474
|
+
`dispatchQueue` 는 값이 하나뿐이라 라운드마다 덮인다 — 라운드 1 이 26개,
|
|
1475
|
+
critic 동수 라운드가 8개, 라운드 3 이 19개였던 run 에서 상태에 남는 것은
|
|
1476
|
+
19개뿐이다. `apply-verdicts` 와 `complete-round` 는 둘 다 그 큐로 스코프하고,
|
|
1477
|
+
`_queue_for` 는 이미 두 번 전진한 해시로부터의 순수 계산이라 지난 큐를
|
|
1478
|
+
되살릴 명령이 없었다. 그래서 `--discard-open-rounds` 로 라운드 1 을 다시
|
|
1479
|
+
적용하면 큐 밖 id 라며 거절됐고, 복구는 상태 파일을 손으로 고쳐야만 됐다
|
|
1480
|
+
(실측 2026-09-09, `fontsninja-v3-site` dev-10627 planning 002).
|
|
1481
|
+
|
|
1482
|
+
결과 파일의 `### P-*` 블록 집합이 곧 그 라운드의 큐다 — 워커는 배정된 항목
|
|
1483
|
+
전부에 답해야 통과하고(`_worker_blocks`), 큐 밖 항목에는 답할 수 없었다.
|
|
1484
|
+
순서는 계획 항목 순서를 따른다. 계획에 없는 id 는 큐에 넣지 않으므로 뒤의
|
|
1485
|
+
`_worker_blocks` 가 그 id 를 이름하며 거절한다.
|
|
1486
|
+
"""
|
|
1487
|
+
if not isinstance(verification, dict):
|
|
1488
|
+
return
|
|
1489
|
+
answered: set[str] = set()
|
|
1490
|
+
for raw in raw_results:
|
|
1491
|
+
_worker, path = _split_result_arg(raw)
|
|
1492
|
+
try:
|
|
1493
|
+
answered |= set(parse_verdict_blocks(path.read_text(encoding="utf-8")))
|
|
1494
|
+
except (OSError, UnicodeError) as exc:
|
|
1495
|
+
raise PlanItemContractError(f"cannot read result {path}: {exc}") from exc
|
|
1496
|
+
restored = [
|
|
1497
|
+
str(item["id"]) for item in recorded
|
|
1498
|
+
if isinstance(item, Mapping) and item.get("id") in answered
|
|
1499
|
+
]
|
|
1500
|
+
verification["dispatchQueue"] = restored
|
|
1501
|
+
print(
|
|
1502
|
+
f"apply-verdicts: dispatchQueue restored from the result files "
|
|
1503
|
+
f"({len(restored)} items)",
|
|
1504
|
+
file=sys.stderr,
|
|
1505
|
+
)
|
|
1506
|
+
|
|
1507
|
+
|
|
1462
1508
|
def _reject_uncompleted_round_loss(
|
|
1463
1509
|
recorded: Sequence[Mapping[str, Any]],
|
|
1464
1510
|
rows: Mapping[str, Any],
|
|
@@ -51,7 +51,8 @@ from okstra_ctl.final_report_schema import (
|
|
|
51
51
|
validate as schema_validate,
|
|
52
52
|
)
|
|
53
53
|
from okstra_ctl.json_boundary import JsonBoundaryError, load_owned_object
|
|
54
|
-
from okstra_ctl.i18n import I18nError,
|
|
54
|
+
from okstra_ctl.i18n import I18nError, load_dictionary, make_jinja_global
|
|
55
|
+
from okstra_ctl.report_language import is_language_tag
|
|
55
56
|
from okstra_ctl.md_table import UNESCAPED_PIPE_RE, to_cell_text
|
|
56
57
|
from okstra_ctl.models import UnknownModelError, resolve_model_metadata
|
|
57
58
|
from okstra_ctl.paths import find_asset_root
|
|
@@ -598,15 +599,10 @@ def validate_report_language(data: dict) -> str:
|
|
|
598
599
|
selects this renderer's dictionary.
|
|
599
600
|
"""
|
|
600
601
|
candidate = (data.get("meta") or {}).get("reportLanguage") or "en"
|
|
601
|
-
if candidate
|
|
602
|
+
if not is_language_tag(candidate):
|
|
602
603
|
raise FinalReportRenderError(
|
|
603
|
-
"reportLanguage
|
|
604
|
-
"
|
|
605
|
-
"'ko' from the run manifest into data.json.meta.reportLanguage."
|
|
606
|
-
)
|
|
607
|
-
if candidate not in SUPPORTED_LANGS:
|
|
608
|
-
raise FinalReportRenderError(
|
|
609
|
-
f"reportLanguage must be one of {SUPPORTED_LANGS}, got {candidate!r}"
|
|
604
|
+
f"reportLanguage must be a language tag such as en, ko, fr or "
|
|
605
|
+
f"pt-BR, got {candidate!r}"
|
|
610
606
|
)
|
|
611
607
|
return MARKDOWN_LANG
|
|
612
608
|
|
|
@@ -25,10 +25,8 @@ placeholders, which a v2 report never carries because its numeric cells are
|
|
|
25
25
|
`null` until this step fills them. Substituting the tokens on a later retry
|
|
26
26
|
then leaves the already-rendered html stale for `validators/validate-report-views.py`.
|
|
27
27
|
|
|
28
|
-
The translation sidecar is the `translate` step,
|
|
29
|
-
|
|
30
|
-
because the extractor refuses a work list from a non-English source. It used to
|
|
31
|
-
be a manual lead sequence outside this command (materialize the translator
|
|
28
|
+
The translation sidecar is the `translate` step, directly before `render-views`,
|
|
29
|
+
which overlays it. It used to be a manual lead sequence outside this command (materialize the translator
|
|
32
30
|
prompt, dispatch it, resume finalize at `render-views`), written only in a doc
|
|
33
31
|
the lead lazy-reads; a lead that ran the whole sequence at once skipped it and
|
|
34
32
|
the run kept an English view under a `ko` report (2026-09-09, fontsninja-v3-site
|
|
@@ -88,7 +86,6 @@ from okstra_project.phase_pointer import (
|
|
|
88
86
|
|
|
89
87
|
|
|
90
88
|
STEP_PROJECT_ACTIVITY = "project-activity"
|
|
91
|
-
STEP_CHECK_SOURCE = "check-source"
|
|
92
89
|
STEP_TRANSLATE = "translate"
|
|
93
90
|
STEP_TOKEN_USAGE = "token-usage"
|
|
94
91
|
STEP_RENDER_VIEWS = "render-views"
|
|
@@ -99,10 +96,6 @@ STEP_TEARDOWN_STAGES = "teardown-stages"
|
|
|
99
96
|
|
|
100
97
|
STEP_ORDER = (
|
|
101
98
|
STEP_PROJECT_ACTIVITY,
|
|
102
|
-
# First, because everything after it derives from the data.json: rendering
|
|
103
|
-
# a Korean SSOT into English chrome, spawning follow-ups from it, and
|
|
104
|
-
# validating it all succeed on a record the next phase cannot read.
|
|
105
|
-
STEP_CHECK_SOURCE,
|
|
106
99
|
STEP_TRANSLATE,
|
|
107
100
|
STEP_TOKEN_USAGE,
|
|
108
101
|
STEP_RENDER_VIEWS,
|
|
@@ -119,8 +112,7 @@ STEP_ORDER = (
|
|
|
119
112
|
V3_STEP_ORDER = (
|
|
120
113
|
STEP_TOKEN_USAGE,
|
|
121
114
|
STEP_PROJECT_ACTIVITY,
|
|
122
|
-
|
|
123
|
-
# After the English gate, before the render that overlays its sidecar.
|
|
115
|
+
# Before the render that overlays its sidecar.
|
|
124
116
|
STEP_TRANSLATE,
|
|
125
117
|
STEP_RENDER_VIEWS,
|
|
126
118
|
STEP_SPAWN_FOLLOWUPS,
|
|
@@ -334,19 +326,6 @@ def build_commands(ctx: FinalizeContext) -> list[tuple[str, list[str]]]:
|
|
|
334
326
|
str(ctx.data_path),
|
|
335
327
|
],
|
|
336
328
|
),
|
|
337
|
-
(
|
|
338
|
-
STEP_CHECK_SOURCE,
|
|
339
|
-
[
|
|
340
|
-
sys.executable,
|
|
341
|
-
str(
|
|
342
|
-
resolve_workspace_script(
|
|
343
|
-
ctx.workspace_root, "okstra-report-translate.py"
|
|
344
|
-
)
|
|
345
|
-
),
|
|
346
|
-
"check-source",
|
|
347
|
-
str(ctx.data_path),
|
|
348
|
-
],
|
|
349
|
-
),
|
|
350
329
|
(
|
|
351
330
|
STEP_TRANSLATE,
|
|
352
331
|
["<in-process>", "translate", str(ctx.data_path)],
|
|
@@ -976,18 +955,17 @@ _CLI_EPILOG = r"""Usage:
|
|
|
976
955
|
Runs the Phase 7 steps in their contractual order against one final-report:
|
|
977
956
|
|
|
978
957
|
1. project-activity project the run's activity events into the data.json
|
|
979
|
-
2.
|
|
980
|
-
3. translate for a non-English reportLanguage, materialize and
|
|
958
|
+
2. translate for a non-English reportLanguage, materialize and
|
|
981
959
|
dispatch the translator worker and require its
|
|
982
960
|
*.i18n.<lang>.json sidecar; a no-op for English or
|
|
983
961
|
when the sidecar already exists
|
|
984
|
-
|
|
985
|
-
|
|
962
|
+
3. token-usage substitute real token/cost numbers into the data.json
|
|
963
|
+
4. render-views write the schema-v2 task-specific *.html sibling with
|
|
986
964
|
the translation overlaid; v1 keeps the
|
|
987
965
|
legacy conditional interactive view
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
966
|
+
5. spawn-followups turn section 4 rows into task stubs
|
|
967
|
+
6. validate-run validate the finished run artifacts
|
|
968
|
+
7. record-group-memory / 8. teardown-stages after a clean validation
|
|
991
969
|
|
|
992
970
|
Every step is idempotent, so re-running after a fixed failure is safe. The
|
|
993
971
|
sequence stops at the first non-zero exit and reports which step failed, except
|
|
@@ -12,7 +12,7 @@ from jinja2 import Environment, FileSystemLoader, StrictUndefined, select_autoes
|
|
|
12
12
|
from ..final_report_paths import final_report_data_path, translation_sidecar_path
|
|
13
13
|
from ..final_report_schema import load_schema_for_data, validate
|
|
14
14
|
from ..i18n import HTML_DICTIONARY_REL, load_dictionary, make_jinja_global
|
|
15
|
-
from ..report_translation import overlay
|
|
15
|
+
from ..report_translation import overlay
|
|
16
16
|
from ..report_view_artifacts import user_responses_dir_for_report
|
|
17
17
|
from ..usage_cells import format_duration_ms
|
|
18
18
|
from ..json_boundary import load_owned_object
|
|
@@ -223,16 +223,6 @@ def render_v2_html_view(
|
|
|
223
223
|
document = env.get_template(route.template_name).render(**context)
|
|
224
224
|
document = inject_report_index(document, label=translate("base.contents"))
|
|
225
225
|
output_path.write_text(document, encoding="utf-8")
|
|
226
|
-
if lang != "en":
|
|
227
|
-
# 사이드카 보고("left in English")는 추출 범위 안만 센다. 페이지에 실제로
|
|
228
|
-
# 남은 영어 문장은 여기서 세어 같은 stdout 에 낸다 — 두 숫자가 갈리면
|
|
229
|
-
# `PROSE_KEYS` 밖의 필드가 화면에 나가고 있다는 뜻이다.
|
|
230
|
-
english = rendered_english_lines(document)
|
|
231
|
-
sys.stdout.write(
|
|
232
|
-
f"rendered {len(english)} line(s) still in English on the {lang} page"
|
|
233
|
-
+ (f" (e.g. {english[0][:80]!r})" if english else "")
|
|
234
|
-
+ "\n"
|
|
235
|
-
)
|
|
236
226
|
if context["clarificationItems"] or context.get("directionSelection"):
|
|
237
227
|
# The footer tells the reader to drop the exported file here, so the
|
|
238
228
|
# directory has to exist before they go looking for it.
|
|
@@ -6,28 +6,32 @@ the run manifest, which report assembly copies into `meta.reportLanguage` and
|
|
|
6
6
|
the HTML renderer reads. When only the prompt called this, a project could ask
|
|
7
7
|
for `ko`, get a Korean-instructed writer, and still ship an English report.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
The value is a language tag (`en`, `ko`, `fr`, `pt-BR`, …). The Phase 7
|
|
10
|
+
translator receives that tag and translates into it; nothing here knows any
|
|
11
|
+
particular language. Precedence: project config → global config → `en`.
|
|
10
12
|
"""
|
|
11
13
|
from __future__ import annotations
|
|
12
14
|
|
|
13
|
-
import json
|
|
14
15
|
import os
|
|
16
|
+
import re
|
|
15
17
|
from pathlib import Path
|
|
16
18
|
from typing import Any, Mapping
|
|
17
19
|
|
|
18
|
-
from .worker_prompt_body import instruction_path
|
|
19
20
|
from .json_boundary import JsonBoundaryError, load_owned_object
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
DEFAULT_REPORT_LANGUAGE = "en"
|
|
22
23
|
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
|
|
26
|
-
_BRIEF_SCAN_CHARS = 16000
|
|
24
|
+
# BCP 47 의 흔한 꼴만 — 소문자 2~3자 언어 코드와 선택적 하위 태그. 대문자
|
|
25
|
+
# 언어 코드나 단어(`english`)는 사이드카 파일명과 사전 파일명이 갈리므로 거절.
|
|
26
|
+
_LANGUAGE_TAG = re.compile(r"^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$")
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
class ReportLanguageError(ValueError):
|
|
30
|
-
"""A config file declares a reportLanguage
|
|
30
|
+
"""A config file declares a reportLanguage that is not a language tag."""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def is_language_tag(value: object) -> bool:
|
|
34
|
+
return isinstance(value, str) and _LANGUAGE_TAG.match(value) is not None
|
|
31
35
|
|
|
32
36
|
|
|
33
37
|
def resolve_report_language(
|
|
@@ -36,11 +40,9 @@ def resolve_report_language(
|
|
|
36
40
|
active_context: Mapping[str, Any],
|
|
37
41
|
) -> str:
|
|
38
42
|
for value in _report_language_candidates(project_root):
|
|
39
|
-
if value == "auto":
|
|
40
|
-
return _infer_report_language(project_root, manifest, active_context)
|
|
41
43
|
if value:
|
|
42
44
|
return value
|
|
43
|
-
return
|
|
45
|
+
return DEFAULT_REPORT_LANGUAGE
|
|
44
46
|
|
|
45
47
|
|
|
46
48
|
def _report_language_candidates(project_root: Path) -> list[str]:
|
|
@@ -63,26 +65,9 @@ def _read_report_language(path: Path, label: str) -> str:
|
|
|
63
65
|
value = payload.get("reportLanguage")
|
|
64
66
|
if value in (None, ""):
|
|
65
67
|
return ""
|
|
66
|
-
if
|
|
68
|
+
if is_language_tag(value):
|
|
67
69
|
return value
|
|
68
70
|
raise ReportLanguageError(
|
|
69
|
-
f"{label} config reportLanguage must be en, ko,
|
|
71
|
+
f"{label} config reportLanguage must be a language tag such as en, ko, "
|
|
72
|
+
f"fr or pt-BR, got {value!r}: {path}"
|
|
70
73
|
)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def _infer_report_language(
|
|
74
|
-
project_root: Path,
|
|
75
|
-
manifest: Mapping[str, Any],
|
|
76
|
-
active_context: Mapping[str, Any],
|
|
77
|
-
) -> str:
|
|
78
|
-
task_brief = instruction_path(manifest, active_context, "taskBriefPath")
|
|
79
|
-
if not task_brief:
|
|
80
|
-
return "en"
|
|
81
|
-
path = Path(task_brief)
|
|
82
|
-
if not path.is_absolute():
|
|
83
|
-
path = project_root / path
|
|
84
|
-
if not path.is_file():
|
|
85
|
-
return "en"
|
|
86
|
-
text = path.read_text(encoding="utf-8", errors="replace")[:_BRIEF_SCAN_CHARS]
|
|
87
|
-
hangul = sum(1 for char in text if "가" <= char <= "힣")
|
|
88
|
-
return "ko" if hangul >= _HANGUL_THRESHOLD else "en"
|
|
@@ -441,57 +441,6 @@ def overlay(
|
|
|
441
441
|
return out, OverlayReport(applied, untranslated, tuple(sorted(unresolved)))
|
|
442
442
|
|
|
443
443
|
|
|
444
|
-
# Above this share of Hangul, the prose was authored in Korean rather than
|
|
445
|
-
# quoting some. Measured across real reports: Korean-authored ones sit at
|
|
446
|
-
# 35-38%, English ones that quote a Korean brief or a worker's Korean phrase
|
|
447
|
-
# reach 8% at most. The gap is wide enough that no threshold inside it is
|
|
448
|
-
# delicate. Only the strings `extract` offers are counted — a verbatim quote of
|
|
449
|
-
# the user's request is structural and never reaches this.
|
|
450
|
-
HANGUL_PROSE_LIMIT = 0.20
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
_RENDERED_SKIP_RE = re.compile(
|
|
454
|
-
r"<script.*?</script>|<style.*?</style>|<svg.*?</svg>|<pre.*?</pre>|<option.*?</option>",
|
|
455
|
-
re.DOTALL,
|
|
456
|
-
)
|
|
457
|
-
_TEXT_NODE_RE = re.compile(r">([^<>]{40,})<")
|
|
458
|
-
_ENTITY_RE = re.compile(r"&[#A-Za-z0-9]+;")
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
def rendered_english_lines(html: str, *, min_words: int = 6) -> list[str]:
|
|
462
|
-
"""Text nodes of a rendered page that carry no Hangul and read as a sentence.
|
|
463
|
-
|
|
464
|
-
`OverlayReport.untranslated` only sees the pointers the extractor offered,
|
|
465
|
-
so a reader-facing field outside `PROSE_KEYS` never shows up there — the
|
|
466
|
-
2026-09-05 audit found 40 plan-item explanations and 29 step actions in
|
|
467
|
-
English on a page that reported "0 left in English". This reads the page
|
|
468
|
-
itself. Scripts, styles, figures, code blocks and `<option>` values are
|
|
469
|
-
skipped: figure labels and response values are meant to stay verbatim.
|
|
470
|
-
Inline `<code>` is stripped so a sentence around a path still counts.
|
|
471
|
-
"""
|
|
472
|
-
body = html.split("<main", 1)[-1]
|
|
473
|
-
body = _RENDERED_SKIP_RE.sub(" ", body)
|
|
474
|
-
body = re.sub(r"</?code>", "", body)
|
|
475
|
-
lines: list[str] = []
|
|
476
|
-
for match in _TEXT_NODE_RE.finditer(body):
|
|
477
|
-
text = _ENTITY_RE.sub(" ", match.group(1)).strip()
|
|
478
|
-
if len(text.split()) < min_words:
|
|
479
|
-
continue
|
|
480
|
-
if any("가" <= char <= "힣" for char in text):
|
|
481
|
-
continue
|
|
482
|
-
lines.append(text)
|
|
483
|
-
return lines
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
def hangul_share(data: Mapping[str, Any]) -> tuple[float, int]:
|
|
487
|
-
"""Return the Hangul share of the report's authored prose, and its length."""
|
|
488
|
-
text = "".join(extract(data).values())
|
|
489
|
-
if not text:
|
|
490
|
-
return 0.0, 0
|
|
491
|
-
hangul = sum(1 for char in text if "가" <= char <= "힣")
|
|
492
|
-
return hangul / len(text), len(text)
|
|
493
|
-
|
|
494
|
-
|
|
495
444
|
def _schema_string_keys(schema: Mapping[str, Any], *, enums: bool) -> set[str]:
|
|
496
445
|
found: set[str] = set()
|
|
497
446
|
|
|
@@ -37,16 +37,12 @@ from .json_boundary import JsonBoundaryError
|
|
|
37
37
|
|
|
38
38
|
TRANSLATOR_WORKER_ID = "translator"
|
|
39
39
|
|
|
40
|
-
# 지시문의 언어 이름. 워커는 `**Report Language:**` 헤더로 코드를 받지만, 지시문은
|
|
41
|
-
# 사람이 읽는 문장이라 이름으로 적는다. 표에 없는 코드는 코드 그대로 쓴다.
|
|
42
|
-
_LANGUAGE_NAMES = {"ko": "Korean"}
|
|
43
|
-
|
|
44
40
|
# 리드가 종전에 손으로 쓰던 지시문(실측 2026-09-08, fontsninja-nlpvibe dev-10786
|
|
45
41
|
# requirements-discovery-002)과 같은 절차다. 명령은 `agents/workers/translator-worker.md`
|
|
46
42
|
# 의 Procedure 와 같은 세 개이고, 결과·감사 경로는 프롬프트 앵커가 이름한다.
|
|
47
43
|
_INSTRUCTIONS = """## Instructions
|
|
48
44
|
|
|
49
|
-
Translate the finalized report into {language} faithfully. This is translation only: no analysis, no source edits.
|
|
45
|
+
Translate the finalized report into the language whose IETF language tag is `{language}` faithfully. This is translation only: no analysis, no source edits.
|
|
50
46
|
|
|
51
47
|
1. Run `okstra report-translate source --run-manifest {manifest}` and read the complete work list, in chunks if it is long. Copy the `Source digest` it prints.
|
|
52
48
|
2. Write one translated block per `## T-NNN` item to the exact Result Path, using the same `## T-NNN` headings. Preserve every identifier, path, command, enum token, link, and qualification character for character.
|
|
@@ -229,7 +225,7 @@ def _materialize_translator(
|
|
|
229
225
|
instruction.parent.mkdir(parents=True, exist_ok=True)
|
|
230
226
|
instruction.write_text(
|
|
231
227
|
_INSTRUCTIONS.format(
|
|
232
|
-
language=
|
|
228
|
+
language=lang,
|
|
233
229
|
manifest=manifest_path.relative_to(project_root).as_posix()
|
|
234
230
|
if manifest_path.is_relative_to(project_root)
|
|
235
231
|
else str(manifest_path),
|
|
@@ -5,12 +5,23 @@
|
|
|
5
5
|
"""
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
8
10
|
from datetime import datetime
|
|
9
11
|
from pathlib import Path
|
|
10
12
|
from typing import Callable
|
|
11
13
|
|
|
12
14
|
OKSTRA = "okstra"
|
|
13
15
|
_SPEAKER_WIDTH = 14
|
|
16
|
+
_RESET = "\x1b[0m"
|
|
17
|
+
_MUTED = "\x1b[90m"
|
|
18
|
+
_LIVE_COLORS = (
|
|
19
|
+
("→ ", "\x1b[36m"),
|
|
20
|
+
(" ← ok", "\x1b[32m"),
|
|
21
|
+
(" ← error", "\x1b[31m"),
|
|
22
|
+
("!! PERMISSION DENIED", "\x1b[1;31m"),
|
|
23
|
+
(" ← done", "\x1b[33m"),
|
|
24
|
+
)
|
|
14
25
|
|
|
15
26
|
# 파일 사본이 담는 워커 진행 줄의 상한. 진행은 워커 출력의 부피가 몰리는
|
|
16
27
|
# 자리다 — 파일 하나만 읽는 디스패치도 킬로바이트 단위 도구 에코를 남기고,
|
|
@@ -39,6 +50,12 @@ class SessionTranscript:
|
|
|
39
50
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
40
51
|
self._file = path.open("w", encoding="utf-8")
|
|
41
52
|
self._live = live
|
|
53
|
+
self._color = (
|
|
54
|
+
live
|
|
55
|
+
and sys.stdout.isatty()
|
|
56
|
+
and not os.environ.get("NO_COLOR")
|
|
57
|
+
and os.environ.get("TERM") != "dumb"
|
|
58
|
+
)
|
|
42
59
|
self._clock = clock
|
|
43
60
|
self._archived = 0
|
|
44
61
|
self._elided = 0
|
|
@@ -51,7 +68,7 @@ class SessionTranscript:
|
|
|
51
68
|
잘린 결론은 사후 분석 전체를 잃는다.
|
|
52
69
|
"""
|
|
53
70
|
row = self._row(speaker, line)
|
|
54
|
-
self._show(row)
|
|
71
|
+
self._show(row, line)
|
|
55
72
|
self._keep(row, capped=capped)
|
|
56
73
|
|
|
57
74
|
def write_event(
|
|
@@ -67,7 +84,7 @@ class SessionTranscript:
|
|
|
67
84
|
기록에서는 46KB 를 읽은 호출과 잘린 호출이 같은 줄로 보인다.
|
|
68
85
|
"""
|
|
69
86
|
for line in screen:
|
|
70
|
-
self._show(self._row(speaker, line))
|
|
87
|
+
self._show(self._row(speaker, line), line)
|
|
71
88
|
for line in archive:
|
|
72
89
|
self._keep(self._row(speaker, line), capped=True)
|
|
73
90
|
|
|
@@ -77,9 +94,22 @@ class SessionTranscript:
|
|
|
77
94
|
label = f"[{speaker}]".ljust(_SPEAKER_WIDTH)
|
|
78
95
|
return f"{self._clock()} {label}{line}".rstrip()
|
|
79
96
|
|
|
80
|
-
def _show(self, row: str) -> None:
|
|
97
|
+
def _show(self, row: str, line: str) -> None:
|
|
81
98
|
# 화면은 상한과 무관하다. 사람이 보고 있는 것을 잘라 낼 이유가 없다.
|
|
82
99
|
if self._live:
|
|
100
|
+
if self._color:
|
|
101
|
+
color = next(
|
|
102
|
+
(color for prefix, color in _LIVE_COLORS if line.startswith(prefix)),
|
|
103
|
+
"",
|
|
104
|
+
)
|
|
105
|
+
if line.lstrip().startswith("… +"):
|
|
106
|
+
color = "\x1b[33m"
|
|
107
|
+
# 시각·화자는 낮은 대비로 두고 본문은 터미널 기본색을 유지한다.
|
|
108
|
+
prefix_size = len(row) - len(line.rstrip())
|
|
109
|
+
row = (
|
|
110
|
+
f"{_MUTED}{row[:prefix_size]}{_RESET}"
|
|
111
|
+
f"{color}{row[prefix_size:]}{_RESET}"
|
|
112
|
+
)
|
|
83
113
|
print(row, flush=True)
|
|
84
114
|
|
|
85
115
|
def _keep(self, row: str, *, capped: bool) -> None:
|
|
@@ -122,8 +122,9 @@ matching section:
|
|
|
122
122
|
diagnose a symlink/backup warning.
|
|
123
123
|
- **D. PR body template** (release-handoff) — opt-in pre-registration; also
|
|
124
124
|
offered on the first release-handoff run.
|
|
125
|
-
- **E. final report language** (`reportLanguage`) —
|
|
126
|
-
|
|
125
|
+
- **E. final report language** (`reportLanguage`) — a language tag (`en`,
|
|
126
|
+
`ko`, `fr`, …); default `en`. The Phase 7 translator translates the human
|
|
127
|
+
HTML into it.
|
|
127
128
|
- **F. declared architecture style** (`architecture.style`) — `hexagonal` /
|
|
128
129
|
`layered` / `none`; hand-added, default `none`. Declaring one makes that
|
|
129
130
|
architecture's placement rules binding in planning + verification.
|
|
@@ -195,23 +195,22 @@ per-run override prompt during the next release-handoff run.
|
|
|
195
195
|
|
|
196
196
|
## E. Final report language (`reportLanguage`)
|
|
197
197
|
|
|
198
|
-
The
|
|
199
|
-
the
|
|
200
|
-
|
|
201
|
-
report).
|
|
198
|
+
The value is a language tag (`en`, `ko`, `fr`, `pt-BR`, …). The data.json
|
|
199
|
+
stays English; the Phase 7 translator translates the human HTML into the tag.
|
|
200
|
+
If you skip, no `reportLanguage` field is written and the runtime uses `en`.
|
|
202
201
|
|
|
203
202
|
AskUserQuestion (fixed options):
|
|
204
203
|
- Question: `"Which language should the final report be written in?"`
|
|
205
204
|
- Options:
|
|
206
205
|
1. `English (recommended)` → `en`
|
|
207
206
|
2. `Korean` → `ko`
|
|
208
|
-
3. `
|
|
209
|
-
4. `Later` → skip (no field set →
|
|
207
|
+
3. `Other` → ask for the language tag (`fr`, `de`, `ja`, `pt-BR`, …)
|
|
208
|
+
4. `Later` → skip (no field set → `en`)
|
|
210
209
|
|
|
211
210
|
If the user picks 1/2/3:
|
|
212
211
|
|
|
213
212
|
```bash
|
|
214
|
-
okstra config set report-language <
|
|
213
|
+
okstra config set report-language <language-tag> --scope project
|
|
215
214
|
```
|
|
216
215
|
|
|
217
216
|
Set the global default manually with `--scope global` as described in the
|
|
@@ -74,10 +74,6 @@ from okstra_ctl.mutation_probe import ( # noqa: E402
|
|
|
74
74
|
classify_reason,
|
|
75
75
|
)
|
|
76
76
|
from okstra_ctl.self_mock_signals import selfmock_path_key # noqa: E402
|
|
77
|
-
from okstra_ctl.report_translation import ( # noqa: E402
|
|
78
|
-
HANGUL_PROSE_LIMIT,
|
|
79
|
-
hangul_share,
|
|
80
|
-
)
|
|
81
77
|
from okstra_ctl.validation_contract import ( # noqa: E402
|
|
82
78
|
CURRENT_VALIDATION_CONTRACT_VERSION,
|
|
83
79
|
)
|
|
@@ -6353,7 +6349,12 @@ def _plan_verify_dispatched_results(
|
|
|
6353
6349
|
for row in payload.get("workerDispatches") or []:
|
|
6354
6350
|
if not isinstance(row, dict):
|
|
6355
6351
|
continue
|
|
6356
|
-
|
|
6352
|
+
# critic 동수 라운드는 `kind: "critic"` 으로 나간다 — 결과 파일명은
|
|
6353
|
+
# 같은 `-plan-verify-r<N>-` 꼴이다. reverify 계열만 세면 동수가 있던
|
|
6354
|
+
# run 마다 critic 표가 "디스패치 기록 없음" 으로 오탐된다(2026-09-09,
|
|
6355
|
+
# fontsninja-v3-site dev-10627 planning 002).
|
|
6356
|
+
kind = str(row.get("kind") or "")
|
|
6357
|
+
if not (kind.startswith("reverify-r") or kind == "critic"):
|
|
6357
6358
|
continue
|
|
6358
6359
|
name = Path(str(row.get("workerResultPath") or "")).name
|
|
6359
6360
|
if "-plan-verify-r" not in name:
|
|
@@ -8129,32 +8130,6 @@ def _validate_improvement_discovery(
|
|
|
8129
8130
|
failures.append(f"improvement-discovery: {err}")
|
|
8130
8131
|
|
|
8131
8132
|
|
|
8132
|
-
def _validate_ssot_is_english(data: dict, failures: list[str]) -> None:
|
|
8133
|
-
"""Enforce: the final-report data.json is authored in English.
|
|
8134
|
-
|
|
8135
|
-
`meta.reportLanguage` names the language the human HTML renders in, and
|
|
8136
|
-
Phase 7's translator serves it from a sidecar. The data.json itself is the
|
|
8137
|
-
record every later phase, validator and agent reads, so a worker that
|
|
8138
|
-
authors it in the reader's language instead splits the record — and does so
|
|
8139
|
-
silently, because rendering, follow-up spawning and validation all succeed
|
|
8140
|
-
on it.
|
|
8141
|
-
|
|
8142
|
-
`report-finalize` runs the same check as its first step, before anything
|
|
8143
|
-
derives from the report. This is the second gate, for a report that reached
|
|
8144
|
-
validation by some other path.
|
|
8145
|
-
"""
|
|
8146
|
-
if not data:
|
|
8147
|
-
return
|
|
8148
|
-
share, length = hangul_share(data)
|
|
8149
|
-
if length and share >= HANGUL_PROSE_LIMIT:
|
|
8150
|
-
failures.append(
|
|
8151
|
-
f"final-report data.json was authored in Korean ({share:.0%} of its "
|
|
8152
|
-
f"prose, limit {HANGUL_PROSE_LIMIT:.0%}). The data.json is the "
|
|
8153
|
-
"English SSOT; meta.reportLanguage selects the human HTML's "
|
|
8154
|
-
"language and is served by the Phase 7 translator sidecar."
|
|
8155
|
-
)
|
|
8156
|
-
|
|
8157
|
-
|
|
8158
8133
|
def _validate_translation_sidecar(
|
|
8159
8134
|
data: Mapping[str, Any], report_path: Path, failures: list[str]
|
|
8160
8135
|
) -> None:
|
|
@@ -9429,7 +9404,6 @@ def main() -> int:
|
|
|
9429
9404
|
),
|
|
9430
9405
|
)
|
|
9431
9406
|
validation_data = report_data if isinstance(report_data, Mapping) else {}
|
|
9432
|
-
_validate_ssot_is_english(validation_data, failures)
|
|
9433
9407
|
_validate_translation_sidecar(
|
|
9434
9408
|
validation_data, _data_path_for(report_path), failures
|
|
9435
9409
|
)
|