okstra 0.179.2 → 0.183.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli-registry.mjs +30 -2
- package/dist/cli-registry.mjs.map +1 -1
- package/dist/commands/execute/incremental-carry.mjs +9 -8
- package/dist/commands/execute/incremental-carry.mjs.map +1 -1
- package/dist/commands/execute/plan-verify.mjs +3 -1
- package/dist/commands/execute/plan-verify.mjs.map +1 -1
- package/dist/commands/execute/render-bundle.d.mts +4 -2
- package/dist/commands/execute/render-bundle.mjs +46 -5
- package/dist/commands/execute/render-bundle.mjs.map +1 -1
- package/dist/commands/execute/run.mjs +11 -3
- package/dist/commands/execute/run.mjs.map +1 -1
- package/dist/commands/inspect/model-io.d.mts +1 -0
- package/dist/commands/inspect/model-io.mjs +25 -0
- package/dist/commands/inspect/model-io.mjs.map +1 -0
- package/dist/commands/inspect/stage-map.mjs +29 -8
- package/dist/commands/inspect/stage-map.mjs.map +1 -1
- package/dist/commands/inspect/task-list.mjs +52 -6
- package/dist/commands/inspect/task-list.mjs.map +1 -1
- package/dist/commands/inspect/user-response.mjs +14 -4
- package/dist/commands/inspect/user-response.mjs.map +1 -1
- package/dist/commands/lifecycle/check-project.d.mts +1 -0
- package/dist/commands/lifecycle/check-project.mjs +69 -50
- package/dist/commands/lifecycle/check-project.mjs.map +1 -1
- package/dist/commands/lifecycle/contract-check.d.mts +1 -0
- package/dist/commands/lifecycle/contract-check.mjs +18 -0
- package/dist/commands/lifecycle/contract-check.mjs.map +1 -0
- package/dist/commands/lifecycle/preflight.mjs +154 -51
- package/dist/commands/lifecycle/preflight.mjs.map +1 -1
- package/dist/commands/pr/pr.d.mts +1 -0
- package/dist/commands/pr/pr.mjs +19 -1
- package/dist/commands/pr/pr.mjs.map +1 -1
- package/dist/commands/report/agent-activity.mjs +2 -2
- package/dist/commands/report/approval-decision.d.mts +1 -0
- package/dist/commands/report/approval-decision.mjs +21 -0
- package/dist/commands/report/approval-decision.mjs.map +1 -0
- package/dist/commands/report/design-snapshot.d.mts +1 -0
- package/dist/commands/report/design-snapshot.mjs +19 -0
- package/dist/commands/report/design-snapshot.mjs.map +1 -0
- package/dist/commands/report/translate.mjs +3 -0
- package/dist/commands/report/translate.mjs.map +1 -1
- package/dist/lib/host-registry-client.mjs +13 -9
- package/dist/lib/host-registry-client.mjs.map +1 -1
- package/docs/architecture/storage-model.md +1 -1
- package/docs/architecture.md +21 -10
- package/docs/cli.md +36 -20
- package/docs/container.md +6 -4
- package/docs/contributor-change-matrix.md +1 -1
- package/docs/for-ai/README.md +2 -2
- package/docs/for-ai/skills/okstra-brief-gen.md +5 -3
- package/docs/for-ai/skills/okstra-code-review.md +4 -4
- package/docs/for-ai/skills/okstra-container-build.md +20 -17
- package/docs/for-ai/skills/okstra-inspect.md +20 -23
- package/docs/for-ai/skills/okstra-manager.md +19 -18
- package/docs/for-ai/skills/okstra-memory.md +2 -2
- package/docs/for-ai/skills/okstra-pr-gen.md +3 -3
- package/docs/for-ai/skills/okstra-rollup.md +14 -13
- package/docs/for-ai/skills/okstra-run.md +7 -3
- package/docs/for-ai/skills/okstra-schedule-gen.md +15 -18
- package/docs/for-ai/skills/okstra-setup.md +7 -7
- package/docs/for-ai/skills/okstra-usage.md +5 -4
- package/docs/for-ai/skills/okstra-user-response.md +50 -32
- package/docs/project-structure-overview.md +43 -31
- package/docs/task-process/implementation-planning.md +2 -2
- package/docs/task-process/implementation.md +7 -4
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/claude-worker.md +4 -4
- package/runtime/agents/workers/report-writer-worker.md +15 -164
- package/runtime/agents/workers/translator-worker.md +5 -13
- package/runtime/bin/okstra-error-log.py +51 -11
- package/runtime/bin/okstra-report-translate.py +210 -23
- package/runtime/prompts/host-orchestration/implementation.md +1 -1
- package/runtime/prompts/launch.template.md +9 -12
- package/runtime/prompts/lead/adapters/cmux.md +1 -1
- package/runtime/prompts/lead/context-loader.md +41 -141
- package/runtime/prompts/lead/convergence.md +10 -8
- package/runtime/prompts/lead/okstra-lead-contract.md +40 -49
- package/runtime/prompts/lead/plan-body-verification.md +217 -23
- package/runtime/prompts/lead/report-writer.md +81 -421
- package/runtime/prompts/lead/team-contract.md +9 -54
- package/runtime/prompts/profiles/_clarification-recommendation.md +5 -4
- package/runtime/prompts/profiles/_coding-conventions-preflight.md +3 -2
- package/runtime/prompts/profiles/_common-contract.md +4 -4
- package/runtime/prompts/profiles/_implementation-deliverable.md +1 -1
- package/runtime/prompts/profiles/_implementation-diff-review.md +1 -1
- package/runtime/prompts/profiles/_implementation-verifier.md +3 -3
- package/runtime/prompts/profiles/change-impact-analysis.md +1 -1
- package/runtime/prompts/profiles/error-analysis.md +1 -1
- package/runtime/prompts/profiles/feature-analysis.md +1 -1
- package/runtime/prompts/profiles/final-verification.md +1 -1
- package/runtime/prompts/profiles/implementation-planning.md +20 -12
- package/runtime/prompts/profiles/improvement-discovery.md +1 -1
- package/runtime/prompts/profiles/project-analysis.md +1 -1
- package/runtime/prompts/profiles/release-handoff.md +0 -1
- package/runtime/prompts/profiles/requirements-discovery.md +1 -1
- package/runtime/prompts/wizard/prompts.ko.json +0 -1
- package/runtime/python/okstra_ctl/adapters/hosts/capability_adapter.py +69 -17
- package/runtime/python/okstra_ctl/adapters/hosts/claude-code/adapter.py +13 -4
- package/runtime/python/okstra_ctl/adapters/hosts/claude-code/relay.md +8 -2
- package/runtime/python/okstra_ctl/adapters/hosts/codex/adapter.py +2 -2
- package/runtime/python/okstra_ctl/adapters/hosts/codex/relay.md +50 -5
- package/runtime/python/okstra_ctl/adapters/hosts/external/relay.md +1 -1
- package/runtime/python/okstra_ctl/adapters/hosts/grok/adapter.py +2 -2
- package/runtime/python/okstra_ctl/adapters/hosts/grok/relay.md +66 -5
- package/runtime/python/okstra_ctl/adapters/providers/grok/adapter.py +70 -2
- package/runtime/python/okstra_ctl/agent_activity.py +141 -38
- package/runtime/python/okstra_ctl/agent_invocation.py +19 -6
- package/runtime/python/okstra_ctl/agent_prompt_cli.py +70 -23
- package/runtime/python/okstra_ctl/analysis_inputs.py +5 -4
- package/runtime/python/okstra_ctl/analysis_packet.py +124 -3
- package/runtime/python/okstra_ctl/approval_decisions.py +328 -0
- package/runtime/python/okstra_ctl/attempt_evidence.py +2 -2
- package/runtime/python/okstra_ctl/backfill.py +13 -10
- package/runtime/python/okstra_ctl/batch.py +2 -4
- package/runtime/python/okstra_ctl/build_tools.py +6 -3
- package/runtime/python/okstra_ctl/claim_reproduction.py +101 -0
- package/runtime/python/okstra_ctl/clarification_items.py +27 -13
- package/runtime/python/okstra_ctl/cmux.py +130 -52
- package/runtime/python/okstra_ctl/code_review_target.py +34 -8
- package/runtime/python/okstra_ctl/consumers.py +5 -4
- package/runtime/python/okstra_ctl/container.py +103 -8
- package/runtime/python/okstra_ctl/context_cost.py +2 -1
- package/runtime/python/okstra_ctl/contract_graph.py +497 -0
- package/runtime/python/okstra_ctl/contract_graph_cli.py +62 -0
- package/runtime/python/okstra_ctl/convergence.py +338 -17
- package/runtime/python/okstra_ctl/convergence_engine.py +10 -18
- package/runtime/python/okstra_ctl/convergence_provenance.py +58 -8
- package/runtime/python/okstra_ctl/convergence_store.py +55 -34
- package/runtime/python/okstra_ctl/design_prep.py +7 -4
- package/runtime/python/okstra_ctl/design_snapshot.py +134 -0
- package/runtime/python/okstra_ctl/dispatch_core.py +97 -69
- package/runtime/python/okstra_ctl/dispatch_state.py +163 -63
- package/runtime/python/okstra_ctl/doctor.py +6 -3
- package/runtime/python/okstra_ctl/domain/worker_presentation.py +70 -9
- package/runtime/python/okstra_ctl/entrypoints/hosts.py +16 -30
- package/runtime/python/okstra_ctl/error_log_write.py +35 -30
- package/runtime/python/okstra_ctl/error_report.py +26 -1
- package/runtime/python/okstra_ctl/error_zip.py +27 -5
- package/runtime/python/okstra_ctl/execution_identity.py +3 -2
- package/runtime/python/okstra_ctl/execution_manifest.py +7 -4
- package/runtime/python/okstra_ctl/execution_mutation_audit.py +6 -2
- package/runtime/python/okstra_ctl/final_report_schema.py +26 -17
- package/runtime/python/okstra_ctl/fix_cycles.py +2 -2
- package/runtime/python/okstra_ctl/fixed_text.py +39 -0
- package/runtime/python/okstra_ctl/git_reconcile.py +41 -9
- package/runtime/python/okstra_ctl/handoff.py +5 -4
- package/runtime/python/okstra_ctl/i18n.py +4 -2
- package/runtime/python/okstra_ctl/implementation_direction.py +22 -14
- package/runtime/python/okstra_ctl/implementation_outcome.py +4 -7
- package/runtime/python/okstra_ctl/incremental_carry.py +130 -17
- package/runtime/python/okstra_ctl/incremental_scope.py +12 -4
- package/runtime/python/okstra_ctl/index.py +8 -11
- package/runtime/python/okstra_ctl/initial_prompt_materialization.py +79 -7
- package/runtime/python/okstra_ctl/invocation.py +3 -6
- package/runtime/python/okstra_ctl/json_boundary.py +366 -0
- package/runtime/python/okstra_ctl/json_registry.py +10 -12
- package/runtime/python/okstra_ctl/jsonl.py +19 -2
- package/runtime/python/okstra_ctl/lead_events.py +33 -1
- package/runtime/python/okstra_ctl/listing.py +3 -3
- package/runtime/python/okstra_ctl/log_report.py +24 -2
- package/runtime/python/okstra_ctl/manager_cli.py +92 -7
- package/runtime/python/okstra_ctl/manager_store.py +12 -10
- package/runtime/python/okstra_ctl/material.py +5 -1
- package/runtime/python/okstra_ctl/migrate.py +29 -25
- package/runtime/python/okstra_ctl/model_cli.py +3 -15
- package/runtime/python/okstra_ctl/model_io_cli.py +1051 -0
- package/runtime/python/okstra_ctl/mutation_probe.py +13 -4
- package/runtime/python/okstra_ctl/pane_reclaim.py +3 -2
- package/runtime/python/okstra_ctl/path_hints.py +12 -0
- package/runtime/python/okstra_ctl/paths.py +21 -0
- package/runtime/python/okstra_ctl/plan_items.py +115 -4
- package/runtime/python/okstra_ctl/plan_items_cli.py +626 -34
- package/runtime/python/okstra_ctl/ports/worker_dispatch.py +2 -1
- package/runtime/python/okstra_ctl/pr_template.py +3 -2
- package/runtime/python/okstra_ctl/project_meta.py +5 -7
- package/runtime/python/okstra_ctl/recap.py +5 -4
- package/runtime/python/okstra_ctl/reconcile.py +21 -27
- package/runtime/python/okstra_ctl/registry/host_discovery.py +3 -2
- package/runtime/python/okstra_ctl/registry/provider_registry.py +3 -2
- package/runtime/python/okstra_ctl/render.py +74 -16
- package/runtime/python/okstra_ctl/render_final_report.py +10 -8
- package/runtime/python/okstra_ctl/report_assembly.py +509 -0
- package/runtime/python/okstra_ctl/report_contract.py +2 -1
- package/runtime/python/okstra_ctl/report_finalize.py +67 -32
- package/runtime/python/okstra_ctl/report_html/render.py +3 -2
- package/runtime/python/okstra_ctl/report_inputs.py +72 -0
- package/runtime/python/okstra_ctl/report_language.py +3 -2
- package/runtime/python/okstra_ctl/report_markdown.py +81 -8
- package/runtime/python/okstra_ctl/report_narrative.py +351 -0
- package/runtime/python/okstra_ctl/report_projections.py +265 -0
- package/runtime/python/okstra_ctl/report_synthesis_packet.py +518 -0
- package/runtime/python/okstra_ctl/report_views.py +3 -2
- package/runtime/python/okstra_ctl/rollup.py +65 -4
- package/runtime/python/okstra_ctl/run.py +184 -65
- package/runtime/python/okstra_ctl/run_audit.py +3 -2
- package/runtime/python/okstra_ctl/run_context.py +6 -9
- package/runtime/python/okstra_ctl/run_index_row.py +2 -8
- package/runtime/python/okstra_ctl/schedule_semantics.py +5 -2
- package/runtime/python/okstra_ctl/schema_excerpt.py +15 -8
- package/runtime/python/okstra_ctl/session_transcript.py +27 -1
- package/runtime/python/okstra_ctl/set_work_status.py +64 -38
- package/runtime/python/okstra_ctl/stage_fix_carry.py +8 -6
- package/runtime/python/okstra_ctl/stage_ledger.py +132 -18
- package/runtime/python/okstra_ctl/stage_map.py +96 -28
- package/runtime/python/okstra_ctl/stage_targets.py +3 -4
- package/runtime/python/okstra_ctl/team.py +3 -2
- package/runtime/python/okstra_ctl/team_reconcile.py +11 -2
- package/runtime/python/okstra_ctl/time_report.py +51 -4
- package/runtime/python/okstra_ctl/usage_identity.py +2 -1
- package/runtime/python/okstra_ctl/usage_report.py +58 -4
- package/runtime/python/okstra_ctl/user_response.py +1431 -66
- package/runtime/python/okstra_ctl/wizard.py +11 -44
- package/runtime/python/okstra_ctl/work_categories.py +3 -2
- package/runtime/python/okstra_ctl/worker_dispatch.py +5 -2
- package/runtime/python/okstra_ctl/worker_prompt_body.py +49 -3
- package/runtime/python/okstra_ctl/worker_prompt_contract.py +3 -2
- package/runtime/python/okstra_ctl/worker_prompt_policy.py +31 -3
- package/runtime/python/okstra_ctl/worker_runner.py +14 -12
- package/runtime/python/okstra_ctl/workflow.py +2 -1
- package/runtime/python/okstra_ctl/worktree.py +3 -2
- package/runtime/python/okstra_ctl/wrapper_status.py +4 -2
- package/runtime/python/okstra_ctl/write_policy.py +4 -2
- package/runtime/python/okstra_token_usage/antigravity.py +39 -12
- package/runtime/python/okstra_token_usage/collect.py +90 -38
- package/runtime/python/okstra_token_usage/grok.py +127 -0
- package/runtime/schemas/final-report-v2.0.schema.json +9 -0
- package/runtime/schemas/final-report-v3.0.schema.json +10219 -0
- package/runtime/schemas/report-narrative-v3.0.schema.json +30 -0
- package/runtime/schemas/report-synthesis-packet-v1.0.schema.json +140 -0
- package/runtime/skills/okstra-brief-gen/SKILL.md +9 -7
- package/runtime/skills/okstra-code-review/SKILL.md +21 -11
- package/runtime/skills/okstra-container-build/SKILL.md +18 -18
- package/runtime/skills/okstra-inspect/SKILL.md +12 -11
- package/runtime/skills/okstra-inspect/facets/error-zip.md +8 -8
- package/runtime/skills/okstra-inspect/facets/errors.md +2 -2
- package/runtime/skills/okstra-inspect/facets/history.md +9 -14
- package/runtime/skills/okstra-inspect/facets/logs.md +2 -2
- package/runtime/skills/okstra-inspect/facets/recap.md +5 -5
- package/runtime/skills/okstra-inspect/facets/report.md +6 -10
- package/runtime/skills/okstra-inspect/facets/status.md +9 -8
- package/runtime/skills/okstra-inspect/facets/time.md +3 -3
- package/runtime/skills/okstra-manager/SKILL.md +16 -14
- package/runtime/skills/okstra-memory/SKILL.md +3 -3
- package/runtime/skills/okstra-pr-gen/SKILL.md +5 -4
- package/runtime/skills/okstra-rollup/SKILL.md +6 -16
- package/runtime/skills/okstra-run/SKILL.md +7 -7
- package/runtime/skills/okstra-schedule-gen/SKILL.md +21 -17
- package/runtime/skills/okstra-setup/SKILL.md +21 -13
- package/runtime/skills/okstra-setup/references/project-config.md +2 -2
- package/runtime/skills/okstra-usage/SKILL.md +10 -10
- package/runtime/skills/okstra-user-response/SKILL.md +78 -107
- package/runtime/templates/report-writer-prompt-preamble.md +29 -19
- package/runtime/templates/reports/html/macros/forms.html +6 -4
- package/runtime/templates/reports/schedule.template.md +4 -4
- package/runtime/templates/worker-error-contract.md +17 -29
- package/runtime/validators/validate-run.py +636 -72
- package/runtime/validators/validate_session_conformance.py +43 -7
|
@@ -1,459 +1,119 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Report Writer and Report Assembly Contract
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Phase 6 ownership
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Phase 6 gives the report writer all settled analysis, convergence, task, and planning context required for synthesis. Read access supplies context; it does not grant write authority over another owner's file.
|
|
6
6
|
|
|
7
|
-
The
|
|
7
|
+
The report writer writes only the report narrative Markdown, its pointer record, and its audit sidecar. It must not write or patch `final-report-*.data.json`, the approval decision ledger, activity ledger, team state, convergence state, or design-preparation input.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
The narrative owns judgments, plan body, summaries, user explanation, recommended steps, and follow-up descriptions. It never owns `designPreparation`, `designSurfaceCoverage`, `executionStatus`, `executionRoles`, `tokenUsage`, `crossVerification`, `approvalContext`, `clarificationItems`, `agentActivity`, or `planBodyVerification`. It must not pre-fill a future round, future gate result, activity identifier, usage value, or resolution.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Report assembly reads the role-owned inputs, validates them, derives links and statuses, and publishes the final record once. An error identifies `owner`, `artifactPath`, `fieldPath`, and `reason`; return it only to the named owner.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
## Role-owned inputs
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
| Input | Owner | Write boundary |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| report narrative Markdown | report-writer | `reportNarrativePath` |
|
|
18
|
+
| approval decision ledger | lead | `approvalDecisionsPath` through `okstra approval-decision` |
|
|
19
|
+
| activity ledger | activity recorder | `leadEventsPath` through `okstra agent-activity append` |
|
|
20
|
+
| team state and usage | runtime/accounting adapter | `teamStatePath` |
|
|
21
|
+
| convergence state and plan-body result | convergence engine | `convergenceStatePath` |
|
|
22
|
+
| design-preparation snapshot | design-surface detector | `designPreparationPath` |
|
|
23
|
+
| final report record | report assembly | `expectedReportRecordPath` |
|
|
16
24
|
|
|
17
|
-
|
|
25
|
+
An active clarification exists only in `activeClarifications[]`. A decision carried from a previous run exists only in `carriedDecisions[]`; do not recreate it as an active question.
|
|
18
26
|
|
|
19
|
-
|
|
27
|
+
Each decision option has `role`, `answer`, `rationale`, `disposition`, `reach`, optional `scopeEffects`, `addedWork`, and `directionChange`. `reach` is exactly one of `in-repo` or `cross-repo`. `scopeEffects` may contain `new-schema` and `deferrable`. A `correctness-critical` option cannot use `select` or `accept-risk`; a `noncritical-dissent` option cannot use `select`.
|
|
20
28
|
|
|
21
|
-
|
|
29
|
+
Resolution `checkRefs` name existing `A-NNN` activity rows. Those activity rows carry `clarificationRefs[]`; their `planItemIds[]` let report assembly derive the reverse plan-item links. Do not store copied plan or activity identifiers in `approvalContext`.
|
|
22
30
|
|
|
23
|
-
|
|
31
|
+
## Report-writer dispatch
|
|
24
32
|
|
|
25
|
-
|
|
33
|
+
For report contract 3.0, prompt materialization first freezes one report synthesis
|
|
34
|
+
packet. The packet contains the task brief, analysis packet, report template,
|
|
35
|
+
report schema, convergence state, every successful settled worker result recorded
|
|
36
|
+
by the run manifest, accumulated `user-responses/` sidecars, and the current
|
|
37
|
+
session/token/cost accounting snapshot. Each file-backed source carries its owner,
|
|
38
|
+
project-relative path, SHA-256 digest, and value. The report writer receives the
|
|
39
|
+
packet's Markdown reading projection as the only task input instead of an
|
|
40
|
+
independently assembled list of raw paths.
|
|
26
41
|
|
|
27
|
-
|
|
28
|
-
-
|
|
29
|
-
|
|
42
|
+
The packet's authoring contract names the result path, narrative format, writing
|
|
43
|
+
instructions, runtime-owned content, and validation rules. Missing configured
|
|
44
|
+
paths and missing files are collected across the full source set before dispatch
|
|
45
|
+
and reported together with their owners. Report assembly compares every frozen
|
|
46
|
+
source digest again and reports every changed or missing source in one result.
|
|
47
|
+
This is enforced by
|
|
48
|
+
`initial_prompt_materialization._materialize_report_writer_packet()`,
|
|
49
|
+
`report_synthesis_packet.build_report_synthesis_packet()`, and
|
|
50
|
+
`report_assembly.assemble_report()`.
|
|
30
51
|
|
|
31
|
-
|
|
52
|
+
Materialize the duty prompt with `okstra agent-prompt materialize --audience report-writer`. The prompt starts with these anchors in order:
|
|
32
53
|
|
|
33
|
-
1.
|
|
34
|
-
2.
|
|
35
|
-
3.
|
|
36
|
-
4.
|
|
37
|
-
5.
|
|
38
|
-
6.
|
|
54
|
+
1. `**Project Root:**`
|
|
55
|
+
2. `**Prompt History Path:**`
|
|
56
|
+
3. `**Result Path:**`
|
|
57
|
+
4. `**Worker Result Path:**`
|
|
58
|
+
5. `**Worker Preamble Path:**`
|
|
59
|
+
6. `**Worker Error Contract Path:**`
|
|
60
|
+
7. `**Errors log path:**`
|
|
61
|
+
8. `**Errors sidecar path:**`
|
|
39
62
|
|
|
40
|
-
The
|
|
63
|
+
The errors sidecar anchor reserves the runtime-owned write-artifact path used by dispatch validation. No model-authored error JSON file is part of report-writer dispatch; failures use the typed error-log command from the worker error contract.
|
|
41
64
|
|
|
42
|
-
|
|
65
|
+
Register the dispatch with `okstra agent-prompt record-dispatch`. When `terminalBackend` is `cmux-pane`, run `okstra team dispatch`; for `runner: cli-wrapper`, run `okstra worker-dispatch --audience report-writer`. Attach the result through `okstra agent-prompt link-result`. The result path is the report narrative Markdown, not the final record.
|
|
43
66
|
|
|
44
|
-
|
|
45
|
-
2. `**Prompt History Path:** <project-relative-path>` (under current run `prompts/`)
|
|
46
|
-
3. `**Result Path:** runs/<task-type>/reports/final-report-<task-type>-<seq>.data.json` — canonical JSON SSOT. The full reading copy is rendered on demand.
|
|
47
|
-
4. `**Worker Result Path:** runs/<task-type>/worker-results/report-writer-worker-<task-type>-<seq>.md` — canonical three-path worker-result pointer and source for the audit-path derivation.
|
|
48
|
-
5. `**Audit sidecar path:** <absolute-path>` — the generated report-writer heartbeat/read-confirmation destination derived from the Markdown `**Worker Result Path:**`, never from Result Path.
|
|
49
|
-
6. `Assigned worker prompt history path: <absolute-path>`
|
|
50
|
-
7. The four BLOCKING dispatch anchor headers generated from the report-writer audience (the worker cannot synthesize any of these paths):
|
|
51
|
-
- `**Worker Preamble Path:** <absolute-path>` — selects `templates/report-writer-prompt-preamble.md`.
|
|
52
|
-
- `**Worker Error Contract Path:** <absolute-path>` — selects `templates/worker-error-contract.md`.
|
|
53
|
-
- `**Errors log path:** <absolute-path>` — run-level errors JSONL (`logs/errors-<task-type>-<seq>.jsonl`).
|
|
54
|
-
- `**Errors sidecar path:** <absolute-path>` — this worker's per-run sidecar JSON (`worker-results/report-writer-worker-errors-<task-type>-<seq>.json`).
|
|
55
|
-
8. `**Prompt Delivery Mode:** <mode>` — the selected adapter's declared `initialPromptDeliveryMode`.
|
|
56
|
-
9. `**Model:** Report writer worker, <modelExecutionValue>` (resolved per Phase 5.5 anchor-header rules)
|
|
57
|
-
10. The full `[Required reading]` clause (see [team-contract](./team-contract.md)) — for Phase 6 it adds two **per-task-type, instruction-set-local** read-only files, both scoped to this run's task-type by `okstra-ctl` at prep time:
|
|
58
|
-
- `<instruction-set>/final-report-schema.json` — a task-type excerpt of schema v2. This is the binding authoring shape; the installed full schema is what the run is judged against. Do **NOT** pull the full repository schema because it is outside the task bundle.
|
|
59
|
-
- `<instruction-set>/final-report-template.md` — the full reading copy template. It shows the agent-facing ledger shape, not the human presentation. The task-specific HTML renderer reads data.json separately.
|
|
60
|
-
11. The analysis packet path plus a one-line MCP pointer instead of copying the server block verbatim: `**MCP servers:** follow the analysis packet's "Available MCP Servers" section. If the section is absent or says none, treat MCP as unavailable for this run; never infer tools from host configuration.`
|
|
61
|
-
12. `Convergence state: runs/<task-type>/state/convergence-<task-type>-<seq>.json`, followed by pointers to all analysis-worker result files under `worker-results/`. The convergence path is deterministic and is listed even before Phase 5.5 creates the file. Read its classifications (Full/Partial/Contested/Worker-Unique), `roundHistory[]`, `round2SkippedReason`, and `finalClassificationCounts`; populate `crossVerification.roundHistory` in data.json so Section 6 can show which rounds executed, queue sizes, and why Round 2 was (or was not) skipped. The renderer prints the full per-round table only when more than one round ran; single-round or zero-round histories are auto-collapsed to a one-line summary.
|
|
62
|
-
13. `**Report Language:** <en|ko>` — must be either `en` or `ko`; `auto`
|
|
63
|
-
has been resolved by the lead from project.json / global config
|
|
64
|
-
before the dispatch is constructed. The worker copies this verbatim
|
|
65
|
-
into `data.json.meta.reportLanguage`.
|
|
66
|
-
14. An explicit instruction: `You are the author of TWO files: (a) the report record at <Result Path>, and (b) the worker-result pointer at <Worker Result Path>. Maintain the separate heartbeat audit sidecar at <Audit sidecar path>. Do not return the report inline. Do not invoke okstra render-final-report. The dispatch fails when either completion artifact is missing, and session conformance fails when the audit sidecar is missing or invalid.`
|
|
67
|
-
15. The prose budget (dedup contract): `verdictCard.finalConclusion` is the conclusion SSOT — at most 3 sentences. `rationale.*` fields stay within 2 sentences each; `humanSummary` entries stay concise; task `userNarrative` explains each user-facing section once with evidence references. Do not copy these narratives into the AI Markdown. `summary` stays at 3-5 rows unless the run covers multiple tickets. Generation time scales with output volume, so exceeding the budget is a cost bug, not extra diligence.
|
|
67
|
+
The pointer record contains the narrative and audit paths. Completion never depends on the final record because assembly runs after writer completion.
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
## Implementation-planning sequence
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
1. Dispatch the report writer and wait for the narrative and pointer.
|
|
72
|
+
2. Parse the narrative and extract the deterministic plan-item queue without publishing `data.json`.
|
|
73
|
+
3. Run initial plan-body verification as round 1.
|
|
74
|
+
4. Apply at most one automatic planner self-fix to the narrative.
|
|
75
|
+
5. Run targeted re-verification as round 2 when needed.
|
|
76
|
+
6. Persist the completed `planBodyVerification` value in convergence state.
|
|
77
|
+
7. Complete the design-surface detector snapshot.
|
|
78
|
+
8. Run Phase 7 report assembly.
|
|
72
79
|
|
|
73
|
-
|
|
80
|
+
The writer never predicts steps 3–7 in its draft. The plan-body verifier reads the plan body, and report assembly adds its completed result afterward.
|
|
74
81
|
|
|
75
|
-
A
|
|
82
|
+
**Implementation-planning direction branch.** A selected-direction narrative carries `selectedDirectionRef` and `directionRealization`; the `P-Dir-1` verifier checks that realization against the selected core mechanism, architecture boundaries, planning invariants, and any hidden direction change. A legacy candidate-comparison narrative retains `P-Opt-*` option comparison semantics. These are plan-body judgments, not frontmatter fields owned by the writer.
|
|
76
83
|
|
|
77
|
-
|
|
84
|
+
**Implementation-option-selection comparison.** Candidate details remain direction-level and must not claim planning precision:
|
|
78
85
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
1. A Report writer worker dispatch was actually attempted through `dispatch_worker`.
|
|
82
|
-
2. The attempt recorded a terminal status of `error`, `timeout`, or `not-run` with a concrete reason (tool error message, timeout duration, or external blocker).
|
|
83
|
-
3. The reason is logged via `okstra error-log append-observed --error-type cli-failure ...` (or `tool-failure` if the failure was internal).
|
|
84
|
-
4. **The user permitted it.** Ask at a gate, and have the answer written to this run's `user-responses/` sidecar as a `## REPORT AUTHORING` block with `- Status: approved` (`okstra user-response write --report <data.json> --answers '[]' --report-authoring '{"status":"approved","reason":"<the user's words>"}'`). A failed dispatch is your cue to ask, not your permission — a lead that dispatches once, watches it fail, and proceeds has still decided alone. You cannot write this block for yourself; it is the user's answer, in the user's file.
|
|
85
|
-
5. **Record it in the report.** Set `header.leadAuthoredFallback` with `dispatchFailureReason` quoted verbatim from the failed dispatch row and `approvalSidecar` set to that sidecar's project-relative path. The approval passes the gate; it does not retire it. This block renders under `Report Author`, so someone reading the report months later sees that this run left the report-writer path and why, without having to find the sidecar.
|
|
86
|
-
|
|
87
|
-
Speculative reasons such as "session resume constraint", "runtime state is unavailable", or "lead can do it faster" are NOT valid.
|
|
88
|
-
|
|
89
|
-
**Enforced:** `validators/validate-run.py` `_validate_lead_authored_report` checks all of it — the terminal failure status, its reason, the approving sidecar block, and the `header.leadAuthoredFallback` record whose reason must match the dispatch row. `release-handoff` is exempt because it never dispatches a report writer.
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
## Phase 6 → Phase 7 execution sequence (BLOCKING order)
|
|
93
|
-
|
|
94
|
-
Phase 6 first produces the report record at `runs/<task-type>/reports/final-report-<task-type>-<seq>.data.json`. Token Usage cells are `null` at this point, and Section 3 does not yet include auto-spawned follow-ups.
|
|
95
|
-
|
|
96
|
-
For an implementation-planning run, the Report writer worker owns the Phase 6 design assessment snapshot: it writes `designPreparation` and every stage's `designSurfaceCoverage` into data.json from the detector output and consolidated plan. It does not create user inputs, consume a user answer as if it were part of that snapshot, or materialize `design-prep-requests/`; `schemas/final-report-v2.0.schema.json` and `validators/validate-run.py` `_validate_design_prep_contract` enforce the snapshot shape, detector coverage, and references.
|
|
97
|
-
|
|
98
|
-
### Before `report-finalize`: the translation sidecar (BLOCKING order)
|
|
99
|
-
|
|
100
|
-
The finalization renderer overlays the translation sidecar, so a non-English run must produce that sidecar before finalization. Use this fixed order:
|
|
101
|
-
|
|
102
|
-
1. **For a non-English report only**, run `okstra report-finalize ... --only project-activity --only check-source`. The shared finalizer projects canonical activity before checking the English source. A historical manifest without `activityContractVersion: 1` leaves data.json unchanged.
|
|
103
|
-
2. **Only when that check passes**, dispatch the translator worker, which writes `final-report-<task-type>-<seq>.i18n.<lang>.json`.
|
|
104
|
-
3. Run the full `report-finalize` command below. English reports start here; the finalizer repeats the idempotent projection and source check before every downstream step.
|
|
105
|
-
|
|
106
|
-
For step 2, write translator-only task instructions and run `okstra
|
|
107
|
-
agent-prompt materialize` with `--audience translator`, `--assignment-ref
|
|
108
|
-
translator`, `--worker-id translator`, and `--dispatch-kind translator`. Run
|
|
109
|
-
`okstra agent-prompt verify` on the returned `metadataPath` before dispatch and
|
|
110
|
-
use the returned `promptPath` unchanged. A native-session call uses only
|
|
111
|
-
`hostModelValue`; first run `okstra agent-prompt record-dispatch` with the run
|
|
112
|
-
manifest, metadata path, and `--enforcement-mode
|
|
113
|
-
host-native-spec-link-gate`, then run `okstra agent-prompt link-result` with
|
|
114
|
-
`--dispatch-id <invocationId>:attempt-1` and the translation result before
|
|
115
|
-
accepting it. A CLI-wrapper call uses `okstra team dispatch` when `terminalBackend` is
|
|
116
|
-
`cmux-pane`, or `okstra worker-dispatch` and its `modelExecutionValue`
|
|
117
|
-
otherwise. The host-native record links the accepted result to a
|
|
118
|
-
verified call specification but does not assert that Okstra observed the host's
|
|
119
|
-
actual prompt delivery.
|
|
120
|
-
|
|
121
|
-
**Never dispatch the translator before step 1.** The data.json is the English SSOT; a report-writer that authored it in the reader's language produces a translation *from that language into itself* — a full-cost, entirely useless artifact, and the run still fails at `check-source` afterwards. **Enforced:** `okstra report-translate extract` refuses to build a work list from a data.json over the Korean-prose limit, so a mis-ordered dispatch fails at the translator's first command instead of after it. When it does fail, the fix is a report-writer rewrite in English — discard the sidecar and `translation-source.json` produced from the Korean draft rather than editing them, because their English column is not English.
|
|
122
|
-
|
|
123
|
-
Phase 7 post-processing is then **one command**. `okstra report-finalize` owns the ordered sequence — it is the same code path the Codex lead adapter runs automatically, so a Claude-led run and a Codex-led run finalize identically:
|
|
124
|
-
|
|
125
|
-
```bash
|
|
126
|
-
okstra report-finalize \
|
|
127
|
-
--project-root <project_root> \
|
|
128
|
-
--run-manifest <runDirectoryPath>/manifests/run-manifest-<task-type>-<seq>.json \
|
|
129
|
-
--report <runDirectoryPath>/reports/final-report-<task-type>-<seq>.data.json
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
Do NOT run the seven steps below by hand. Hand-running them is the recurring root cause of reports shipping with stale activity, `--` token cells, a missing html sibling, Section 3 missing follow-up entries, or Section 4 rows never spawning — the order is load-bearing and a skipped step surfaces only later, as a validator `contract-violated`. Every step is idempotent, so after fixing a reported failure just re-run the same command.
|
|
133
|
-
|
|
134
|
-
The steps it executes, in this contractual order, and the contract each one carries:
|
|
135
|
-
|
|
136
|
-
1. **`project-activity` — project canonical activity.** Replaces only `agentActivity[]` from this run's canonical events before translation source extraction. A legacy manifest without activity contract v1 is a byte-preserving no-op. Conformance compares IDs, order, and every core field against the canonical events.
|
|
137
|
-
2. **`check-source` — verify the data.json is English.** The same gate as the pre-translator check above, run again here because everything after it derives from the data.json: rendering a Korean SSOT into English chrome, spawning follow-ups from it, and validating it all succeed on a record the next phase cannot read. A failure here means the report-writer authored in the reader's language; re-dispatch it with the English rule rather than editing the data.json by hand.
|
|
138
|
-
3. **`token-usage` — collect usage.** Aggregates `leadUsage` / `workers[].usage` / `usageSummary` into team-state and populates `tokenUsage` and the execution-status usage fields in data.json. It does not render the full reading copy.
|
|
139
|
-
|
|
140
|
-
The data.json paths populated: `tokenUsage.lead.{totalTokens,billableTokens,costUsd}`, the `worker` / `grand` rows, `tokenUsage.cli.costUsd`, and each `executionStatus[].{totalTokens,billableTokens,costUsd,durationMs,cliTotalTokens,cliCostUsd}` for rows whose role matches a team-state worker. The data.json MUST already exist (Phase 6 output).
|
|
141
|
-
|
|
142
|
-
For implementation-planning, this Phase 7 canonical render calls `materialize_design_prep_requests()` after token substitution and creates deterministic request files only for `provisional` / `blocked` items. Later answers are append-only user-input sidecars; request generation and user input never rewrite the assessment fields, so the source report remains immutable as the design-input snapshot after this render. `validators/validate-run.py` `_validate_design_prep_requests` enforces request existence, canonical path, content, and assessment fingerprint.
|
|
143
|
-
4. **`render-views` — render the human report artifact.** Runs against the substituted v2 data.json and its Markdown sibling.
|
|
144
|
-
|
|
145
|
-
Output (idempotent — re-running overwrites):
|
|
146
|
-
- `runs/<task-type>/reports/final-report-<task-type>-<seq>.html` — single-file self-contained human view, always generated for schema v2 from the dedicated template registered for that task type. Clarification rows with `Status` ∈ {`open`, `answered`} embed response controls and export a `user-response-<task-type>-<seq>.md` sidecar. The original data and Markdown artifacts are never mutated by user input.
|
|
147
|
-
- the implementation-planning report renders a **Plan Approval** section at the end of the body — an implementation-option `<select>` plus approval checkbox for legacy candidate-comparison, and an approval checkbox only for selected-direction plans. It stays disabled while any §1 `Blocks: approval` row is unresolved.
|
|
148
|
-
- Schema-v1 and quick compatibility reports retain the legacy conditional HTML path; this does not change the schema-v2 always-generated contract.
|
|
149
|
-
|
|
150
|
-
It runs after usage collection so token placeholders are substituted in any rendered html, and before routing persistence so the html artifact, when generated, exists for the validator step that checks it. It also overlays the translation sidecar, which is why a non-English run must dispatch the translator before this command — see the ordering rule above.
|
|
151
|
-
5. **`spawn-followups` — routing and follow-up persistence.** Turns the report's `## 4. Follow-up Tasks` rows into `tasks/<task-group>/<new-task-id>/` stubs.
|
|
152
|
-
|
|
153
|
-
Behaviour contract:
|
|
154
|
-
- Idempotent: rows whose target dir exists are reported as `existing` and skipped. Reruns of the same parent task are safe.
|
|
155
|
-
- Rows with `autoSpawn != "yes"` are reported as `skipped` and never written; surface them in Section 3 if manual action is still needed.
|
|
156
|
-
- Rows whose `origin` is `phase-continuation` are reported as `skipped (no new task dir)` and never spawn — they advance the same task-key via `/okstra-run` instead.
|
|
157
|
-
- An invalid `origin`, `suggestedTaskType`, missing `title`, missing `reason`, or missing `newTaskId` exits `1`. (Schema validation in Phase 6 catches most of these before the spawner runs.)
|
|
158
|
-
- **Canonical spawn rule (single source of truth):** the spawner runs when `task-type` ∈ {`implementation`, `final-verification`, `release-handoff`}, OR when `followUpTasks` is non-empty for any other task-type. For the listed task-types `followUpTasks` must be present (schema enforces the phase-continuation row for non-terminal task-types); an empty array is permitted only for `release-handoff`. Missing arrays are no-ops (exit `0`). All other references to this rule (including the Persistence Checklist) defer to this statement.
|
|
159
|
-
After the spawner, the report writer MUST append one row per newly spawned task-key with its entry command:
|
|
160
|
-
|
|
161
|
-
```
|
|
162
|
-
- Follow-up: `<task-group>/<new-task-id>` — in-session `/okstra-run task-key=<task-group>/<new-task-id> task-type=<suggested>` / standalone `scripts/okstra.sh --task-key <task-group>/<new-task-id> --task-type <suggested>`
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
The status file is written after routing and follow-up persistence completes.
|
|
166
|
-
6. **`validate-run` — validate the finished run.** Checks the completed artifact set, including exact canonical-event-to-`agentActivity[]` conformance and the report-views contract that catches a missing or stale html sibling. A failure here names the specific contract; fix it and re-run `okstra report-finalize`.
|
|
167
|
-
|
|
168
|
-
7. **`teardown-stages` — reclaim the stage worktrees.** In-process, and a no-op for every run except a whole-task `final-verification` whose verdict clears the work for release (`accepted`, or `conditional-accept` with no condition blocking release). Whole-task entry merges the done stages but deliberately leaves their worktrees and registry stage-keys in place, because a `blocked` verdict routes straight back to rework on those trees. This step is where they are reclaimed once the verdict says the work is moving on. A stage worktree with uncommitted changes is preserved; stage branches are never deleted.
|
|
169
|
-
|
|
170
|
-
After `okstra report-finalize` reports `"ok": true`, **execute the run-scoped cleanup gate.** Call `shutdown_workers` only after that success, all persistence work, and explicit user approval under [okstra-lead-contract](./okstra-lead-contract.md) "Run-scoped worker-resource lifecycle". If the user keeps resources, leave the selected adapter's resources intact and surface its manual cleanup guidance.
|
|
171
|
-
|
|
172
|
-
## Schema-v2 report data responsibilities
|
|
173
|
-
|
|
174
|
-
The binding authoring shape is the task bundle's `instruction-set/final-report-schema.json`. Populate both audiences in data.json: agent-facing verdict, routing, evidence, task facts, and audits; user-facing `humanSummary` and task `userNarrative`. The full reading copy template deliberately omits the full user narrative, while the task-specific HTML deliberately moves `crossVerification`, `executionStatus`, and `tokenUsage` into collapsed audit details.
|
|
175
|
-
|
|
176
|
-
## Legacy schema-v1 Markdown structure reference
|
|
177
|
-
|
|
178
|
-
The remaining numbered-section guide exists only for rendering or diagnosing historical schema-v1 data. New report-writer runs do not author against it; their instruction-set schema and full reading copy template are authoritative.
|
|
179
|
-
|
|
180
|
-
### Report Header
|
|
181
|
-
|
|
182
|
-
Read the exact permitted values for `header.reportOwner` and `header.reportAuthor` from the task bundle's `instruction-set/final-report-schema.json` excerpt, then write those values according to the actual authorship path. The current v2 contract uses the provider-neutral `Okstra lead`; a legacy v1 excerpt may retain historical compatibility values. Do not derive either header field from the selected runtime's provider-specific lead label. Runtime identity remains visible in the execution-status row and team-state audit fields.
|
|
183
|
-
|
|
184
|
-
```markdown
|
|
185
|
-
# <task-key> - Multi-Agent Cross Verification Final Report
|
|
186
|
-
- Date: <ISO 8601 timestamp>
|
|
187
|
-
- Task Key: <task-key>
|
|
188
|
-
- Task Type: <task-type>
|
|
189
|
-
- Report Owner: `<exact schema header.reportOwner compatibility value>`
|
|
190
|
-
- Report Author: `<exact schema header.reportAuthor compatibility value for the actual authorship path>`
|
|
191
|
-
- Lead model: `<lead-model>`
|
|
192
|
-
- Preparation Method: Final report authored by Report writer worker (or lead-authored fallback — record the documented dispatch failure reason here when applicable; the machine-readable record is `header.leadAuthoredFallback`, which is what the validator and the rendered report both read)
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
### Agent-Specific Execution Status Table
|
|
196
|
-
|
|
197
|
-
The template renders this table in the merged record-meta shape (same pattern as §1 / §2.1): one meta cell stacking the short fields, one findings cell. The writer supplies the per-agent fields in data.json; the rendered form is:
|
|
198
|
-
|
|
199
|
-
```markdown
|
|
200
|
-
| Record | Summary of Key Findings |
|
|
201
|
-
|--------|-------------------------|
|
|
202
|
-
| **<team-state.lead.agent>**<br>Role: <team-state.lead.role><br>Model: <model><br>Status: completed<br>Raw tokens: <tokens><br>Billable: <billable><br>Cost: <cost><br>Duration: <duration> | Final synthesis status |
|
|
203
|
-
| **<team-state.workers[].agent>**<br>Role: <team-state.workers[].role><br>Model: <model><br>Status: <status><br>Raw tokens: <tokens><br>Billable: <billable><br>Cost: <cost><br>Duration: <duration> | Key findings summary |
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
Table Generation Rules:
|
|
207
|
-
- **Exactly one row per team-state entry: the lead, then one per `team-state.workers[]` — never more, never fewer.** The first row's agent / role / usage come from `team-state.lead.agent` / `team-state.lead.role` / `leadUsage`. Each later row copies its `agent`, `role`, and `model` **verbatim from a `team-state.workers[]` entry** (e.g. role `Claude worker`, `Codex worker`, `Report writer worker`), ordered to follow `recommendedWorkers` / `resultContract.requiredWorkerRoles`. Do not infer labels from provider names.
|
|
208
|
-
- **Never split one worker into multiple function rows or invent role labels** (`Analysis verifier`, `Acceptance critic`, …). A provider that played several roles — e.g. codex ran both the analysis-verify pass and the acceptance-critic pass — is still **one** `team-state.workers[]` entry with **one** usage figure: name the roles it played in that row's *Summary of Key Findings* cell, not in extra rows. Extra or renamed rows break Phase-7 token attribution, which keys each row's tokens to a single team-state worker — a split or renamed row lands as `--`.
|
|
209
|
-
- **Raw tokens** = `usage.totalTokens` (input + output + cache_creation + cache_read; the raw volume processed).
|
|
210
|
-
- **Billable tokens** = `usage.billableEquivalentTokens` (cache reads weighted at 0.1×, cache_creation 1.25×, output 5×; useful as a single number for "how big was this session in cost terms").
|
|
211
|
-
- **Cost (USD)** = `usage.estimatedCostUsd`. For Codex/Antigravity workers that actually invoked the CLI, append `(+ CLI $X.XX)` from `usage.cliEstimatedCostUsd`.
|
|
212
|
-
- For Codex/Antigravity workers, append `(CLI: <cliTotalTokens>)` to the Raw tokens cell when `usage.cliTotalTokens` is set.
|
|
213
|
-
- Status values are retrieved from team-state; format duration as `Xm Ys` from `usage.durationMs`.
|
|
214
|
-
- Workers with status `not-run` or unavailable usage evidence show `--` for tokens/cost/duration; quote the `note` underneath the table if useful.
|
|
215
|
-
|
|
216
|
-
### Token Usage Summary Section
|
|
217
|
-
|
|
218
|
-
Place this section immediately after the execution status table.
|
|
219
|
-
|
|
220
|
-
Example (the Markdown renders in English whatever `meta.reportLanguage` says):
|
|
221
|
-
|
|
222
|
-
```markdown
|
|
223
|
-
### Token Usage Summary
|
|
224
|
-
|
|
225
|
-
| Item | Raw tokens | Billable tokens (input-equiv.) | Cost (USD) |
|
|
226
|
-
|------|------------|--------------------------------|------------|
|
|
227
|
-
| Lead | 10,479,327 | 1,769,798 | $26.55 |
|
|
228
|
-
| Worker subtotal | 7,988,699 | 2,075,192 | $25.43 |
|
|
229
|
-
| **Grand total** | **18,468,026** | **3,844,990** | **$51.97** |
|
|
230
|
-
| Codex/Antigravity CLI add-on | | | $4.12 |
|
|
231
|
-
|
|
232
|
-
> **How to read**: "Raw tokens" is the total tokens the model actually processed (input + output + cache_creation + cache_read). In long sessions cache_read can account for 95%+ making the number look large. "Billable tokens" weights cache_read at 0.1×, cache_creation at 1.25×, and output at 5× to give an input-equivalent figure closer to actual cost. Costs are estimates based on published Anthropic/OpenAI/Google pricing.
|
|
86
|
+
```json
|
|
87
|
+
{"candidateDetailBoundary":{"expectedChangeAreas":"direction-level-only","expectedVerification":"direction-level-signals-only","forbidden":["exact-file-lists","stage-lists","test-commands"]}}
|
|
233
88
|
```
|
|
234
89
|
|
|
235
|
-
|
|
236
|
-
- **You populate the data.json in Phase 6, BEFORE Phase 7 runs the collector.** Set `tokenUsage.lead.totalTokens` / `.billableTokens` / `.costUsd`, the `worker` and `grand` rows, `tokenUsage.cli.costUsd`, and each `executionStatus[].{totalTokens,billableTokens,costUsd,durationMs,cliTotalTokens,cliCostUsd}` to JSON `null`. The renderer emits `--` for nulls; `okstra-token-usage.py --substitute-data` populates them in Phase 7 and re-renders the markdown. Never set these cells to `0`, `"not-collected"`, `"--"`, `"N/A"`, or any other sentinel: nulls are the only valid placeholder, and the substitution step depends on them being null when it runs.
|
|
237
|
-
- Set `meta.reportLanguage` to the resolved `en` or `ko` value passed in
|
|
238
|
-
**Report Language**. `auto` is forbidden in this field — the lead has
|
|
239
|
-
already resolved it. The field records **which language the human HTML
|
|
240
|
-
renders in**, not the language you author in: you always author English
|
|
241
|
-
(see "Writing Guidelines" below). Phase 7 reads it to decide whether to
|
|
242
|
-
dispatch the translator.
|
|
243
|
-
- All values come from `usageSummary` (populated by `scripts/okstra-token-usage.py` at the start of Phase 7). Do not estimate or invent.
|
|
244
|
-
- **Lead** row: `usageSummary.leadTotalTokens` / `usageSummary.leadBillableEquivalentTokens` / `usageSummary.estimatedCostUsd.lead`.
|
|
245
|
-
- **Worker subtotal** row: `usageSummary.workerTotalTokens` / `usageSummary.workerBillableEquivalentTokens` / `usageSummary.estimatedCostUsd.claudeWorkers`.
|
|
246
|
-
- **Grand total** row: `usageSummary.grandTotalTokens` / `usageSummary.grandBillableEquivalentTokens` / sum of `lead + claudeWorkers`.
|
|
247
|
-
- **Codex/Antigravity CLI add-on** row: `usageSummary.estimatedCostUsd.cliWorkers`. The writer only supplies the value in data.json — the renderer emits the row when the CLI cost is > 0 and omits it entirely at 0 (`final-report.template.md` gates it on `tokenUsage.cli.costUsd > 0`), so do not expect a `$0.00` row in the rendered report.
|
|
248
|
-
- Format tokens with comma separators (e.g., `32,500`); format USD with two decimals (e.g., `$1.43`).
|
|
249
|
-
- If `lead` or any `worker.usage` records unavailable evidence, show `--` for that row and append a one-line note (`reason: <note>`).
|
|
250
|
-
- If pricing for a model is unknown, the script omits `estimatedCostUsd` for that block — show `N/A` in that column and add a note like `pricing missing for model <model>`.
|
|
251
|
-
|
|
252
|
-
### Implementation-planning section heading contract (schema v1 only)
|
|
253
|
-
|
|
254
|
-
**This does not apply to any run you will author.** New runs are schema v2 (`report_contract.CURRENT_REPORT_SCHEMA_VERSION`), and `validate_phase_boundary` returns before the substring scan when `schemaVersion == "2.0"` — the v2 deliverable is gated by the schema instead, whose `implementationPlanning` block requires every one of these contents as a named key. The v2 full reading copy template carries nine headings and serialises the plan as JSON beneath them, so it cannot produce these strings and is not expected to.
|
|
255
|
-
|
|
256
|
-
Reading this section as a live instruction is a known and expensive mistake: the writer is sent to author headings the v2 template has no place for, and the run reads as structurally unpassable when nothing is wrong with it. It is retained only for rendering or diagnosing historical schema-v1 reports.
|
|
257
|
-
|
|
258
|
-
For those v1 reports, the final report must contain section headings whose **lines include each of the 12 literal English substrings below**. The rows mirror `PLANNING_REQUIRED_SECTIONS` in `validators/validate-run.py`, which is the SSOT. **Enforced:** `tests/contract/test_planning_required_sections_ssot.py` fails when this table and that tuple diverge, and pins the v1 scoping above so the section cannot silently become unconditional again.
|
|
90
|
+
For historical schema-v1 Markdown only, the following heading table remains a read-side compatibility reference. It is not an authoring instruction for report contract 3.0.
|
|
259
91
|
|
|
260
92
|
| # | Required substring | Recommended heading form |
|
|
261
|
-
|
|
262
|
-
| 1 | `Option Candidates` | `### Option Candidates (Korean gloss)` |
|
|
263
|
-
| 2 | `Trade-off` | `### Trade-off Matrix (Korean gloss)` |
|
|
264
|
-
| 3 | `Recommended Option` | `### Recommended Option (Korean gloss)` |
|
|
265
|
-
| 4 | `Stage Map` | `## 5.5 Stage Map (Korean gloss)` — the per-stage sections hang off it. |
|
|
266
|
-
| 5 | `Stepwise Execution Order` | `### Stepwise Execution Order (Korean gloss)` |
|
|
267
|
-
| 6 | `Dependency` | `### Dependency / Migration Risk (Korean gloss)` |
|
|
268
|
-
| 7 | `Validation Checklist` | `### Validation Checklist (Korean gloss)` |
|
|
269
|
-
| 8 | `Rollback` | `### Rollback Strategy (Korean gloss)` |
|
|
270
|
-
| 9 | `Requirement Coverage` | `### Requirement Coverage (Korean gloss)` |
|
|
271
|
-
| 10 | `Plan Body Verification` + `Gate result:` | `### Plan Body Verification (Korean gloss)` containing a `Gate result:` line — copy `templates/reports/final-report-v2.template.md §5.5.9` verbatim. Validator checks both substrings. |
|
|
272
|
-
| 11 | `Cross-Project Dependencies` | `### Cross-Project Dependencies (Korean gloss)` — `_(none)_` when the plan is single-project. |
|
|
273
|
-
| 12 | `Decision Drafts` | `### Decision Drafts (Korean gloss)` |
|
|
274
|
-
|
|
275
|
-
**Never author a `User Approval Request` section.** The approval gate moved to the YAML frontmatter `approved: true|false` field, and `validators/validate-run.py` fails any report containing a `## User Approval Request` block or a `### 5.5.8 User Approval Request` stub. This paragraph replaces an earlier row that listed the heading as required — following it produced a report the validator rejected.
|
|
276
|
-
|
|
277
|
-
`Implementation Design Preparation` is NOT in the substring list: `templates/reports/final-report-v2.template.md` §5.5.10 renders that heading from `implementationPlanning.designPreparation`, so it is enforced by the schema + renderer rather than by a heading scan.
|
|
278
|
-
|
|
279
|
-
The English keyword is mandatory and the body of each section is written in English, like everything else you author — see "Writing Guidelines" below. For non-`implementation-planning` runs, omit this entire block — these headings are NOT validator-checked for other task-types.
|
|
280
|
-
|
|
281
|
-
The final-report template `templates/reports/final-report-v2.template.md` Section 5.5 already encodes this contract — copy that block verbatim and fill in.
|
|
282
|
-
|
|
283
|
-
### Self-fix rewrite (plan-body self-fix round)
|
|
284
|
-
|
|
285
|
-
Lead instructs a self-fix round as **cause groups**, not a flat `P-*` list (`plan-body-verification.md` §"Round protocol" step 7). Treat each group's `causeSummary` as the unit of work: remove that cause once, then confirm every derivative item it names is settled by that single correction. Correct the plan sections the group's items point to — do NOT rewrite the entire draft:
|
|
286
|
-
|
|
287
|
-
- abbreviated path → replace with the full relative path from `<PROJECT_ROOT>` (File Structure / Stepwise `files`).
|
|
288
|
-
- prose command → make it concrete as an executable command sequence including the working directory, arguments, and task-type.
|
|
289
|
-
- placeholder (e.g. `stage-<N>`) → replace with concrete filenames / a regeneration plan.
|
|
290
|
-
- requirement-coverage mapping error → remap to a real option/stage/step or XP row.
|
|
291
|
-
- missing/weak design-prep contract → fix with kind-specific inline detail or an AI-prepared PREP item carrying a concrete `aiProposal`. Do NOT invent facts requiring user/external authority — keep them `blocked` + request material.
|
|
292
|
-
|
|
293
|
-
**Carry the correction to its contradictions (BLOCKING).** "Only the section the item points to" bounds *which defect you fix*, not *how far the fix reaches*. When a correction changes a constant, an owner, a path, or a disposition, every other statement in the plan asserting the old value is now false — find and rewrite those too, in whatever section they sit.
|
|
294
|
-
|
|
295
|
-
**Enumerate before you edit.** Patching at the positions the lead named is what makes a round trade one defect for another: the correction lands, its siblings keep asserting the old value, and the next round finds a *new* contradiction the fix itself created. So for each cause group, first list every place the plan mentions that decision — grep the constant, the symbol, the path, the requirement ID across the whole plan body including rejected options, per-stage `Test case (…)` lines, `Acceptance`, `exitContract`, `stageValidation`, and the Requirement Coverage row — then reconcile each hit against the new decision and only then write. `okstra plan-items derivations --data <data.json> --response <user-response sidecar>` does that grep mechanically: it extracts the symbols, paths, and ids the answer names and returns every plan string that mentions one, as a pointer plus excerpt. Its output is candidates, not verdicts — which hits are now false is yours to decide — but starting from it is what stops the enumeration from being skipped, which is the observed failure (17 of 23 blocked items in one run were a recorded decision whose derivations were never swept). Record the enumeration in the group's supersession entry so the next round can see what was considered in scope. A patch that leaves its own contradictions standing produces the same defect class in the next round, so the loop spends its budget re-finding what the previous round created. Record each retirement in `implementationPlanning.supersessionLedger[]` exactly as the answer-carry-in rule requires (`_common-contract.md` §"Supersession").
|
|
296
|
-
|
|
297
|
-
**Record the reach.** For each cause group you rewrite, list the data.json paths you actually changed in that group's `rewrittenPaths`, and the subset of those lying outside the sections its `itemIds` point at in `outsideScopePaths` (e.g. `stages[0].stepwiseExecution`, `validationChecklist[3]`). Carrying a correction to its contradictions legitimately reaches past the flagged item, so the second list is a measurement and not a violation — no threshold is applied to either. It exists because "this round was a targeted correction, not a full regeneration" is currently a claim with nothing behind it, and a round that quietly rewrites the whole draft costs the same tokens every time it repeats. **Enforced:** `validators/validate-run.py` `_validate_self_fix_rewrite_scope` requires every `outsideScopePaths` entry to appear in `rewrittenPaths`.
|
|
298
|
-
|
|
299
|
-
After correcting, leave `self-fixed in round <N>: <what was fixed>` in that `planItems[].selfFixNote`. Do NOT set `planBodyVerification.selfFixRoundsApplied` — the lead owns that count and records it at the round's end, so promotion eligibility does not hang on a worker's self-report. `needs-user-input` items are NEVER a correction target — they are promoted to clarification as-is.
|
|
300
|
-
|
|
301
|
-
Lead may instruct several rounds (bounded by `selfFixMaxRounds`, see [plan-body-verification](./plan-body-verification.md) §"Round protocol" step 7). Each round targets only the items still broken, so a round that fixes nothing new ends the loop — correcting an item by breaking a sibling counts as no progress, not progress.
|
|
302
|
-
|
|
303
|
-
### Final-verification verdict token contract (BLOCKING)
|
|
304
|
-
|
|
305
|
-
When the run's `task-type` is `final-verification`, the report's `## 7. Final Verdict` table MUST contain a `Verdict Token` row whose value is **exactly one of** the literal strings below. The `release-handoff` profile reads this row as its entry gate; any other value blocks the next phase.
|
|
93
|
+
|---:|---|---|
|
|
306
94
|
|
|
307
|
-
|
|
308
|
-
|---|--------------------|---------|
|
|
309
|
-
| 1 | `accepted` | All acceptance criteria pass; `release-handoff` may proceed. |
|
|
310
|
-
| 2 | `conditional-accept` | Acceptance passes with caveats; user must resolve listed conditions before `release-handoff`. |
|
|
311
|
-
| 3 | `blocked` | Acceptance failed; routing returns to `error-analysis`, `implementation-option-selection`, or `implementation-planning` according to whether the cause, direction, or detailed plan failed. |
|
|
312
|
-
|
|
313
|
-
For every other task-type, set the `Verdict Token` cell to `not-applicable`. Do NOT omit the row — the template renders it for all task-types and downstream tooling expects the field to exist.
|
|
314
|
-
|
|
315
|
-
The final-report template `templates/reports/final-report-v2.template.md` Section 7 already encodes this contract — copy that block verbatim and fill in.
|
|
316
|
-
|
|
317
|
-
### Release-handoff section contract (release-handoff runs only)
|
|
318
|
-
|
|
319
|
-
When the run's `task-type` is `release-handoff`, the final report MUST include Section `## 5.6 Release Handoff Deliverables` with all eight sub-sections (`5.6.1` Source Verification Report, `5.6.2` Feature Branch & Working-Tree State, `5.6.3` User Selections, `5.6.4` Executed Commands, `5.6.5` Commit List, `5.6.6` Merge Conflict Probe, `5.6.7` Pull Request Outcome, `5.6.8` Routing Recommendation). Every entry is dictated by the lead's recorded git/gh command log and the user's verbatim answers to the H1/H2/H3 menu prompts. H1 choices are `local checkout`, `push + PR`, or `skip`; release-handoff records existing implementation commits and MUST NOT create new commits. If the user picked `skip` (H1) or `cancel` (H3), keep 5.6.3 populated but leave 5.6.4–5.6.6 explicitly empty per the template's empty-state lines.
|
|
320
|
-
|
|
321
|
-
**Single-lead authorship (release-handoff only):** release-handoff has no worker roster. The lead authors the final-report file directly — there is no `Report writer worker` dispatch to perform in Phase 6, no resume-safe dispatch concern, and no mandatory worker-results file for a report-writer role. The rest of this contract's dispatch / resume / fallback machinery applies ONLY when `Report writer worker` is in the roster (i.e. every task-type other than `release-handoff`).
|
|
322
|
-
|
|
323
|
-
The final-report template `templates/reports/final-report-v2.template.md` Section 5.6 already encodes this contract — copy that block verbatim and fill in. For non-`release-handoff` runs, omit Section 5.6 entirely.
|
|
324
|
-
|
|
325
|
-
### Mandatory worker-result pointer and audit sidecar (BLOCKING)
|
|
326
|
-
|
|
327
|
-
You (the report-writer worker) MUST write the worker-result pointer at `**Worker Result Path:**`, defaulting to:
|
|
328
|
-
|
|
329
|
-
```
|
|
330
|
-
runs/<task-type>/worker-results/report-writer-worker-<task-type>-<seq>.md
|
|
331
|
-
```
|
|
332
|
-
|
|
333
|
-
Its body contains exactly the project-relative data.json path and the convergence-state input path. Analysis-worker result files stay in `## Inputs`; do not copy their list into the pointer. **Enforced:** both dispatch adapters include this pointer in `WorkerJob.completion_paths` and refuse `completed` while it is absent.
|
|
334
|
-
|
|
335
|
-
The pointer's frontmatter and header follow `team-contract` "Result Frontmatter" and the standard worker-result header sections. Use `workerId: "report-writer"` and copy the remaining canonical values from `analysis-material.md`; do not duplicate the final-report body.
|
|
336
|
-
|
|
337
|
-
You MUST also write the separate heartbeat/read-confirmation audit file at `**Audit sidecar path:**`, derived from Worker Result Path and defaulting to:
|
|
338
|
-
|
|
339
|
-
```
|
|
340
|
-
runs/<task-type>/worker-results/report-writer-worker-audit-<task-type>-<seq>.md
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
The selected report-writer preamble defines that audit shape. **Enforced:** `validators/validate_session_conformance.py` checks its reading confirmation, progress stages, timestamps, and cadence whenever the role completes.
|
|
95
|
+
## Phase 6 → Phase 7 execution sequence (BLOCKING order)
|
|
344
96
|
|
|
345
|
-
|
|
97
|
+
Do not run the seven steps below manually. Invoke `okstra report-finalize`; contract 3.0 runs them in this order:
|
|
346
98
|
|
|
347
|
-
|
|
99
|
+
1. **`token-usage`** — collect usage into team state without touching the final record.
|
|
100
|
+
2. **`project-activity`** — report assembly validates every owner input and publishes the final record once.
|
|
101
|
+
3. **`check-source`** — verify the assembled English source.
|
|
102
|
+
4. **`render-views`** — render the Markdown reading copy and human HTML.
|
|
103
|
+
5. **`spawn-followups`** — materialize registered follow-up tasks.
|
|
104
|
+
6. **`validate-run`** — validate the record, views, run manifest, and team state.
|
|
105
|
+
7. **`teardown-stages`** — remove eligible stage worktrees after successful validation.
|
|
348
106
|
|
|
349
|
-
|
|
107
|
+
### Before `report-finalize`: the translation sidecar
|
|
350
108
|
|
|
351
|
-
|
|
352
|
-
- `motivation` — why we are doing this work (goal / context).
|
|
353
|
-
- `problem` — why this is a problem (the flaw in the current state).
|
|
354
|
-
- `approach` — what work is therefore needed (the chosen direction).
|
|
355
|
-
- `justification` — why this is a reasonable choice (versus alternatives, with rationale).
|
|
109
|
+
Never dispatch the translator before report assembly and `check-source`. For a non-English human report, first run `report-finalize --only token-usage --only project-activity --only check-source`; the extraction command refuses to build a work list from a non-English source. Then dispatch the translator worker with `okstra agent-prompt materialize --audience translator`, `okstra agent-prompt record-dispatch`, `okstra worker-dispatch --audience translator`, and `okstra agent-prompt link-result`. Resume with `report-finalize --only render-views --only spawn-followups --only validate-run --only teardown-stages`; do not assemble the record a second time.
|
|
356
110
|
|
|
357
|
-
|
|
111
|
+
## Routing pointer
|
|
358
112
|
|
|
359
|
-
|
|
113
|
+
`workflow.nextRecommendedPhase` has `phase`, `status`, and `rationale`. The status vocabulary is `ready`, `pending`, `blocked`, and `terminal`.
|
|
360
114
|
|
|
361
|
-
|
|
362
|
-
1. **Clarification Items** — single unified `C-*` table; column schema (4 columns with the short fields stacked in one record-meta cell), ID convention, and rerun behaviour are owned by `_common-contract.md §Clarification request policy` (SSOT). The deprecated `5.5.9 Open Questions` / `1.1 Additional Material Request` / `1.2 User Confirmation Questions` sub-sections are removed; the validator fails reports that reintroduce them.
|
|
363
|
-
- **Open `Blocks=approval` rows carry `origin` and `userConfirmation`** (same SSOT). Lead's dispatch prompt MUST state, per intended blocker, which `origin` applies and what Lead did about it — the writer cannot observe either. When Lead instructed the writer to raise an item rather than decide it, that row's `origin` is `lead-directed` no matter how the workers subsequently voted on it: an instruction returning as a consensus is not a finding. Before writing such an instruction, run the confirmation sequence in [okstra-lead-contract](./okstra-lead-contract.md) "User confirmation before an approval blocker" — asking first is usually cheaper than the row.
|
|
364
|
-
2. **Evidence and Detailed Analysis** — primary evidence rows (file path, line, snippet); secondary evidence / alternate interpretations. If `reference-expectations.md` lists explicit expected values, record match/gap per row.
|
|
365
|
-
- **Final-verification added-surface audit.** When `header.taskType` is `final-verification`, populate `finalVerification.addedSurfaceAudit` from the workers' enumeration of what the diff added — one row per identifier / module / configuration entry, each with the callers found across the repository and its disposition. Do not summarise the rows away: this table is the only machine-readable evidence for the over-delivery axis, and requirement coverage answers the opposite question. An `over-delivery` row's `note` MUST cite the `AB-NNN` (no caller) or `CA-NNN` (called, but no requirement) row it became, and that row MUST exist in this report. **Enforced:** `schemas/final-report-v2.0.schema.json` requires the array and rejects an unknown `disposition`; `validators/validate-run.py::_validate_added_surface_audit` enforces the citation and refuses a `traced` row that names no requirement.
|
|
366
|
-
- **Error-analysis diagnosis and routing.** When `header.taskType` is `error-analysis`, populate the required `errorAnalysis` object. Copy `errorAnalysis.symptomVerbatim` byte-for-byte from the symptom stated in the brief's `Source Material`; do not paraphrase it. Every `causeCandidates[]` row includes the full `supportingEvidence`, `falsifyingEvidenceChecked`, `confidence`, and `disproveWith` fields. When a candidate is a step in a propagation chain rather than a competing explanation — the analysis calls it a downstream step, a second stage, or a consequence of another candidate — set its `downstreamOf` to the ids of the candidates immediately upstream of it; leave the field absent for a candidate that stands on its own. Every id listed MUST be another candidate in the same report, no row may name itself, and the links MUST NOT form a cycle; `validators/validate-run.py::_validate_cause_chain` rejects all three. This is the only place the chain is machine-readable — prose calling a candidate "the second step of the chain" while `downstreamOf` is absent leaves the report's figure claiming the candidates are alternatives. Route `errorAnalysis.routing.nextTaskType=implementation-option-selection` with `direction=begin-option-selection`, or route `errorAnalysis.routing.nextTaskType=error-analysis` with `direction=continue-investigation`; no other pairing is valid. `verdictCard.nextStep`, `finalVerdict.nextStep`, the first `recommendedNextSteps` action and command, and the unique `followUpTasks` row whose `origin` is `phase-continuation` MUST all point to the same `errorAnalysis.routing.nextTaskType` target. The schema enforces only the presence of a `phase-continuation` row; `validators/validate-run.py::_validate_error_analysis_consistency` enforces exact target agreement and uniqueness.
|
|
367
|
-
- **Implementation-option-selection comparison.** When `header.taskType` is `implementation-option-selection`, populate `implementationOptionSelection` from the converged direction-selection findings. Preserve every merged or rejected raw candidate in `candidateAudit`, and put at most three selectable candidates in `rankedOptions`. Each displayed candidate carries its requirement coverage, scope commitments, criterion scores, feasibility votes, safety blockers, unresolved feasibility facts, planning invariants, and exact coverage summary. In each displayed candidate, `expectedChangeAreas` names direction-level change surfaces, never exact file paths or an exact file list. `expectedVerification` names direction-level verification signals, never a stage list or executable test commands. `schemas/final-report-v2.0.schema.json` enforces the displayed-summary constants and the three-option cap; semantic recalculation belongs to `validators/validate-run.py`.
|
|
368
|
-
- **Routing.** `implementationOptionSelection.routing` is a required **string enum** — not an object — with exactly three values: `implementation-planning`, `pending-direction-selection`, `blocked`. It is the only field in this report that records where the task goes next, and Phase 7 projects `workflow.nextRecommendedPhase` from it (`scripts/okstra_ctl/next_phase.py`): `implementation-planning` becomes a `ready` pointer naming that phase, while `pending-direction-selection` and `blocked` become `pending` and `blocked` pointers carrying no phase. Only the first proposes a next run.
|
|
369
|
-
- **The value is determined by this run's mode and candidate set, not chosen freely.** `preselected-validation` mode routes to `implementation-planning` — the direction was already selected and this run only validated it. `candidate-comparison` mode that displays any candidate routes to `pending-direction-selection` — the user still owes the direction pick, so a comparison never routes straight to planning. `blocked` is legal only when no valid candidate exists at all, and is required in that case. **Enforced:** `scripts/okstra_ctl/implementation_options.py::validate_implementation_option_selection` rejects all three mismatches (`validated preselected direction must route to implementation-planning`, `candidate-comparison with options must await direction selection`, `routing must be blocked only when no valid options exist` / `routing may be blocked only when no valid options exist`).
|
|
370
|
-
- **Implementation-planning direction branch.** When `implementationPlanning.planningContract == "selected-direction"`, read `selectedDirectionRef` and the snapshot before authoring. Materialize the snapshot into `directionRealization`, stages, validation, rollback, and bidirectional original-requirement links. Author exactly one `P-Dir-1`; its payload is the complete `directionRealization`. Its verification covers the core mechanism, architecture boundaries, planning invariants, and any hidden direction change against `selectedDirectionRef`. Do not author Option Candidates, candidate scores, a Recommended Option, or user candidate-selection fields. When current evidence requires changing the direction, author `outcome: "direction-invalidated"` and omit the execution plan. Legacy candidate-comparison reruns retain `P-Opt-*`, Option Candidates, trade-off, and Recommended Option semantics.
|
|
115
|
+
`phase` is non-empty only for an authored `ready` pointer. `prepare` may lower `ready` to `pending` while retaining `phase` in `scripts/okstra_ctl/render.py::_derive_next_recommended_phase`; readers must use `status` for launchability. When `finalVerification.routingRecommendation.target` is `release-handoff(stage-group)`, write `phase` as `release-handoff`.
|
|
371
116
|
|
|
372
|
-
|
|
373
|
-
{
|
|
374
|
-
"candidateDetailBoundary": {
|
|
375
|
-
"expectedChangeAreas": "direction-level-only",
|
|
376
|
-
"expectedVerification": "direction-level-signals-only",
|
|
377
|
-
"forbidden": ["exact-file-lists", "stage-lists", "test-commands"]
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
```
|
|
117
|
+
## Compatibility
|
|
381
118
|
|
|
382
|
-
|
|
383
|
-
- **Implementation and final-verification routing.** Both phases record where the task goes next in a `routingRecommendation` **object** with exactly two fields: `target` is one enum value, `rationale` is the sentence that justifies it. Neither field takes free-form routing prose, and a target named only in the prose does not count — Phase 7 projects `workflow.nextRecommendedPhase` from `target` alone (`scripts/okstra_ctl/next_phase.py`), so the value you write there is the route the task actually takes.
|
|
384
|
-
- `implementation.routingRecommendation.target` is one of `final-verification`, `error-analysis`, `implementation-planning`, `implementation`. Pick `final-verification` when this stage's plan items landed and validation passed; `error-analysis` when a failure's cause is not understood; `implementation-planning` when the approved plan itself no longer fits the evidence; `implementation` when work remains inside this stage (the next run is a fix run).
|
|
385
|
-
- `finalVerification.routingRecommendation.target` is one of `release-handoff`, `release-handoff(stage-group)`, `error-analysis`, `implementation-option-selection`, `implementation-planning`, `implementation`, `done`. Both `release-handoff` values require the `accepted` verdict, and plain `release-handoff` additionally requires `verificationScope` `whole-task` — a `single-stage` accepted run routes to `release-handoff(stage-group)` instead. `done` ends the lifecycle here. `error-analysis` / `implementation-option-selection` / `implementation-planning` follow the cause-vs-direction-vs-plan split of the verdict token table above.
|
|
386
|
-
- `rationale` is one or two sentences on why that target and nothing else, citing the blocker ids or evidence rows behind the choice. It is the only free-form half of the field; the digest sections still point here for the full reasoning.
|
|
387
|
-
- `releaseHandoff.routingRecommendation` is unchanged — it stays a single prose field, because `release-handoff` is terminal and nothing projects a next phase from it.
|
|
388
|
-
- **Enforced:** `schemas/final-report-v2.0.schema.json` rejects a `target` outside the enum, a missing `rationale`, and any string value in either field; `validators/validate-run.py::_validate_final_verification_consistency` rejects a final-verification report whose `routingRecommendation.target` is absent, and rejects the verdict↔routing and scope↔routing combinations named above.
|
|
389
|
-
3. **Recommended Next Steps** — prioritized actions. After Phase 7's follow-up spawner runs, append a row per newly created task-key (see "Phase 6 → Phase 7 execution sequence" above). **Approval-gate consistency:** when §1 carries any `Blocks: approval` row with `Status` ∈ {open, answered}, the Verdict Card `Next Step` and the first recommended step MUST point to the clarification rerun (`resume-clarification` of the SAME task-type) — never to "flip frontmatter `approved: true` → jump straight to `implementation`". Run-prep enforces this gate (`run.py _validate_approved_plan` fail-closes on those rows and on a blocking data.json `gateResult`), so a direct-implementation next-step is an instruction the reader cannot actually follow. **Cross-project pointer rule:** for cross-project dependencies (another repo / a different top-level deployment module / a published package), `crossProjectDependencies` (§5.4 Cross-Project Dependencies) is authoritative — do NOT duplicate that substance (prerequisite work / verification signals / handoff) into `recommendedNextSteps`; put only a one-line pointer to that section (no double-recording).
|
|
390
|
-
4. **Follow-up Tasks** — auto-spawn-eligible table. Each row drives `okstra-spawn-followups.py`; see template §4 for the row schema.
|
|
391
|
-
5. **Missing Information and Risks** — uncertain / "I don't know" items. `implementation-planning` adds §5.5 (see heading contract below); `release-handoff` adds §5.6.
|
|
392
|
-
6. **Cross Verification Results** — 4 categories (Full / Partial / Contested / Worker-Unique) when convergence is enabled, per `convergence`. Prepend the Round History sub-table (columns: `Round | inputQueueSize | resolvedCount | carriedForwardCount | dispatches | skippedWorkers`) plus a `round2SkippedReason: <value>` note, pulled verbatim from `convergence-<task-type>-<seq>.json`. Empty contested list renders as `- No items lacking consensus.`. Convergence-disabled runs use the legacy Consensus/Differences format and omit the round table.
|
|
393
|
-
7. **Final Verdict** — `Direction` ∈ `continue-investigation` / `begin-option-selection` / `begin-planning` / `begin-implementation` / `approve` / `reject` / `hold`. **Verdict Token** is `not-applicable` for every task-type except `final-verification` — see "Final-verification verdict token contract" below for that case.
|
|
394
|
-
|
|
395
|
-
**§5.10 Fix History (data-presence gated).** When the run-manifest carries a `fixCycleId`, fill the data.json `fixCycle` block (`cycle` / `targetReport` / `symptom` / `runs`). Read the values from the task root's `history/fix-cycles.jsonl`: `cycle` MUST equal `fixCycleId`, `targetReport` / `symptom` come from that cycle's `opened` row, and `runs` lists its attached `run` rows (`taskType` / `runSeq` / `runManifest`). The validator (`validators/validate-run.py` → `_validate_fix_cycle`) fails the run when the block is missing or `fixCycle.cycle` does not match `fixCycleId`. When the run-manifest has no `fixCycleId`, OMIT the `fixCycle` block entirely — the renderer omits §5.10.
|
|
396
|
-
|
|
397
|
-
### Writing Guidelines
|
|
398
|
-
|
|
399
|
-
- Write in Markdown. **Prefer tables over prose bullet lists** for any section that enumerates multiple items with the same shape (evidence rows, risks, options, dependencies, rollback steps, follow-ups, open questions). Bullets are reserved for short, single-line standalone statements (e.g., "- No additional information requested."). When the template provides a table form, do NOT degrade it back to bullets in the rendered report. **Exception — `## Background and Rationale` (`rationale`) is deliberately prose**: it is connected narrative explaining the *why*, not a same-shape enumeration, so write full sentences there rather than forcing it into a table.
|
|
400
|
-
- **Do not restate the same conclusion verbatim across sections.** The Verdict Card and Reader Summary are *digests*: give the outcome in one or two sentences and point to `## 7. Final Verdict` / `## 5.8.8 Routing Recommendation` for the full reasoning, rather than copying their multi-clause conclusion word-for-word. Only the `Verdict Token` and `Direction` cells must byte-match §7 (per the Verdict Card contract above). `Next Step` must point to the same routing target as §7, but its actionable command and prose need not be byte-identical. The prose conclusion must not be a duplicate.
|
|
401
|
-
- **Keep each sentence to one main idea.** A single sentence that stacks four or five clauses with em-dashes and nested parentheticals (300+ characters) is hard to read, and the renderer can only line-break at sentence ends — so break such reasoning into separate sentences. Facts, evidence, and IDs still live in the tables; prose carries only the connective *why*.
|
|
402
|
-
- **Write the report body in English, whatever the Report Language is.**
|
|
403
|
-
The data.json is the SSOT every later phase, validator and agent reads,
|
|
404
|
-
and its full reading copy has the same audience, so both stay
|
|
405
|
-
in one language. Only the human HTML follows the reader: when
|
|
406
|
-
**Report Language** is not `en`, Phase 7 dispatches the translator
|
|
407
|
-
worker, which writes a sidecar the HTML renderer overlays. You never
|
|
408
|
-
author that sidecar and never write a second language into the data.json.
|
|
409
|
-
The HTML's own fixed strings — headings, column headers, empty states,
|
|
410
|
-
enum labels — come from `templates/reports/html/i18n/<lang>.json` and
|
|
411
|
-
are not yours to write either.
|
|
412
|
-
- If only one worker is usable, perform a reduced-confidence synthesis
|
|
413
|
-
- If evidence is insufficient, explicitly state "I don't know"
|
|
414
|
-
- If expected values are present in `reference-expectations.md`, list matches, gaps, and missing evidence separately
|
|
415
|
-
- If `reference-expectations.md` is explicitly empty, report the absence of expected states as missing information
|
|
416
|
-
- If there are no substantive differences between workers, state "No difference"
|
|
417
|
-
- Write the actual analysis text instead of a meta-description
|
|
418
|
-
- Do not make unfounded assertions
|
|
419
|
-
- Include findings from all four categories. Do not omit "contested" or "worker-unique" findings
|
|
420
|
-
- Include the convergence round history sub-table (Section 6) so the reader can audit which rounds executed and what `round2SkippedReason` indicates (e.g. `"not-skipped"` when Round 2 ran, or one of the three skip reasons). Pull values verbatim from `convergence-<task-type>-<seq>.json`; do NOT recompute.
|
|
421
|
-
- For each finding, include a brief summary of votes per worker across executed rounds. `verification-error` votes are listed as such — never as `DISAGREE`.
|
|
422
|
-
- The report writer worker does not participate in the re-verification vote. It is responsible only for drafting the final report
|
|
423
|
-
|
|
424
|
-
## Artifact Persistence Checklist
|
|
425
|
-
|
|
426
|
-
Persistence steps that must be performed in Phase 7:
|
|
427
|
-
|
|
428
|
-
- [ ] 1. **Draft report record**: Save to `runs/<task-type>/reports/final-report-<task-type>-<seq>.data.json`
|
|
429
|
-
- [ ] 2. **Update team state**: Update `runs/<task-type>/state/team-state-<task-type>-<seq>.json`
|
|
430
|
-
- Final status, start/end times, and result file paths for each worker
|
|
431
|
-
- Overall run status
|
|
432
|
-
- [ ] 3. **Update run manifest**: Update `runs/<task-type>/manifests/run-manifest-<task-type>-<seq>.json`
|
|
433
|
-
- [ ] 4. **Update task-manifest.json**: Reflect task-level status and workflow lifecycle metadata
|
|
434
|
-
- Update `workCategory` if the run produced a confident classification
|
|
435
|
-
- Update `workflow.currentPhase`, `workflow.currentPhaseState`, `workflow.lastCompletedPhase`, and `workflow.phaseStates`
|
|
436
|
-
- Write `workflow.nextRecommendedPhase` as an object with exactly three string fields — `phase`, `status`, `rationale`. **This checklist item is the canonical statement of that field**; the lead contract, the context loader and every okstra skill point here instead of restating it, so a change to the rule belongs in this bullet.
|
|
437
|
-
- `status` is one of `ready` (the named phase can be started now), `pending` (this run did not settle where the task goes next), `blocked` (something outside this run must change before any phase can start), or `terminal` (the lifecycle ends here; there is no next phase).
|
|
438
|
-
- `phase` carries a lifecycle phase name only when `status` is `ready`; under the other three, write the empty string. This is an authoring rule for the value **you** write, not a constraint the struct enforces or a shape you can rely on when reading. `prepare` lowers a `ready` pointer to `pending` and keeps its `phase` (`scripts/okstra_ctl/render.py::_derive_next_recommended_phase`), so every in-flight task's manifest holds a non-`ready` pointer that still names a phase. Never infer launchability from a non-empty `phase` — read `status`, which is the one field that answers it.
|
|
439
|
-
- `rationale` is one sentence saying why. It is the only free-form field, and it is the only part of the pointer that survives a correction.
|
|
440
|
-
- **`phase` and `status` MUST agree with this report's own routing field.** Which field that is depends on the task-type: `requirementsDiscovery.routing.nextTaskType`, `errorAnalysis.routing.nextTaskType`, `implementationOptionSelection.routing`, `implementationPlanning.outcome`, `implementation.routingRecommendation.target`, or `finalVerification.routingRecommendation.target` (see "Implementation and final-verification routing" above for those two enums). Two task-type groups have no routing field that Phase 7 projects from: `release-handoff` (its `routingRecommendation` is prose that nothing reads) is always `terminal`, and the analysis sidetracks — `improvement-discovery`, `project-analysis`, `feature-analysis`, `change-impact-analysis` — are always `pending`, whatever a per-candidate recommendation inside the report says. One routing value is not a phase name: when `finalVerification.routingRecommendation.target` is `release-handoff(stage-group)`, write `phase` as `release-handoff`. The parenthesised part names the handoff's scope, not a different phase, and Phase 7 projects it that way — writing the parenthesised form here records a correction against a report that was right.
|
|
441
|
-
- **Enforced:** Phase 7 validation recomputes `phase` and `status` from that routing field (`scripts/okstra_ctl/next_phase.py::project`). On a passing run whose authored pair disagrees with the recomputed pair, `validators/validate-run.py` overwrites both with the recomputed values, replaces your `rationale` with a pointer sentence, and preserves what you wrote under `workflow.nextRecommendedPhaseCorrection.authored`. A run whose validation fails ends with the pointer `blocked`, keeping your `rationale`. So the routing field is what actually moves the task — a pointer authored against the report body changes nothing but the audit trail.
|
|
442
|
-
- Update `workflow.awaitingApproval`
|
|
443
|
-
- Update `workflow.lastSafeCheckpoint` to the best resume point for the current task
|
|
444
|
-
- [ ] 5. **Update task-index.md**: Refresh human-readable summary
|
|
445
|
-
- [ ] 6. **Generate final status file**: `runs/<task-type>/status/final-<task-type>-<seq>.status` (if necessary)
|
|
446
|
-
- [ ] 7. **Save convergence state**: `runs/<task-type>/state/convergence-<task-type>-<seq>.json` (when convergence is enabled)
|
|
447
|
-
- [ ] 8. **Spawn follow-up task stubs**: run `okstra spawn-followups` against the final-report per the canonical spawn rule defined in "Phase 7 follow-up task spawner" above. Do not restate the trigger condition here — that section is the single source of truth. The script is idempotent across reruns.
|
|
448
|
-
- [ ] 9. **Human HTML report** (conditional): `runs/<task-type>/reports/final-report-<task-type>-<seq>.html` — produced by the Phase 7 `render-views` step per its generation predicate (≥1 §1 `C-*` clarification row OR an implementation-planning Plan Approval widget target; that step is the single source for the exact condition). Reports matching neither condition legitimately have no html sibling; do not treat its absence as a missing artifact.
|
|
449
|
-
|
|
450
|
-
### Response after Persistence
|
|
451
|
-
|
|
452
|
-
Provide a concise report in the Report Language covering the following:
|
|
453
|
-
- Completion status
|
|
454
|
-
- Human report path (`.html`)
|
|
455
|
-
- Report record path (`.data.json`) and one line to render the full reading copy: `okstra render-final-report <task-qualified data.json>`
|
|
456
|
-
- Team-state path
|
|
457
|
-
- Validator results
|
|
458
|
-
- Resume command path
|
|
459
|
-
- Remaining blockers (if any)
|
|
119
|
+
Contract 2.0 reports remain readable. They are never migrated or rewritten by report assembly. New writes use contract 3.0 only.
|