okstra 0.206.0 → 0.207.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/cli-registry.mjs +7 -1
- package/dist/cli-registry.mjs.map +1 -1
- package/dist/commands/lifecycle/install.mjs +1 -1
- package/dist/commands/lifecycle/install.mjs.map +1 -1
- package/docs/architecture/storage-model.md +1 -0
- package/docs/architecture.md +40 -16
- package/docs/cli.md +17 -15
- package/docs/contributor-change-matrix.md +3 -2
- package/docs/performance-improvement-plan-v2.md +1 -1
- package/docs/project-structure-overview.md +43 -20
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/operations/code-review.json +1 -1
- package/runtime/bin/lib/okstra/usage.sh +3 -3
- package/runtime/bin/okstra-compact-reminder.sh +1 -1
- package/runtime/bin/okstra-spawn-followups.py +2 -2
- package/runtime/prompts/duties/direction-selection-worker.json +1 -1
- package/runtime/prompts/launch.template.md +2 -2
- package/runtime/prompts/lead/adapters/cmux.md +4 -3
- package/runtime/prompts/lead/context-loader.md +1 -1
- package/runtime/prompts/lead/convergence.md +44 -12
- package/runtime/prompts/lead/okstra-lead-contract.md +44 -73
- package/runtime/prompts/lead/phase-routing.md +64 -0
- package/runtime/prompts/lead/report-writer.md +10 -8
- package/runtime/prompts/lead/team-contract.md +1 -1
- package/runtime/prompts/profiles/_clarification-recommendation.md +4 -4
- package/runtime/prompts/profiles/_coding-conventions-preflight.md +1 -1
- package/runtime/prompts/profiles/_common-contract.md +2 -2
- package/runtime/prompts/profiles/_coverage-critic.md +1 -1
- package/runtime/prompts/profiles/forbidden-actions.json +0 -94
- package/runtime/prompts/wizard/prompts.ko.json +2 -1
- package/runtime/python/okstra_ctl/adapters/hosts/antigravity/relay.md +1 -1
- package/runtime/python/okstra_ctl/adapters/hosts/claude-code/relay.md +5 -5
- package/runtime/python/okstra_ctl/adapters/hosts/codex/relay.md +1 -1
- package/runtime/python/okstra_ctl/adapters/hosts/external/relay.md +3 -2
- package/runtime/python/okstra_ctl/adapters/hosts/grok/relay.md +1 -1
- package/runtime/python/okstra_ctl/adapters/hosts/kimi/relay.md +1 -1
- package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +17 -26
- package/runtime/python/okstra_ctl/agent/prompt_cli/batch.py +183 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/cli.py +60 -10
- package/runtime/python/okstra_ctl/agent/prompt_cli/corrections.py +1 -1
- package/runtime/python/okstra_ctl/agent/prompt_cli/jobs.py +21 -4
- package/runtime/python/okstra_ctl/agent/prompt_cli/materialize.py +10 -1
- package/runtime/python/okstra_ctl/analysis_inputs.py +0 -39
- package/runtime/python/okstra_ctl/analysis_scope.py +31 -0
- package/runtime/python/okstra_ctl/approval_decisions.py +32 -2
- package/runtime/python/okstra_ctl/asset_roots.py +19 -0
- package/runtime/python/okstra_ctl/assignment_resolver.py +8 -0
- package/runtime/python/okstra_ctl/blocking_checks.py +7 -0
- package/runtime/python/okstra_ctl/code_review_target.py +92 -6
- package/runtime/python/okstra_ctl/consumers.py +12 -0
- package/runtime/python/okstra_ctl/dispatch_checkpoints.py +121 -0
- package/runtime/python/okstra_ctl/dispatch_core.py +54 -32
- package/runtime/python/okstra_ctl/dispatch_state.py +34 -5
- package/runtime/python/okstra_ctl/doctor.py +2 -1
- package/runtime/python/okstra_ctl/domain/provider.py +5 -0
- package/runtime/python/okstra_ctl/domain/worker_presentation.py +21 -2
- package/runtime/python/okstra_ctl/domain/write_policy.py +2 -1
- package/runtime/python/okstra_ctl/execution_mutation_audit.py +46 -9
- package/runtime/python/okstra_ctl/handoff.py +11 -466
- package/runtime/python/okstra_ctl/handoff_error.py +5 -0
- package/runtime/python/okstra_ctl/implementation_direction.py +0 -477
- package/runtime/python/okstra_ctl/initial_prompt_materialization.py +13 -1
- package/runtime/python/okstra_ctl/lead_progress.py +33 -1
- package/runtime/python/okstra_ctl/manager_view.py +26 -19
- package/runtime/python/okstra_ctl/model_io/lines.py +21 -4
- package/runtime/python/okstra_ctl/models.py +4 -1
- package/runtime/python/okstra_ctl/operation_invocation.py +11 -2
- package/runtime/python/okstra_ctl/option_comparison.py +3 -165
- package/runtime/python/okstra_ctl/option_votes.py +3 -191
- package/runtime/python/okstra_ctl/paths.py +8 -6
- package/runtime/python/okstra_ctl/phases/catalog.py +56 -12
- package/runtime/python/okstra_ctl/phases/change_impact_analysis/boundary.json +11 -0
- package/runtime/python/okstra_ctl/phases/change_impact_analysis/entry.py +39 -0
- package/runtime/python/okstra_ctl/{report_html/view_models/change_impact_analysis.py → phases/change_impact_analysis/report.py} +3 -3
- package/runtime/python/okstra_ctl/phases/change_impact_analysis/spec.md +26 -0
- package/runtime/python/okstra_ctl/phases/change_impact_analysis/validation.py +23 -0
- package/runtime/python/okstra_ctl/phases/error_analysis/__init__.py +1 -0
- package/runtime/python/okstra_ctl/phases/error_analysis/boundary.json +9 -0
- package/runtime/{prompts/profiles/error-analysis.md → python/okstra_ctl/phases/error_analysis/profile.md} +2 -2
- package/runtime/python/okstra_ctl/{report_html/view_models/error_analysis.py → phases/error_analysis/report.py} +9 -8
- package/runtime/{templates/reports → python/okstra_ctl/phases/error_analysis/report_assets}/error-analysis-input.template.md +1 -1
- package/runtime/python/okstra_ctl/phases/error_analysis/spec.md +118 -0
- package/runtime/python/okstra_ctl/phases/error_analysis/validation.py +241 -0
- package/runtime/python/okstra_ctl/phases/feature_analysis/__init__.py +1 -0
- package/runtime/python/okstra_ctl/phases/feature_analysis/boundary.json +8 -0
- package/runtime/python/okstra_ctl/phases/feature_analysis/entry.py +63 -0
- package/runtime/python/okstra_ctl/{report_html/view_models/feature_analysis.py → phases/feature_analysis/report.py} +12 -5
- package/runtime/python/okstra_ctl/phases/feature_analysis/spec.md +22 -0
- package/runtime/python/okstra_ctl/phases/feature_analysis/validation.py +27 -0
- package/runtime/python/okstra_ctl/phases/feature_analysis/wizard.py +95 -0
- package/runtime/python/okstra_ctl/phases/final_verification/boundary.json +8 -0
- package/runtime/python/okstra_ctl/phases/final_verification/profile.md +2 -2
- package/runtime/{templates/reports → python/okstra_ctl/phases/final_verification/report_assets}/final-verification-input.template.md +1 -1
- package/runtime/python/okstra_ctl/phases/final_verification/spec.md +1 -1
- package/runtime/python/okstra_ctl/phases/implementation/__init__.py +1 -0
- package/runtime/python/okstra_ctl/phases/implementation/boundary.json +17 -0
- package/runtime/python/okstra_ctl/{implementation_stage.py → phases/implementation/entry.py} +22 -10
- package/runtime/{prompts/host-orchestration/implementation.md → python/okstra_ctl/phases/implementation/host-rules.md} +1 -1
- package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-deliverable.md +1 -1
- package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-executor.md +4 -3
- package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-verifier.md +18 -7
- package/runtime/{prompts/profiles/implementation.md → python/okstra_ctl/phases/implementation/profile.md} +5 -5
- package/runtime/python/okstra_ctl/{report_html/view_models/implementation.py → phases/implementation/report.py} +3 -3
- package/runtime/{templates/reports → python/okstra_ctl/phases/implementation/report_assets}/implementation-input.template.md +1 -1
- package/runtime/python/okstra_ctl/phases/implementation/spec.md +238 -0
- package/runtime/python/okstra_ctl/phases/implementation/validation.py +205 -0
- package/runtime/python/okstra_ctl/phases/implementation/wizard.py +39 -0
- package/runtime/python/okstra_ctl/phases/implementation_option_selection/__init__.py +1 -0
- package/runtime/python/okstra_ctl/phases/implementation_option_selection/authoring.py +80 -0
- package/runtime/python/okstra_ctl/phases/implementation_option_selection/boundary.json +10 -0
- package/runtime/python/okstra_ctl/phases/implementation_option_selection/comparison.py +168 -0
- package/runtime/python/okstra_ctl/phases/implementation_option_selection/entry.py +27 -0
- package/runtime/{prompts/profiles/implementation-option-selection.md → python/okstra_ctl/phases/implementation_option_selection/profile.md} +3 -3
- package/runtime/python/okstra_ctl/{report_html/view_models/implementation_option_selection.py → phases/implementation_option_selection/report.py} +2 -2
- package/runtime/python/okstra_ctl/phases/implementation_option_selection/spec.md +83 -0
- package/runtime/python/okstra_ctl/{implementation_options.py → phases/implementation_option_selection/validation.py} +3 -3
- package/runtime/python/okstra_ctl/phases/implementation_option_selection/votes.py +194 -0
- package/runtime/python/okstra_ctl/phases/implementation_planning/__init__.py +1 -0
- package/runtime/python/okstra_ctl/phases/implementation_planning/authoring.py +2345 -0
- package/runtime/python/okstra_ctl/phases/implementation_planning/boundary.json +12 -0
- package/runtime/python/okstra_ctl/phases/implementation_planning/entry.py +161 -0
- package/runtime/python/okstra_ctl/phases/implementation_planning/guidance.py +178 -0
- package/runtime/{prompts/lead → python/okstra_ctl/phases/implementation_planning/instructions}/plan-body-verification.md +61 -51
- package/runtime/python/okstra_ctl/phases/implementation_planning/plan_body.py +3295 -0
- package/runtime/{prompts/profiles/implementation-planning.md → python/okstra_ctl/phases/implementation_planning/profile.md} +74 -25
- package/runtime/python/okstra_ctl/phases/implementation_planning/report.py +237 -0
- package/runtime/{templates/reports → python/okstra_ctl/phases/implementation_planning/report_assets}/implementation-planning-input.template.md +2 -2
- package/runtime/python/okstra_ctl/phases/implementation_planning/spec.md +204 -0
- package/runtime/python/okstra_ctl/phases/implementation_planning/validation.py +597 -0
- package/runtime/python/okstra_ctl/phases/implementation_planning/wizard.py +166 -0
- package/runtime/python/okstra_ctl/phases/improvement_discovery/boundary.json +12 -0
- package/runtime/python/okstra_ctl/{improvement_lenses.py → phases/improvement_discovery/lenses.py} +1 -6
- package/runtime/{prompts/profiles/improvement-discovery.md → python/okstra_ctl/phases/improvement_discovery/profile.md} +5 -5
- package/runtime/python/okstra_ctl/{report_html/view_models/improvement_discovery.py → phases/improvement_discovery/report.py} +3 -3
- package/runtime/{templates/reports → python/okstra_ctl/phases/improvement_discovery/report_assets}/improvement-discovery-input.template.md +1 -2
- package/runtime/python/okstra_ctl/phases/improvement_discovery/spec.md +29 -0
- package/runtime/{validators/validate_improvement_report.py → python/okstra_ctl/phases/improvement_discovery/validation.py} +5 -14
- package/runtime/python/okstra_ctl/phases/project_analysis/__init__.py +1 -0
- package/runtime/python/okstra_ctl/phases/project_analysis/boundary.json +8 -0
- package/runtime/python/okstra_ctl/phases/project_analysis/entry.py +11 -0
- package/runtime/python/okstra_ctl/{report_html/view_models/project_analysis.py → phases/project_analysis/report.py} +3 -3
- package/runtime/python/okstra_ctl/phases/project_analysis/spec.md +33 -0
- package/runtime/python/okstra_ctl/phases/project_analysis/validation.py +55 -0
- package/runtime/python/okstra_ctl/phases/release_handoff/__init__.py +1 -0
- package/runtime/python/okstra_ctl/phases/release_handoff/boundary.json +17 -0
- package/runtime/python/okstra_ctl/phases/release_handoff/entry.py +147 -0
- package/runtime/python/okstra_ctl/phases/release_handoff/operations.py +446 -0
- package/runtime/{prompts/profiles/release-handoff.md → python/okstra_ctl/phases/release_handoff/profile.md} +3 -3
- package/runtime/python/okstra_ctl/{report_html/view_models/release_handoff.py → phases/release_handoff/report.py} +3 -3
- package/runtime/{templates/reports → python/okstra_ctl/phases/release_handoff/report_assets}/release-handoff-input.template.md +1 -1
- package/runtime/python/okstra_ctl/phases/release_handoff/spec.md +233 -0
- package/runtime/python/okstra_ctl/phases/release_handoff/wizard.py +84 -0
- package/runtime/python/okstra_ctl/phases/requirements_discovery/__init__.py +1 -0
- package/runtime/python/okstra_ctl/phases/requirements_discovery/boundary.json +9 -0
- package/runtime/{prompts/profiles/requirements-discovery.md → python/okstra_ctl/phases/requirements_discovery/profile.md} +2 -3
- package/runtime/python/okstra_ctl/{report_html/view_models/requirements_discovery.py → phases/requirements_discovery/report.py} +3 -3
- package/runtime/python/okstra_ctl/phases/requirements_discovery/spec.md +132 -0
- package/runtime/{validators/validate_fanout.py → python/okstra_ctl/phases/requirements_discovery/validation.py} +11 -12
- package/runtime/python/okstra_ctl/phases/technical_verification/__init__.py +1 -0
- package/runtime/python/okstra_ctl/phases/technical_verification/boundary.json +9 -0
- package/runtime/python/okstra_ctl/phases/technical_verification/entry.py +100 -0
- package/runtime/{prompts/profiles/technical-verification.md → python/okstra_ctl/phases/technical_verification/profile.md} +2 -2
- package/runtime/python/okstra_ctl/{report_html/view_models/technical_verification.py → phases/technical_verification/report.py} +2 -2
- package/runtime/python/okstra_ctl/phases/technical_verification/spec.md +37 -0
- package/runtime/python/okstra_ctl/phases/technical_verification/validation.py +90 -0
- package/runtime/python/okstra_ctl/plan_approval.py +70 -0
- package/runtime/python/okstra_ctl/plan_items_cli.py +2 -2130
- package/runtime/python/okstra_ctl/process_group.py +118 -0
- package/runtime/python/okstra_ctl/profile_show.py +3 -3
- package/runtime/python/okstra_ctl/render.py +15 -4
- package/runtime/python/okstra_ctl/report_assembly.py +28 -92
- package/runtime/python/okstra_ctl/report_finalize.py +106 -2
- package/runtime/python/okstra_ctl/report_html/context_links.py +1 -1
- package/runtime/python/okstra_ctl/report_projections.py +1 -36
- package/runtime/python/okstra_ctl/report_routing.py +23 -0
- package/runtime/python/okstra_ctl/report_synthesis_packet.py +4 -73
- package/runtime/python/okstra_ctl/report_validation_identity.py +38 -0
- package/runtime/python/okstra_ctl/report_views.py +1 -1
- package/runtime/python/okstra_ctl/run.py +68 -350
- package/runtime/python/okstra_ctl/run_artifact_prune.py +200 -0
- package/runtime/python/okstra_ctl/stage_map.py +13 -0
- package/runtime/python/okstra_ctl/team.py +108 -9
- package/runtime/python/okstra_ctl/technical_verification_facts.py +52 -0
- package/runtime/python/okstra_ctl/wizard/__init__.py +31 -31
- package/runtime/python/okstra_ctl/wizard/api.py +18 -0
- package/runtime/python/okstra_ctl/wizard/outcome.py +3 -12
- package/runtime/python/okstra_ctl/wizard/registry.py +20 -12
- package/runtime/python/okstra_ctl/wizard/steps_analysis.py +0 -97
- package/runtime/python/okstra_ctl/wizard/steps_options.py +8 -0
- package/runtime/python/okstra_ctl/wizard/steps_plan.py +10 -263
- package/runtime/python/okstra_ctl/wizard/steps_roles.py +2 -1
- package/runtime/python/okstra_ctl/work_categories.py +1 -1
- package/runtime/python/okstra_ctl/worker_dispatch.py +44 -3
- package/runtime/python/okstra_ctl/worker_prompt_contract.py +36 -0
- package/runtime/python/okstra_ctl/worker_prompt_policy.py +19 -0
- package/runtime/python/okstra_ctl/worker_runner.py +21 -3
- package/runtime/python/okstra_ctl/workflow.py +26 -143
- package/runtime/python/okstra_ctl/write_policy.py +57 -7
- package/runtime/python/okstra_project/dirs.py +14 -0
- package/runtime/python/okstra_project/resolver.py +2 -1
- package/runtime/schemas/execution-manifest-v2.schema.json +2 -1
- package/runtime/skills/okstra-brief-gen/SKILL.md +3 -3
- package/runtime/skills/okstra-code-review/SKILL.md +70 -32
- package/runtime/skills/okstra-code-review/references/review-calibration.md +26 -6
- package/runtime/skills/okstra-run/SKILL.md +3 -3
- package/runtime/templates/manager/view.template.html +18 -1
- package/runtime/templates/reports/quick-input.template.md +1 -1
- package/runtime/templates/reports/task-brief.template.md +1 -1
- package/runtime/validators/validate-brief.py +2 -2
- package/runtime/validators/validate-run.py +299 -3940
- package/runtime/validators/validate_analysis_report.py +14 -126
- package/runtime/python/okstra_ctl/report_html/view_models/implementation_planning.py +0 -147
- package/runtime/python/okstra_ctl/technical_verification.py +0 -195
- /package/runtime/{prompts/profiles/change-impact-analysis.json → python/okstra_ctl/phases/change_impact_analysis/profile.json} +0 -0
- /package/runtime/{prompts/profiles/change-impact-analysis.md → python/okstra_ctl/phases/change_impact_analysis/profile.md} +0 -0
- /package/runtime/{templates/reports → python/okstra_ctl/phases/change_impact_analysis/report_assets}/change-impact-analysis-input.template.md +0 -0
- /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/change_impact_analysis/report_assets}/change-impact-analysis.template.html +0 -0
- /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/change_impact_analysis/report_assets}/change-impact-analysis.template.md +0 -0
- /package/runtime/{prompts/profiles/error-analysis.json → python/okstra_ctl/phases/error_analysis/profile.json} +0 -0
- /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/error_analysis/report_assets}/error-analysis.template.html +0 -0
- /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/error_analysis/report_assets}/error-analysis.template.md +0 -0
- /package/runtime/{prompts/profiles/feature-analysis.json → python/okstra_ctl/phases/feature_analysis/profile.json} +0 -0
- /package/runtime/{prompts/profiles/feature-analysis.md → python/okstra_ctl/phases/feature_analysis/profile.md} +0 -0
- /package/runtime/{templates/reports → python/okstra_ctl/phases/feature_analysis/report_assets}/feature-analysis-input.template.md +0 -0
- /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/feature_analysis/report_assets}/feature-analysis.template.html +0 -0
- /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/feature_analysis/report_assets}/feature-analysis.template.md +0 -0
- /package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-diff-review.md +0 -0
- /package/runtime/{prompts/profiles → python/okstra_ctl/phases/implementation/instructions}/_implementation-self-check.md +0 -0
- /package/runtime/{prompts/profiles/implementation.json → python/okstra_ctl/phases/implementation/profile.json} +0 -0
- /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/implementation/report_assets}/implementation.template.html +0 -0
- /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/implementation/report_assets}/implementation.template.md +0 -0
- /package/runtime/{prompts/profiles/implementation-option-selection.json → python/okstra_ctl/phases/implementation_option_selection/profile.json} +0 -0
- /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/implementation_option_selection/report_assets}/implementation-option-selection.template.html +0 -0
- /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/implementation_option_selection/report_assets}/implementation-option-selection.template.md +0 -0
- /package/runtime/{prompts/host-orchestration/implementation-planning.md → python/okstra_ctl/phases/implementation_planning/host-rules.md} +0 -0
- /package/runtime/{prompts/profiles/implementation-planning.json → python/okstra_ctl/phases/implementation_planning/profile.json} +0 -0
- /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/implementation_planning/report_assets}/implementation-planning.template.html +0 -0
- /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/implementation_planning/report_assets}/implementation-planning.template.md +0 -0
- /package/runtime/{prompts/profiles/improvement-discovery.json → python/okstra_ctl/phases/improvement_discovery/profile.json} +0 -0
- /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/improvement_discovery/report_assets}/improvement-discovery.template.html +0 -0
- /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/improvement_discovery/report_assets}/improvement-discovery.template.md +0 -0
- /package/runtime/{prompts/profiles/project-analysis.json → python/okstra_ctl/phases/project_analysis/profile.json} +0 -0
- /package/runtime/{prompts/profiles/project-analysis.md → python/okstra_ctl/phases/project_analysis/profile.md} +0 -0
- /package/runtime/{templates/reports → python/okstra_ctl/phases/project_analysis/report_assets}/project-analysis-input.template.md +0 -0
- /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/project_analysis/report_assets}/project-analysis.template.html +0 -0
- /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/project_analysis/report_assets}/project-analysis.template.md +0 -0
- /package/runtime/{prompts/profiles/release-handoff.json → python/okstra_ctl/phases/release_handoff/profile.json} +0 -0
- /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/release_handoff/report_assets}/release-handoff.template.html +0 -0
- /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/release_handoff/report_assets}/release-handoff.template.md +0 -0
- /package/runtime/python/okstra_ctl/{fanout.py → phases/requirements_discovery/fanout.py} +0 -0
- /package/runtime/{prompts/profiles/requirements-discovery.json → python/okstra_ctl/phases/requirements_discovery/profile.json} +0 -0
- /package/runtime/{templates/reports → python/okstra_ctl/phases/requirements_discovery/report_assets}/fan-out-unit.template.md +0 -0
- /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/requirements_discovery/report_assets}/requirements-discovery.template.html +0 -0
- /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/requirements_discovery/report_assets}/requirements-discovery.template.md +0 -0
- /package/runtime/{prompts/profiles/technical-verification.json → python/okstra_ctl/phases/technical_verification/profile.json} +0 -0
- /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/technical_verification/report_assets}/technical-verification.template.html +0 -0
- /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/technical_verification/report_assets}/technical-verification.template.md +0 -0
package/docs/cli.md
CHANGED
|
@@ -147,7 +147,7 @@ The only next phase is `implementation-option-selection`. Carry the verification
|
|
|
147
147
|
`improvement-discovery` is a sidetrack entry point outside `PHASE_SEQUENCE`. It uses multi-worker consensus to find improvement candidates within the codebase scope and lens allowlist.
|
|
148
148
|
|
|
149
149
|
- Input: a brief with the frontmatter marker `scope: codebase`.
|
|
150
|
-
- `priority-lenses`: one to four values. The lens allowlist is the `LENSES` constant in `scripts/okstra_ctl/
|
|
150
|
+
- `priority-lenses`: one to four values. The lens allowlist is the `LENSES` constant in `scripts/okstra_ctl/phases/improvement_discovery/lenses.py`.
|
|
151
151
|
- `scan-scope`: one or more paths.
|
|
152
152
|
- `out-of-scope`: optional.
|
|
153
153
|
- `candidate-cap`: 1–12; default 8.
|
|
@@ -157,7 +157,7 @@ The only next phase is `implementation-option-selection`. Carry the verification
|
|
|
157
157
|
- Workers: claude + codex + antigravity + report-writer are all required.
|
|
158
158
|
- Primary-pass assignment: selected analyser instances are enumerated in `requiredWorkerRoles` order, then the lead rotates the primary pass across the resolved priority lenses. Provider/model names do not affect the order, and every analyser still covers every resolved lens after its primary pass.
|
|
159
159
|
- Two bidirectional grilling points: an enhanced Step 4 in `okstra-brief-gen` with a budget of 8, and the lead's Phase 1.5 reflect-back with a budget of 12.
|
|
160
|
-
- Validator: `
|
|
160
|
+
- Validator: `scripts/okstra_ctl/phases/improvement_discovery/validation.py` enforces the 11-part contract for an `improvement-discovery` final report.
|
|
161
161
|
- Because an `improvement-discovery` run is not in `PHASE_SEQUENCE`, its report has no routing field to project from, so the run leaves `workflow.nextRecommendedPhase` `pending` with no phase. The `--task-key` short form therefore cannot fill `--task-type` after one.
|
|
162
162
|
|
|
163
163
|
#### Analysis sidetrack task types
|
|
@@ -500,7 +500,7 @@ The Codex worker (`--workers codex`, `--codex-model`) and Codex lead runtime are
|
|
|
500
500
|
|
|
501
501
|
> Every `--*-model` flag accepts only aliases registered in the provider mappings in `scripts/okstra_ctl/models.py`. An unregistered value is immediately rejected with `UnknownModelError`, preventing a contract violation where the manifest's `modelExecutionValue` differs from the actual execution value. Allowed values:
|
|
502
502
|
> - Claude (`--lead-model` / `--claude-model` / `--report-writer-model`): `fable`, `fable-5-1`, `claude-fable-5-1`, `fable-5`, `claude-fable-5`, `opus`, `opus-5`, `claude-opus-5`, `sonnet`, `sonnet-5`, `claude-sonnet-5`, `haiku`, `haiku-4-5`, `claude-haiku-4-5`
|
|
503
|
-
> - Codex (`--codex-model`): `gpt-6-astra`, `gpt-
|
|
503
|
+
> - Codex (`--codex-model`): `gpt-6-astra`, `gpt-6.1-sol`, `gpt-6-luna`. The bundled default is `gpt-6.1-sol`, which okstra runs at `high` reasoning effort (`-c model_reasoning_effort=high`, overriding `~/.codex/config.toml`) for both workers and a launched lead. GPT-6 Sol, GPT-5.6 Sol, Terra, and Luna, `gpt-5.4-mini`, and `codex-auto-review` remain in the catalog for historical records but are not selectable. When the CLI model cache matches the running CLI version, dispatch rejects identifiers absent from that catalog rather than renaming them. A missing or mismatched cache leaves availability enforcement to the provider CLI; model selection does not guarantee account access.
|
|
504
504
|
> - Antigravity (`--antigravity-model`): `gemini-3.1-pro` (default), `gemini-3.8-flash`, and their space-separated aliases. The antigravity worker uses the `agy` CLI to run Gemini-family models, so model IDs retain the `gemini-*` form.
|
|
505
505
|
> - Grok (`--worker-model grok=<model>`): `grok-4.7`
|
|
506
506
|
> - Kimi (`--worker-model kimi=<model>`): `kimi-k3`, `k3`, `k3-256k` and their registered display aliases
|
|
@@ -515,7 +515,7 @@ Each confirmed count becomes `RoleInstance` ordinals. `ModelPool` then assigns o
|
|
|
515
515
|
|
|
516
516
|
### `--role-model`
|
|
517
517
|
|
|
518
|
-
Pins one model reference onto a role slot, in ordinal order: `--role-model <role>=<modelRef>`. Repeat the flag to fill later ordinals. `modelRef` is `<provider>/<model>`, for example `claude/opus` or `codex/gpt-
|
|
518
|
+
Pins one model reference onto a role slot, in ordinal order: `--role-model <role>=<modelRef>`. Repeat the flag to fill later ordinals. `modelRef` is `<provider>/<model>`, for example `claude/opus` or `codex/gpt-6.1-sol`.
|
|
519
519
|
|
|
520
520
|
A known selectable model may be assigned to any canonical role. The same role must not receive the same model ref twice; duplicate refs in one role panel fail before any worktree or state file is created. Same provider with different models is allowed. Fewer models than the confirmed count are filled from the model-default chain. Extra models do not raise the count; set `--role-count <role>=<N>` first. Unknown roles and unknown model refs fail before side effects.
|
|
521
521
|
|
|
@@ -547,7 +547,7 @@ Selects the model used by the host-native Okstra lead. Claude Code resolves it t
|
|
|
547
547
|
### `--codex-model`
|
|
548
548
|
|
|
549
549
|
Selects the model used by the `Codex worker`.
|
|
550
|
-
When omitted, it uses the central default `OKSTRA_DEFAULT_CODEX_MODEL`, falling back to `gpt-
|
|
550
|
+
When omitted, it uses the central default `OKSTRA_DEFAULT_CODEX_MODEL`, falling back to `gpt-6.1-sol`.
|
|
551
551
|
|
|
552
552
|
### `--antigravity-model`
|
|
553
553
|
|
|
@@ -571,11 +571,11 @@ The central-default environment variables are:
|
|
|
571
571
|
Fallback defaults are:
|
|
572
572
|
|
|
573
573
|
- Claude Code lead: `opus`
|
|
574
|
-
- Codex lead: `gpt-6-sol`
|
|
574
|
+
- Codex lead: `gpt-6.1-sol`
|
|
575
575
|
- Antigravity lead: `gemini-3.1-pro`
|
|
576
576
|
- `Report writer worker`: `sonnet`
|
|
577
577
|
- `Claude worker`: `opus`
|
|
578
|
-
- `Codex worker`: `gpt-6-sol`
|
|
578
|
+
- `Codex worker`: `gpt-6.1-sol`
|
|
579
579
|
- `Antigravity worker`: `gemini-3.1-pro`
|
|
580
580
|
- Implementation executor: `claude`, so the default is `Claude executor`.
|
|
581
581
|
|
|
@@ -585,7 +585,7 @@ Selects the provider that performs the Executor role for `--task-type implementa
|
|
|
585
585
|
|
|
586
586
|
- Default: `OKSTRA_DEFAULT_EXECUTOR` → fallback `claude`.
|
|
587
587
|
- The Executor is the **only worker allowed to mutate project files** in this run. The other providers are dispatched as strict read-only verifiers in the same run.
|
|
588
|
-
- The Executor reuses the provider's worker model flag. With `--executor codex`, its model comes from `--codex-model`, default `gpt-6-sol`; with `--executor antigravity`, it comes from `--antigravity-model`, default `gemini-3.1-pro`. With `--executor grok`, its model comes from `--worker-model grok=`, default `grok-4.7`.
|
|
588
|
+
- The Executor reuses the provider's worker model flag. With `--executor codex`, its model comes from `--codex-model`, default `gpt-6.1-sol`; with `--executor antigravity`, it comes from `--antigravity-model`, default `gemini-3.1-pro`. With `--executor grok`, its model comes from `--worker-model grok=`, default `grok-4.7`.
|
|
589
589
|
- All three Claude, Codex, and Antigravity verifiers are always dispatched regardless of the Executor provider. Even the verifier using the same provider runs in a separate CLI session with isolated context, preserving the self-review safeguard.
|
|
590
590
|
- Codex and Antigravity mutate files through each CLI's auto-edit mode, for example `codex exec --sandbox danger-full-access`, without passing through Claude-side Edit/Write tools. Mutations occur in the task worktree described below. Every `okstra-<provider>-exec.sh` entrypoint receives the worktree path as its fourth positional argument and adds it to the worker's write scope, which each provider is told as repeated `--add-dir` (Codex names the project root with `-C` and skips the repeat). No provider CLI enforces a sandbox boundary: the write scope tells a worker where its work belongs, and the run checks afterwards that it stayed there.
|
|
591
591
|
- **Claude Executor cwd handling**: Claude's Bash tool has no per-call cwd argument and inherits the lead session cwd. To run cwd-sensitive toolchains such as `cargo`, `npm`, `pnpm`, `bun`, `pytest`, `make`, or `go` inside the worktree, prefix the invocation with `cd {{EXECUTOR_WORKTREE_PATH}} && <cmd>`. Keep `cd` as the leading token in a single Bash call so Claude Code permission auto-allow works; do not wrap it in `bash -lc "..."` or `bash -c "..."`, which hides `cd` and causes a permission prompt on every call. Prefer a tool's working-directory option—such as `git -C <path>`, `cargo --manifest-path`, or `pytest --rootdir`—over a `cd && ` chain. Edit/Write/Read tools already use absolute paths and need no cwd handling. This rule applies only to the Claude Executor; the Codex and Antigravity wrappers inject cwd.
|
|
@@ -863,6 +863,7 @@ The `okstra` Node CLI (`bin/okstra`) provides both installer/admin commands and
|
|
|
863
863
|
| `okstra worker-liveness [--team-state <path> --worker <id>]… [--max-idle <seconds>] [--launch-grace <seconds>] [--stall-confirm <seconds>] [--json]` | Judge whether pending workers are still alive so the lead's poll ends a stalled wait early instead of paying the full deadline. Prefer paired `--team-state <path> --dispatch-id <id>` options for identified attempts; do not mix them with `--worker`. Worker-name selection is retained only when the dispatch is unambiguous. Each retry starts a new wait for its own id. A selector error is a monitoring-input defect, not a failed worker. The worker row's `livenessMode` picks the probe: `audit-heartbeat` reads its `auditSidecarPath` and reports `stalled` when the `- PROGRESS:` heartbeat is past the idle budget; `wrapper-status` reads its `promptPath` and reports `did-not-launch` when neither the wrapper `.log` nor `.status.json` appears. Both graces start at the persisted `startedAt`, never at an artifact mtime — the audit sidecar is reused on re-dispatch, so a heartbeat older than this dispatch counts as no signal yet rather than a stall. A heartbeat budget breach is confirmed before it is reported: the probe re-reads the sidecar after `--stall-confirm` seconds (default: half that stage's budget; `0` disables) and reports `stalled` only when the newest heartbeat has not advanced, so a worker inside one long uninterruptible tool call is not judged dead for being slow. Healthy probes report `live`. It only judges—it never kills or re-dispatches. Exit 1 on an unhealthy verdict, so a poll loop can branch without parsing JSON. The heartbeat line shape and budget come from the `okstra_ctl.worker_heartbeat` SSOT shared with the Phase 7 audit (`validators/validate_session_conformance.py`) |
|
|
864
864
|
| `okstra verification-target --project-root <dir> --run-manifest <path> --expected-head <commit> --command <declared-command> [--baseline <json>]` | Read-only target observation for implementation and final verification. Reads the active run's worktree, checks the commit and rejects checkout-changing command syntax without executing the command. Save the JSON before the check; compare it with `--baseline` afterwards. Changed source fingerprints, commands, worktrees or commits invalidate reuse. A successful observation does not prove the declared command was executed. Exit 1 on a target or input error. |
|
|
865
865
|
| `okstra worker-audit-check --run-dir <runs/<task-type>/> --task-type <type> --seq <nnn> [--worker <id>]` | Apply the Phase 7 worker audit-sidecar rules mid-run, while the worker session is still alive. For each of this run's `worker-results/<worker>-<task-type>-<seq>.md` it checks that the file carries no `## 0. Reading Confirmation` heading, that the matching audit sidecar exists, and — for prompts carrying the required-v1 evidence-ledger marker — that every backticked `path:line` citation has an Evidence read row in that sidecar. `--worker` scopes it to the role that just returned. `--seq` accepts a bare number and zero-pads it to three digits, so `--seq 1` and `--seq 001` select the same run. Emits `{ok, inspected, inspectedFiles[], failures[], blocking[], advisory[], runImpact}` and exits 2 when `failures[]` (= `blocking` + `advisory`) is non-empty — and also when the selector matched no result file at all, in which case the payload carries `selectorError` and empty `failures[]`: nothing was judged, which is not a pass. Exit 2 means "fix it now", not "the run fails": only `blocking` rows (no audit sidecar) fail the run at Phase 7, while `advisory` rows (a citation with no matching Evidence read row) never fail the run and are only repairable while the worker session is alive — do not reject or re-dispatch a result over an advisory row alone. The rules come from the `okstra_ctl.worker_audit_ledger` SSOT shared with `validate-run.py`, so an early pass and the Phase 7 pass cannot disagree. Run it right after collecting a result: the same failure at Phase 7 leaves only a retroactive edit, which breaks the audit chain, or a failed run |
|
|
866
|
+
| `okstra prune-run-artifacts [--project-root <dir>] [--cwd <dir>] [--task-group <group> --task-id <id>] [--apply] [--text]` | List, under `.okstra/tasks` (or one task root) with sizes and a total, what no reader needs after a run: every `node_modules` and `.next` directory, and the dispatch snapshots (`*.mutation-audit.json`) and publication locks (`*.publish.lock`) that the team state records for a run whose `validation.status` is `passed`, or for an earlier run in the same run directory (lower manifest sequence) than a passed one. It removes them only with `--apply`. Symbolic links are neither followed nor removed; source copies, logs, lockfiles, diffs, prompts and results stay, so technical-verification experiment working directories remain valid. The `prune-run-artifacts` Phase 7 step does the same for its own run directory; this command cleans runs finalized before it |
|
|
866
867
|
| `okstra log-report [--project-root <dir>] [--cwd <dir>] [--top <N>] [--json]` | Read-only inventory of wrapper transcript `.log` files and their sibling prompt `.md` files. Each ranked entry preserves `path` / `sizeBytes` for compatibility and also reports `transcriptPath`, `transcriptBytes`, `promptPath`, `promptBytes`, and `transcriptToPromptRatio`; totals distinguish prompt bytes from transcript bytes and count paired files. Ranking remains transcript-size descending |
|
|
867
868
|
| `okstra recap <assemble\|record\|note> (<task-root\|task-key> \| --task-group <group>) …` | Backend for the okstra-inspect `recap` facet. `assemble` is read-only: for a task it prints a JSON summary of phase transitions across its runs; with `--task-group` it prints the group's start order (briefs in ordinal order, each `done` / `in progress` / `not started` from the catalog's task-manifests, memory entries only for tasks the catalog does not know) and every recorded task's latest conclusion from `group-context.md`'s Task Memory. `okstra model-io recap-input --task-group <group>` is the fixed-text projection of the same join. `record --kind <summary\|qa> --mode <artifact\|code> --answer <text> [--question <text>] [--citation <path:line> …]` appends one line to `<task-root>/recap/recap-log.jsonl`, or with `--task-group` to `.okstra/tasks/<group>/.recap/recap-log.jsonl`, and never mutates other artifacts. `note` is task-only. `note --kind <verification-evidence\|decision-draft\|analysis-note> --slug <topic> --purpose <text> --scope-note <text> (--body <markdown>\|--body-file <path>)` writes an agent-authored note to `<task-root>/notes/` and prints its path plus the `--clarification-response` argument for feeding it into a later run |
|
|
868
869
|
| `okstra user-response <list-view\|show-view\|begin\|answer\|plan-decision\|legacy-report-authoring\|finalize> …` | Backend for the `/okstra-user-response` skill. `list-view` and `show-view --report <md\|data.json> --project-root <dir>` are fixed-text model views; `show-view` validates that the report belongs to the explicit project root and prints each open row's why-asked line, linked plan items, and cited `path:line` artifacts so the skill can read them before asking. The legacy `list` and `show` JSON reads retain their automation-compatible fields. `begin --report <md\|data.json> --task-key <key>` returns an opaque transaction id. A predefined clarification choice uses `answer --transaction <id> --clarification-id <C-NNN> --kind <kind> --option-number <N>`; Python resolves the answer, disposition, reach, and scope effects from the validated report. Direct input instead uses `--disposition <answer\|reframe> --value-file <md> [--rationale-file <md>]`. Every value, rationale, and reason file must be a regular file under `<PROJECT_ROOT>/.okstra/tmp/user-response/`; external paths and symbolic links are rejected. `plan-decision` accepts `approved`, `revision-requested`, or `rejected`, validates any `--implementation-option` against the report candidates, and requires `--reason-file` for the latter two statuses. `legacy-report-authoring` is restricted to report contract 2.0. `finalize` validates the complete existing sidecar before a lossless merge, uses compare-and-swap under a run-local lock, and atomically publishes only the user-owned sidecar; exit 0 ok / 1 error. |
|
|
@@ -881,23 +882,24 @@ The `okstra` Node CLI (`bin/okstra`) provides both installer/admin commands and
|
|
|
881
882
|
| `okstra worktree-status [--path <dir>] [--check-clean]` | Answer "is this worktree clean?" over source paths only, excluding what okstra provisioned there — `.okstra`, the configured sync entries (`.project-docs`, `.claude`, …), and any nested stage worktree. A bare `git status --porcelain` in a task worktree is never empty for that reason, so a plan step asserting a clean tree with one fails on okstra's scaffolding instead of on the stage's own work; this is the same gate `handoff` and stage integration use. Output is JSON `{ ok, path, clean, entries, excluded }` where `entries` holds the `git status --short` rows that made it dirty. Exit code is 0 regardless unless `--check-clean` is given, which exits 1 on a dirty tree so it can stand as a shell assertion (`okstra worktree-status --check-clean`). okstra writes `stage-<N>-exit` itself when it settles the stage, so a plan step must not tag. A path outside a git work tree exits 2 rather than reporting a clean tree |
|
|
882
883
|
| `okstra plan-validate <plan-path>` | Run `_validate_approved_plan` and report frontmatter `approved` recognition plus unresolved Blocks=approval rows |
|
|
883
884
|
| `okstra render-bundle <args…> [--stage <auto\|N>] [--stages <csv>]` | Thin shim over `prepare_task_bundle(render_only=True)` with the same signature as `python3 -m okstra_ctl.run --render-only`. `--stage` is for `implementation` and `final-verification`: for implementation, `auto` (default) selects the earliest incomplete stage with satisfied dependencies, while `<N>` forces a stage; for final-verification, `<N>` verifies one stage with artifacts under `runs/final-verification/stage-<N>/` and a `-fv-s<N>` team suffix, while an empty value performs whole-task verification with the flat layout. The separate `--stages <csv>` channel is for `release-handoff`: it names the stages to open a PR for, one PR per stage, and an empty value takes every eligible stage. Preparation enforces eligibility—`done` + accepted `verified` + not yet `pr`—and automatically creates an input document that cites verification reports |
|
|
884
|
-
| `okstra profile show <task-type> [--resolved]` | Print a phase profile. `--resolved` expands its `{{INCLUDE:}}` targets and appends the lazy-read sidecars named in the profile body — transitively, because sidecars name sidecars of their own (`_implementation-executor.md` points at the coding-conventions preflight, the diff-review sweep, and the completion self-check). That matters because a profile is assembled from three places, so grepping only the top-level file returns false negatives: `grep clarification
|
|
885
|
+
| `okstra profile show <task-type> [--resolved]` | Print a phase profile. `--resolved` expands its `{{INCLUDE:}}` targets and appends the lazy-read sidecars named in the profile body — transitively, because sidecars name sidecars of their own (`_implementation-executor.md` points at the coding-conventions preflight, the diff-review sweep, and the completion self-check). That matters because a profile is assembled from three places, so grepping only the top-level file returns false negatives: `grep clarification scripts/okstra_ctl/phases/implementation/profile.md` finds nothing while the assembled profile has many hits. One grep over this output answers whether a task-type covers a rule. The sidecar list is read from the profile body, never hard-coded, so a newly added sidecar is picked up without a code change. Read-only: it writes no manifest and registers no run, which is what separates it from `render-bundle` — `render-bundle` answers the same question but records a run in `recent.jsonl`, so it cannot be used to look something up. Exits 2 for an unknown task-type |
|
|
885
886
|
| `okstra codex-run <args…>` | Codex lead-adapter dry-run entry point. Accepts the same arguments as `render-bundle` but owns `--render-only --lead-runtime codex`. It prepares the task bundle and prints the prompt for the Codex lead without dispatching workers |
|
|
886
|
-
| `okstra worker-dispatch --project-root <dir> --run-manifest <path> [--workers <csv>] [--dry-run]` | Provider-neutral deterministic dispatcher for `runner=cli-wrapper` assignments. It verifies each adjacent invocation specification against the immutable run manifest immediately before process creation and records `core-pre-dispatch`; native-session rows stay with the host. The default selects CLI analysis assignments only. Phase 6 uses explicit `--workers report-writer`, and a mixed analysis/report batch is rejected. `--dry-run` performs the same verification and resolution without starting a provider process. |
|
|
887
|
+
| `okstra worker-dispatch --project-root <dir> --run-manifest <path> [--workers <csv>] [--dry-run]` | Provider-neutral deterministic dispatcher for `runner=cli-wrapper` assignments. It verifies each adjacent invocation specification against the immutable run manifest immediately before process creation and records `core-pre-dispatch`; native-session rows stay with the host. The default selects CLI analysis assignments only. Phase 6 uses explicit `--workers report-writer`, and a mixed analysis/report batch is rejected. `--dry-run` performs the same verification and resolution without starting a provider process. A real dispatch records the lead checkpoints it owns in the run's lead-events ledger and returns them as `progressLines`: `phase-3-team-create` when it writes the implicit-team marker, `phase-4-dispatch` for each `initial` job, `phase-6-synthesis` on the first report-writer dispatch, and `phase-5-collect` for each `initial` dispatch it settled. |
|
|
887
888
|
| `okstra codex-dispatch --project-root <dir> --run-manifest <path> [--workers <csv>] [--dry-run]` | Compatibility alias for `okstra worker-dispatch`; it no longer selects a Codex-only transport-agent path. |
|
|
888
889
|
| `okstra agent-prompt resolve-operation --operation <id> [--json]` | Print what a non-run operation runs: its duty, its canonical role, the worker count, and one slot line per worker carrying that slot's provider and model reference. The operation contract (`agents/operations/<id>.json`) owns the duty and the count; the models come from the same project/global/bundled default chain a run uses, one distinct model per slot. A machine with fewer distinct models than the contract requires fails here rather than dispatching a short roster. The default output is fixed text because a skill body must not instruct a model to parse okstra-owned JSON; `--json` is for programmatic callers. |
|
|
889
890
|
| `okstra agent-prompt jobs --project-root <dir> --run-manifest <path> --dispatch-kind <kind> --metadata <path> [--metadata <path>] --out <path> [--json]` | Generate an immutable v2 jobs file from verified invocation metadata. Reads canonical identity, role, five digests, and actual result anchors; validates the full batch through the dispatch consumer before publishing. Rejects mixed runs or dispatch kinds, duplicate attempts, and translator input (use canonical `worker-dispatch --workers translator`). Reuses identical output; preserves differing output and requests a new `--out` path. Does not launch workers. |
|
|
891
|
+
| `okstra agent-prompt materialize --project-root <dir> --run-manifest <path> --batch <file> [--jobs-out <path>] [--json]` | Materialize every invocation of one dispatch batch in one call. The batch file holds `{"invocations": [...]}`; each entry maps the run-mode per-invocation flags (`invocation-id`, `audience`, `instruction`, `prompt`, `worker-id`, `dispatch-kind`, `assignment-ref`, `source-role-execution-ref`, `result`, `corrections`, `audit-source`, and `replace-undispatched: true`) to values. Every entry goes through the same parser and materialization as a single call and fails with the same error. Entries run in order; a failure names the entry and every invocation already published, and an identical rerun after the fix reuses those. An unknown key, a repeated invocation id, a per-invocation flag given at the top level, or mixed dispatch kinds under `--jobs-out` is refused before any entry is written. `--jobs-out` (also accepted by a single run-mode `materialize`) writes the verified jobs file for `okstra team dispatch --jobs-file` exactly as `agent-prompt jobs` would; every entry must share one dispatch kind. Prints each prompt path and then the jobs path; `--json` returns `invocations` (one single-call payload each) and `jobsPath`. |
|
|
890
892
|
| `okstra agent-prompt materialize\|check-corrections\|apply-corrections\|verify\|record-dispatch\|link-result\|reject-result\|abandon-attempt\|materialize-result\|complete\|verify-completion` | Internal invocation-contract CLI. `materialize` composes model assignment, functional duty, and task instructions; `verify` rejects identity, path, snapshot, assignment, source, or digest drift. Every run-branch report-writer prompt gets its `## Output` section (narrative, pointer record, reading audit) rendered by okstra, and an instruction body that writes a `## Output` or `## Corrections` heading is refused. A corrective report-writer round — the narrative at `reportNarrativePath` already exists and its structure parses, value defects included — must pass `--corrections <ledger>` (`schemas/report-writer-corrections-v1.0.schema.json`: `replace` / `remove` / `add` / `move` / `rewrite` entries keyed by the validator's field-path grammar, `baseNarrativePath` naming a preserved copy of the attempt, and optional `baseNarrativeSha256` binding that version): the ledger is applied to that base and checked against the writer-owned schema and the task's semantic validator before dispatch, every defect is reported at once, and okstra renders the prompt's `## Corrections` section from it; a report-writer materialization without a ledger over such a narrative is refused before any prompt is written, while a narrative whose structure does not parse (line grammar, unknown top-level field) is re-authored without one. `check-corrections --run-manifest <path> --corrections <ledger> [--json]` runs the same check without materializing (exit 1 lists the defects; `mechanical: true` means every entry is a validated `replace`, `remove`, `add`, or `move`, including derived planning step counts). `apply-corrections` with the same arguments applies such a mechanical ledger without a writer round: it writes the corrected narrative to `reportNarrativePath` and records a `lead-correction-applied` activity row (`evidenceRefs` = ledger path + correction ids) through the run's activity contract; `--rewrite-results <file>` also accepts hash-bound replacement values for exactly the requested rewrite ids. Correction-only materialization sends those target fields, evidence, and constraints instead of the initial instructions and complete synthesis packet; the runtime merges the submitted values and checks the complete narrative before writing. It refuses unresolved `rewrite` entries or any defect, a stale live narrative, a base that is the live narrative, a run without `activityContractVersion` 1, and a ledger already applied. An empty ledger can preflight the initial writer result and derive `stageMap[].stepCount` from matching execution rows without another writer call. Run-backed calls resolve `assignmentRef` from the manifest, enforce `authorizedPaths`, and reject real-path or symbolic-link escape. `record-dispatch` records a verified host-native specification before dispatch and `link-result` binds the accepted result; one result path belongs to one dispatch, so a corrective round retires the first attempt with `reject-result --dispatch-id <first> --superseded-by <corrective> --reason <text>` before the new link is accepted — the rejected row stays in `agentResultLinks` carrying `supersededBy` and `rejectionReason` rather than being deleted. The corrective dispatch is a new invocation: an invocation whose last attempt finished with a mutation takes no further attempt (`execution_manifest._validate_next_attempt` lets only `failed-no-mutation` be followed), so a retry attempt of the rejected invocation itself is refused by the manifest, and `reject-result` does not make it possible. `abandon-attempt --invocation-ref <ref> --reason <text>` closes a started attempt whose worker died without producing a result — the one case neither `link-result` (which needs the result file) nor the dispatch-failure path covers — so a retry can follow it instead of the run having to be re-rendered. It refuses any attempt whose `writePolicy.sourcePolicy.mode` is not `source-readonly`: closing an attempt records `failed-no-mutation`, which is true by policy for a read-only worker and a guess for a mutating one. Standalone calls are identified by `(purpose, invocationId)` under `.okstra/agent-invocations/<purpose>/`; they publish a canonical result envelope and publish the completion marker last. Consumers use only the `returnedBody` from `verify-completion`. Metadata contains exactly `catalogDigest`, `assignmentDigest`, `dutyDigest`, `instructionDigest`, and `promptDigest`; JSON inputs use UTF-8, sorted keys, compact separators, and no non-finite values, while duty files use versioned sorted-name/byte framing. Instruction sources use `{kind: project\|runtime, path: <relative POSIX path>}` and never persist an installed absolute runtime path. A published prompt is immutable, so re-running `materialize` with an edited instruction file fails as `existing_invocation_conflict`; `--replace-undispatched` is the one exit, for a call that failed a pre-dispatch gate and therefore ran nowhere — it covers a differing prompt and a differing metadata alike, since the two are published together and describe one call. It republishes prompt and metadata together, and it is verified rather than trusted — a row in `agentDispatches` or `workerDispatches` naming this `invocationId` refuses the replacement and names the dispatch that used it. |
|
|
891
893
|
| `okstra agent-prompt refreeze-contracts --project-root <dir> --run-manifest <path> [--json]` | Re-freeze one run's duty contract snapshot in the installed format and stamp `agentContract.catalogDigest` and `contractFormatVersion` on its run manifest. A run freezes its contracts at prepare time and pins their digest; installing a release that changed the contract format leaves that digest unmatchable, so the run can materialize no further prompt and `materialize` stops with the format message naming this command. It replaces the frozen directory's contents (no file of the old format is kept), touches no prompt, result or ledger, and reports `changed: false` when the run is already on the installed format. User-invoked recovery only — nothing runs it automatically, because a run's contracts are frozen on purpose. |
|
|
892
|
-
| `okstra team dispatch --project-root <dir> --run-manifest <path> [--workers <csv>] [--jobs-file <path>] [--dry-run]` / `okstra team await --project-root <dir> --run-manifest <path> [--json]` / `okstra team teardown --project-root <dir> --run-manifest <path> [--dry-run] [--json]` | Read a `leadRuntime=external` run manifest and dispatch, await, or tear down pane-backed workers. Default dispatch excludes report writer; Phase 6 selects it explicitly, and mixed analysis/report jobs are rejected. If a pane cannot be opened, gracefully degrade to the CLI wrapper, print a `DEGRADED <role>: cmux-pane -> cli-wrapper (<why>)` line, and record the fallback in `workerDispatches[].degradedFrom` with the reason in `degradedReason`. A degraded worker is not waited for inside the dispatch — it settles through `okstra team await` like a pane worker, so the round still runs concurrently |
|
|
894
|
+
| `okstra team dispatch --project-root <dir> --run-manifest <path> [--workers <csv>] [--jobs-file <path>] [--dry-run]` / `okstra team await --project-root <dir> --run-manifest <path> [--json]` / `okstra team teardown --project-root <dir> --run-manifest <path> [--dry-run] [--json]` | Read a `leadRuntime=external` run manifest and dispatch, await, or tear down pane-backed workers. On a `cmux-pane` run, dispatch records `phase-3-team-create` when it writes the implicit-team marker, `phase-4-dispatch` for each `initial` job and `phase-6-synthesis` on the first report-writer dispatch; await records `phase-5-poll` and `phase-5-collect` for each `initial` dispatch it settled. Both write the run's lead-events ledger and print the `PROGRESS:` lines to emit (`progressLines` under `--json`). Any other run records nothing there. Default dispatch excludes report writer; Phase 6 selects it explicitly, and mixed analysis/report jobs are rejected. If a pane cannot be opened, gracefully degrade to the CLI wrapper, print a `DEGRADED <role>: cmux-pane -> cli-wrapper (<why>)` line, and record the fallback in `workerDispatches[].degradedFrom` with the reason in `degradedReason`. A degraded worker is not waited for inside the dispatch — it settles through `okstra team await` like a pane worker, so the round still runs concurrently |
|
|
893
895
|
| `okstra agent-activity append --project-root <dir> --run-manifest <path> --kind <kind> --agent <assigned-id> (--summary <text>\|--summary-file <markdown>) --outcome <outcome> [--plan-item-id <current-id>]… [--command <text> --command-cwd <dir> --command-exit-code <n> --command-output-file <markdown>] [--request-ref <returned-ref>]` | Append one structured activity after checking the agent against this run's role assignments and every plan item against its current convergence state. Python returns an `activityRequestRef`; supply only that returned value with `--request-ref` to retry idempotently. A new call without it remains a distinct activity even with identical contents. Legacy JSON command records remain automation compatibility only. |
|
|
894
896
|
| `okstra agent-activity project --project-root <dir> --run-manifest <path> --data <data.json>` | Project this run's canonical activity events into `agentActivity[]`. The command preserves event order, rejects duplicate or decreasing activity IDs, and replaces no other report field. A historical manifest without `activityContractVersion: 1` returns an empty projection and leaves data.json unchanged. Normal Phase 7 execution reaches this behavior through `report-finalize`; use the standalone command only for diagnostics. |
|
|
895
897
|
| `okstra lead-progress append --project-root <dir> --run-manifest <path> --phase <phase-id> [--worker <role>] [--field NAME=VALUE]… [--detail <text>]` | Append one `PROGRESS:` checkpoint to the run's `leadEventsPath` and print the line to emit to the user as `progressLine`. The checkpoint is what `validate_session_conformance.py` reads, and on a host whose adapter declares `sessionAccounting: artifact-only` the ledger is the only place it can read one — a conversation line alone is not retained there. `--phase` accepts the phase ids the lead contract's "Progress reporting (BLOCKING)" list defines; the fixed-prose checkpoints render their contract wording without `--detail`. `--worker` is resolved against team-state and rewritten to the roster `workers[].role` the per-worker checks match, so a phase-specific functional label still lands on the right worker; a name that matches no roster row is written through with a note on stderr. |
|
|
896
|
-
| `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. |
|
|
898
|
+
| `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, and its repeatable `--supersedes <C-NNN>` names a carried decision the new question replaces (assembly publishes that carried row as `obsolete` once the new row is resolved), `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. |
|
|
897
899
|
| `okstra option-votes gaps --task-manifest <task-manifest.json> (--report <final-report .data.json> \| --narrative <report-writer narrative.md>) [--json]` | List the `implementation-option-selection` candidates that fail the ranking rule on the every-analyser clause alone, and name the analyser owing each vote. Round 1 runs the designers in parallel, so each votes only on the candidates it proposed and the merged set keeps a different hole per analyser; a run whose comparison had converged can end `blocked` with an empty `rankedOptions` for that reason alone. The lead reads this before concluding `blocked` and dispatches one vote-completion assignment per named analyser — a feasibility verdict on the named candidate and nothing else, so the run stays in `candidate-comparison` mode. A candidate carrying `safetyBlockers` or `unresolvedFeasibilityFacts`, or one that could not reach two `feasible` votes even with every missing vote, is excluded: another round would not change it. `--narrative` reads the writer's markdown before assembly and tolerates its value defects; `--report` reads a published record. |
|
|
898
900
|
| `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. |
|
|
899
901
|
| `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. |
|
|
900
|
-
| `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),
|
|
902
|
+
| `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, records a `verified` row per cleared stage for a release-ready final-verification (`record-verified`, the same write as `okstra handoff record-verified`), 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), tears down eligible stage worktrees, and removes what no reader needs after the run (`prune-run-artifacts`: every `node_modules` and `.next` directory under the run directory, and the dispatch snapshots and publication locks of a passed run or of an earlier run superseded by one). 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; `prune-run-artifacts` still runs, because the lockfiles, logs and experiment directories it leaves are enough to reinstall and it leaves the dispatch snapshots of a failed run that no later run has passed. 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. Repairable failures return `recovery.mode=same-run`, complete assembly owner issues, and `resumeCommand` using this manifest; `nextCommand` does not ask for a new run. A validator-only failure targeting an earlier phase retains that recovery target. Finalization step failures and run-bound contract exceptions from `plan-items` and `agent-prompt` write bounded runtime error records, with any logging failure reported separately. Without `--only` it first records the lead's `phase-7-persist` checkpoint, ahead of `validate-run`, and returns it as `progressLines`. This is the shared path for every lead adapter. |
|
|
901
903
|
| `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`. |
|
|
902
904
|
| `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 |
|
|
903
905
|
| `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 |
|
|
@@ -909,7 +911,7 @@ The convergence state lifecycle is `groups v1.0 → work v1.0 → final v1.3`; r
|
|
|
909
911
|
|
|
910
912
|
`okstra convergence apply-critic-gaps` is the only transition that may add verified coverage gaps to terminal main-queue state. `okstra plan-items extract` creates the complete plan queue, and `okstra plan-items validate` rejects any omission or drift before verifier dispatch.
|
|
911
913
|
|
|
912
|
-
`okstra convergence` and `okstra plan-items` are internal admin CLI families used by the lead protocol. Each is an internal admin CLI, not a user-facing skill, and their presence does not add a public skill. The former `okstra-convergence` skill remains obsolete; the installed `prompts/lead/convergence.md` and `
|
|
914
|
+
`okstra convergence` and `okstra plan-items` are internal admin CLI families used by the lead protocol. Each is an internal admin CLI, not a user-facing skill, and their presence does not add a public skill. The former `okstra-convergence` skill remains obsolete; the installed `prompts/lead/convergence.md` and `scripts/okstra_ctl/phases/implementation_planning/instructions/plan-body-verification.md` contracts tell the lead when to invoke these operations.
|
|
913
915
|
|
|
914
916
|
> Every subcommand is wired to `PYTHONPATH` and `~/.okstra/lib/python` by the Python helper (`src/lib/python-helper.mts`) spawned by `bin/okstra`. When invoking `python3 -m okstra_ctl.*` directly, you must configure `PYTHONPATH` yourself.
|
|
915
917
|
|
|
@@ -953,4 +955,4 @@ For every dispatch, whichever provider runs it, okstra creates a `runs/<task-typ
|
|
|
953
955
|
|
|
954
956
|
**Progress appears in the worker's own pane.** Earlier versions split a sibling `tail -F` trace pane next to each worker; they no longer do, and no trace pane is created at all. Instead the presentation is passed to the entrypoint as `--presentation live|quiet`, and only a backend that opened a pane asks for `live` — the default, and what a `cli-wrapper` subagent dispatch passes, is `quiet`. Under `live` each event becomes one readable row on the worker's own streams — `→ Bash: npm run check`, then ` ← ok (2481 bytes)`, and `!! PERMISSION DENIED — <tool>: <reason>` for a refusal. Under `quiet` progress is withheld and only the worker's closing text is printed, which is what a dispatch on a machine with no pane surface needs. The `.log` sidecar records the progress either way, so withholding it from the screen loses nothing.
|
|
955
957
|
|
|
956
|
-
Every pane tag this script once scanned has lost its writer, and the script itself is gone. `@okstra_trace_run` / `@okstra_status` went inert when the wrappers stopped splitting a trace pane; `@okstra_worker_run` went with the pane-tagging dispatch backend; and `okstra-trace-cleanup.sh` followed, because its title scan never matched a cmux surface and current runs are cmux (`terminalBackend: cmux-pane`). What okstra closes now are the panes it opened itself and recorded as `paneId` in `team-state.workerDispatches[]`. `okstra team reclaim` is the round boundary: it closes the panes of dispatches that have finished, leaves an in-progress one alone,
|
|
958
|
+
Every pane tag this script once scanned has lost its writer, and the script itself is gone. `@okstra_trace_run` / `@okstra_status` went inert when the wrappers stopped splitting a trace pane; `@okstra_worker_run` went with the pane-tagging dispatch backend; and `okstra-trace-cleanup.sh` followed, because its title scan never matched a cmux surface and current runs are cmux (`terminalBackend: cmux-pane`). What okstra closes now are the panes it opened itself and recorded as `paneId` in `team-state.workerDispatches[]`. `okstra team reclaim` is the round boundary: it closes the panes of dispatches that have finished, leaves an in-progress one alone, records `phase-batch-cleanup panes=<n>` with the number it closed (`--gate` prints `phase-gate-cleanup` before a user gate and records nothing), and with `--dry-run` prints the same set without closing. `okstra team teardown` is the end of the run: every recorded pane, plus a write-off for any dispatch that never finished. A pane the harness opened for its own teammate is out of scope for both — okstra never opened it and holds no id for it. An `okstra-compact-reminder.sh` `SessionStart` hook (matcher `compact`) re-injects the boundary obligation after a `/compact`.
|
|
@@ -9,8 +9,9 @@ Use this matrix before changing high-risk repo contracts. Update the source file
|
|
|
9
9
|
| Add public skill | `src/lib/skill-catalog.mts`, `.claude-plugin/plugin.json`, `skills/<name>/SKILL.md`, `docs/skills/<name>.md`, `docs/skills/README.md`, `docs/project-structure-overview.md`, `README.md` | `tests-js/skill-catalog.test.mjs`, `tests/contract/test_docs_runtime_contract.py` |
|
|
10
10
|
| Change manager contract | `scripts/okstra_ctl/manager_*.py`, `skills/okstra-manager/SKILL.md`, `docs/skills/okstra-manager.md`, `docs/cli.md`, `docs/architecture/storage-model.md` | `tests-js/cli-wrapper-contract.test.mjs`, `tests/test_okstra_manager_*.py` |
|
|
11
11
|
| Change a skill's behaviour | `skills/<name>/SKILL.md`, `docs/skills/<name>.md` (every Guarantees row names its enforcement or says `unenforced`) | `tests/contract/test_skill_specs.py` |
|
|
12
|
-
| Add phase | `scripts/okstra_ctl/phases/catalog.py`, `scripts/okstra_ctl/workflow.py`,
|
|
13
|
-
| Change worker roster |
|
|
12
|
+
| Add phase | `scripts/okstra_ctl/phases/catalog.py`, `scripts/okstra_ctl/workflow.py`, `scripts/okstra_ctl/phases/<package>/` (`profile.md`, `profile.json`, `spec.md`, policy, report assets and tests), common assembly in `validators/`, `tests/contract/test_phase_catalog.py` | workflow and validation contract tests |
|
|
13
|
+
| Change worker roster | `scripts/okstra_ctl/phases/<package>/profile.md` and `profile.json`, `scripts/okstra_ctl/workers.py`, `tests/contract/test_repo_contracts.py` | worker roster contract tests |
|
|
14
|
+
| Change phase policy | `scripts/okstra_ctl/phases/<package>/`, its `spec.md`, and the common caller; continuation decisions belong in `prompts/lead/phase-routing.md` | phase-local tests, `tests/contract/test_phase_catalog.py`, `tests/contract/test_skill_specs.py` |
|
|
14
15
|
| Change report section | `schemas/final-report-v2.0.schema.json`, `templates/reports/final-report-v2.template.md`, `scripts/okstra_ctl/render_final_report.py`, `validators/validate-run.py` | final-report schema, renderer, and validator tests |
|
|
15
16
|
| Maintain Korean review mirrors | `config/korean-sources.json`, `tools/korean-sources/` (`cli.mjs`, `baseline.mjs`, `config.mjs`, `markdown.mjs`, and the shared workflow), `.agents/skills/sync-korean-sources/`, `.claude/skills/sync-korean-sources/` | `tests-js/korean-sources-*.test.mjs` (`cli`, `config`, `markdown`, and `skill`) |
|
|
16
17
|
|
|
@@ -245,7 +245,7 @@ Recommended design:
|
|
|
245
245
|
|
|
246
246
|
Change targets:
|
|
247
247
|
|
|
248
|
-
- `
|
|
248
|
+
- `scripts/okstra_ctl/phases/requirements_discovery/profile.md`
|
|
249
249
|
- `scripts/okstra_ctl/workflow.py`
|
|
250
250
|
- Next-phase selection UI in `skills/okstra-run/SKILL.md`
|
|
251
251
|
- `skills/okstra-inspect/SKILL.md` (the former `okstra-status` skill folded into `okstra-inspect`)
|
|
@@ -174,7 +174,7 @@ The Module column below is where the command's behaviour lives — a `src/` modu
|
|
|
174
174
|
| `git-reconcile` | `scripts/okstra_ctl/git_reconcile.py` | Reconcile stale stage SHAs after external git history changes |
|
|
175
175
|
| `stage-close` | `scripts/okstra_ctl/stage_close.py` | Close an already-landed implementation stage as done (commit + conformance evidence required) |
|
|
176
176
|
| `option-votes` | `scripts/okstra_ctl/option_votes.py` | List the implementation candidates that only lack feasibility votes, and the analyser owing each one |
|
|
177
|
-
| `handoff` | `scripts/okstra_ctl/handoff.py` |
|
|
177
|
+
| `handoff` | `scripts/okstra_ctl/handoff.py` | CLI assembly and common verification recording; release policy is in `phases/release_handoff/operations.py` |
|
|
178
178
|
| `integrate-stages` | `scripts/okstra_ctl/stage_integrate.py` | Merge verified stages into the task worktree and clean stage worktrees |
|
|
179
179
|
| `task-list`, `task-show` | `scripts/okstra_ctl/task_list_cli.py`, `scripts/okstra_ctl/task_show_cli.py` | Task/run introspection for skills; `task-show` consumes the Python task read-side snapshot |
|
|
180
180
|
| `resolve-task-key` | `scripts/okstra_ctl/resolve_task_key.py` | Resolve a bare task-id to candidate task-keys from the project catalog |
|
|
@@ -196,6 +196,7 @@ The Module column below is where the command's behaviour lives — a `src/` modu
|
|
|
196
196
|
| `convergence` | `scripts/okstra_ctl/convergence.py` | Internal admin CLI for the deterministic Phase 5.5 convergence engine (`seed`/`plan-round`/`apply-round`/`critic-prompt`/`apply-critic-gaps`/`finalize`/`validate`/`example`; Python: `okstra_ctl.convergence`) |
|
|
197
197
|
| `plan-items` | `scripts/okstra_ctl/plan_items_cli.py` | Internal admin CLI for deterministic plan-body item extraction and exact-match validation (`extract`/`validate`; Python: `okstra_ctl.plan_items_cli`) |
|
|
198
198
|
| `agent-activity` | `scripts/okstra_ctl/agent/activity.py` | Thin Node shim for `okstra_ctl.agent.activity`; `append` records one run-bound activity and `project` writes the validated event projection into final-report data |
|
|
199
|
+
| `prune-run-artifacts` | `scripts/okstra_ctl/run_artifact_prune.py` | List, and with `--apply` remove, run artifacts no reader needs after the run (`node_modules` / `.next`, and a validated run's dispatch snapshots and publication locks) under `.okstra/tasks` |
|
|
199
200
|
| `report-finalize` | `scripts/okstra_ctl/report_finalize.py` | Run the whole Phase 7 post-report sequence in contractual order (Python: `okstra_ctl.report_finalize`) — the single reference point shared with the Codex lead adapter |
|
|
200
201
|
| `render-views` | `scripts/okstra-render-report-views.py` | Render schema v2 data with its task-specific human template, or use the quick-report compatibility view |
|
|
201
202
|
| `render-final-report`, `inject-report-index` | `scripts/okstra-render-final-report.py`, `scripts/okstra-inject-report-index.py` | Render the full reading copy Markdown from data.json on demand; v1 index injection remains compatibility-only |
|
|
@@ -243,11 +244,11 @@ Important modules:
|
|
|
243
244
|
| `run.py` | `prepare_task_bundle()` single authority and CLI parser; for final-verification it passes CLI values to `phases/final_verification/`, whose `entry.py` builds the target request, applies the acquired target to render context, and writes the `verification-target.md` snapshot and digest before manifests and prompts are rendered |
|
|
244
245
|
| `agent/activity.py` | Records activity rows against run-manifest identity, imports validated command evidence from worker audit sidecars, and deterministically projects the current run's `lead-events-*.jsonl` activity rows into `agentActivity[]`. Manifests without `activityContractVersion: 1` are left unchanged. |
|
|
245
246
|
| `exact_coverage.py` | Shared pure calculator for requirement coverage and scope precision in option selection and selected-direction planning |
|
|
246
|
-
| `
|
|
247
|
+
| `phases/implementation_option_selection/validation.py` | Option-selection criteria, weighting, candidate fingerprint convergence, ranking, and semantic validation |
|
|
247
248
|
| `implementation_direction.py` | Selected report/response validation, direction snapshot materialization, and selected-direction reference validation |
|
|
248
|
-
| `technical_verification.py` | Optional `technical-verification` phase backend — resolves and freezes the explicitly classified unresolved facts from the same task's implementation-option-selection report into `state/technical-verification-input-<seq>.json` (`write_technical_verification_input` / `resolve_technical_verification_input`, driven from `run.py`). No selected direction is required and unresolved user decisions still block entry; it links test inputs to observed results and never produces adoption approval or changes candidate feasibility |
|
|
249
|
+
| `phases/technical_verification/entry.py` | Optional `technical-verification` phase backend — resolves and freezes the explicitly classified unresolved facts from the same task's implementation-option-selection report into `state/technical-verification-input-<seq>.json` (`write_technical_verification_input` / `resolve_technical_verification_input`, driven from `run.py`). No selected direction is required and unresolved user decisions still block entry; it links test inputs to observed results and never produces adoption approval or changes candidate feasibility |
|
|
249
250
|
| `verification_target.py` | Shared reader for the prepared final-verification target snapshot (`verification-target.md`) written by `phases/final_verification/entry.py::write_verification_target_snapshot`. One implementation of the digest/scope rule serves both consumers — report assembly (records `verificationScope`) and `validators/validate-run.py` (re-checks the published report against the target) — so the two cannot drift |
|
|
250
|
-
| `
|
|
251
|
+
| `phases/implementation/entry.py` | `implementation` single-stage run orchestration — read the Stage Lifecycle Snapshot → pick an available Stage Map entry → provision an isolated stage worktree → publish the selected stage as run context (extracted from `run.py`) |
|
|
251
252
|
| `stage_targets.py` | Stage readiness/verification policy SSOT — from the Stage Lifecycle Snapshot (`consumers.jsonl` ledger + carry sidecar backfill + active registry reservation) it decides which stage is runnable, which commit it branches from, and the Git and ledger facts final-verification builds its target from: whole-task integration, nested stage worktree relocation, the stage that contains every other done stage, and teardown after the verdict. `order_stage_closure` topologically sorts (Kahn) the dependency closure of the wizard's multi-selected stage set to produce the unattended `chain-stages` chaining order |
|
|
252
253
|
| `stage_fix_carry.py` | fix-run carry derivation for a re-run on an `implementation` stage whose latest final-report data.json carries verifier `FAIL` verdicts — collects the previous report path, previous run HEAD, failed verifiers, carried blocking findings, and a routing recommendation, which `run.py` renders into the analysis profile through the `{{FIX_RUN_CONTEXT}}` token. A first run, or a re-run after `PASS`, yields no carry and renders the token empty |
|
|
253
254
|
| `stage_reconcile.py` | best-effort git reconciliation shared by the stage prepare flow (delegates to `git_reconcile.auto_reconcile`; advisory — failures are only reported to stderr, the dependency gate stays authoritative) |
|
|
@@ -270,7 +271,7 @@ Important modules:
|
|
|
270
271
|
| `timeline_runs.py` | read-side overlay of a `history/timeline.json` entry with its run-manifest's current facts (`current_run_facts`) — the entry is a prepare-time snapshot (`status`, `workflowSnapshot`, reserved `reportRecordPath`) and `validate-run` writes the end state to the run-manifest only; a run whose `validation.status` is `not-run` projects no report path. Shared by `recap.py` and the `history-input` / overview projections in `model_io/renderers.py` |
|
|
271
272
|
| `render.py` | task manifest, run manifest, timeline, task index, discovery, team-state, prompt/template render |
|
|
272
273
|
| `group_context.py` | task-group context document (`.okstra/briefs/<task-group>/group-context.md`): the skeleton writer behind `okstra group-context init` (template `templates/reports/group-context.template.md`), `validate_group_context` (four required sections, no template placeholder left, directory slug matches the frontmatter `task-group`) that `validators/validate-brief.py` dispatches to on frontmatter `type: group-context`, and the path helpers `run.py` uses to validate the file at preflight and copy it to `instruction-set/task-group-context.md` for the analysis packet's `## Task-Group Context` section |
|
|
273
|
-
| `workflow.py` |
|
|
274
|
+
| `workflow.py` | Common phase sequence (`PHASE_SEQUENCE`) and boundary rendering. Allowed outputs and forbidden actions are read from the selected phase's `boundary.json`; next-phase decisions remain in the lead routing instructions. |
|
|
274
275
|
| `next_phase.py` | `workflow.nextRecommendedPhase` SSOT — the pointer's shape (`make` / `is_pointer` over `{phase, status, rationale}`, `status` ∈ `ready`/`pending`/`blocked`/`terminal`), the promotion of a legacy string pointer (`promote`), the projection of one report's routing field into a pointer (`project`), and the `ready`-only read the shell and wizard autofill share (`autofill_task_type`). There is no static phase table and no sequence walk: the next phase comes from what the report authored, and nothing else may compute one |
|
|
275
276
|
| `workers.py`, `models.py` | Worker roster; `models.py` is the model catalog SSOT (`ModelSpec` per alias + `ROLE_DEFAULTS`) — add-a-model single reference point from which picker options, codex pricing, and role defaults all derive |
|
|
276
277
|
| `worktree/`, `worktree_registry.py` | One worktree per task-key, branch registry, sync dirs/files/snapshots. The package layers the job: `naming` (path/branch strings, no disk), `sync_config` (which paths follow the checkout across), `git_ops` (the git calls), then `cleanliness` (dirty by okstra's definition), `linking` (installs the symlinks), `decisions` (answers what provisioning would do, without doing it), and `provision` — the only layer with side effects |
|
|
@@ -312,6 +313,7 @@ Important modules:
|
|
|
312
313
|
| `error_log_write.py` | the single writer for `errors-*.jsonl`, shared by the `okstra error-log` CLI and by `dispatch_core`, which records a wrapper's non-zero exit as a `cli-failure` in-process. Owns the agent/role/error-type allow-lists (agents derived from the provider registry) and the cause-evidence gate |
|
|
313
314
|
| `run_audit.py` | backend for the okstra-inspect run-audit facet — reads run-manifest / final-report / team-state artifacts and reports invariant violations (read-only, never the lead's self-report) |
|
|
314
315
|
| `worker_heartbeat.py`, `worker_liveness.py` | `worker_heartbeat` is the single definition of the `- PROGRESS:` heartbeat line shape and its 5-minute (+60s grace) cadence budget, shared by the Phase 7 audit (`validators/validate_session_conformance.py`) and the live probe; `worker_liveness` backs `okstra worker-liveness`, resolving each pending worker from its team-state row (`livenessMode` picks the artifact, `startedAt` anchors the grace) and reporting `stalled` (heartbeat past the budget, or none yet for this dispatch past the grace) or `did-not-launch` (no wrapper `.log`/`.status.json` past the launch grace) |
|
|
316
|
+
| `run_artifact_prune.py` | finds `node_modules` / `.next` directories under a root without following symbolic links, and the `mutationAuditSnapshotPath` / `<promptPath>.publish.lock` files recorded in the team state of runs whose validation passed or that precede a passed run in the same `manifests/`, and removes them; shared by the Phase 7 `prune-run-artifacts` step and `okstra prune-run-artifacts` |
|
|
315
317
|
| `log_report.py`, `time_report.py` | read-side backend for the okstra-inspect logs/time facets (`okstra log-report` pairs each wrapper transcript `.log` with its sibling prompt `.md` and reports both byte counts without changing legacy transcript-size fields; `okstra time-report` is per-task time aggregation) |
|
|
316
318
|
| `rollup.py` | read-side backend for the okstra-rollup skill — fans the catalog out per task-group (or the whole project) and deterministically aggregates each task's run count, elapsed time (raw ms), error count, and latest report path, plus group-level totals/status, category, and phase distribution. Reuses the `time_report`/`error_log_core` functions and delegates report-body synthesis to the skill |
|
|
317
319
|
| `usage_report.py` | Read-only okstra-usage backend — scans the whole current project's recent run timelines, defaults to 30 days, and returns task-type coverage, raw/billable tokens, known USD cost, CPU-sum and wall-clock milliseconds, unavailable reason counts, and unmatched pricing models |
|
|
@@ -322,7 +324,7 @@ Important modules:
|
|
|
322
324
|
| `code_review_target.py` | `okstra code-review target` backend — argument validation and JSON shaping only. Stage mode delegates whole to `okstra_project.state.code_review_target_snapshot`; branch mode is resolved here, defaulting the diff base to the merge-base with the default branch (`refs/remotes/origin/HEAD`, else `main`/`master`). Read-only: it never creates the review directory |
|
|
323
325
|
| `session.py`, `seeding.py`, `locks.py`, `invocation.py`, `sequence.py`, `ids.py`, `material.py` | Supporting lifecycle helpers |
|
|
324
326
|
| `pane_reclaim.py` | resolves which runs of the current project still hold a non-terminal dispatch, so the `SessionStart(compact)` hook can re-inject the pane-cleanup obligation for them. The signal is the newest `team-state` per run directory, not the central run index — an in-session run never appears there (ADR-0011). Imports the status split from the `dispatch_state.NON_TERMINAL_WORKER_STATUSES` SSOT |
|
|
325
|
-
| `
|
|
327
|
+
| `phases/improvement_discovery/lenses.py` | lens enum SSOT + cap constants for the improvement-discovery phase (DEFAULT 8, ABSOLUTE 12, MIN/MAX PRIORITY 1/4, SOURCE_WORKERS) |
|
|
326
328
|
| `container.py` | the `okstra container` convergence entrypoint of the okstra-container-build public skill — `provision_container_group` + `up`/`status`/`down` dispatch, env-override synthesis, compose argv assembly, and healthcheck polling |
|
|
327
329
|
| `plan_run_root.py` | shared helper deriving `approved_plan_path` → `plan_run_root` and back-tracing the task-key |
|
|
328
330
|
| `manager_cli.py` | `okstra manager` Python entrypoint — purpose-specific fixed text by default, machine JSON with `--json` |
|
|
@@ -334,14 +336,17 @@ Important modules:
|
|
|
334
336
|
| `manager_split.py` | `okstra manager task split` — validates a tracker split plan, renders one brief per (issue, project) with a `## Project Scope` section, checks each with `validators/validate-brief.py` before writing, and registers the children |
|
|
335
337
|
| `agent/invocation.py` | Deep invocation-contract module — composes model assignment, common/functional duty, and task instructions; publishes immutable prompt/metadata pairs; verifies five digests; owns standalone result/completion envelopes |
|
|
336
338
|
| `agent/evidence_recovery.py` | Issues a same-model, same-role evidence-recovery invocation over a terminal-state attempt — verifies the source invocation metadata and existing result, then republishes a suffixed prompt/metadata/result triple (`-evidence-recovery-<attempt>`) that preserves the original model assignment while confining the child to preserving the earlier result's evidence rather than re-running the completed work (`prepare_evidence_recovery`, driven from `dispatch_core`) |
|
|
337
|
-
| `agent/prompt_cli/` | CLI boundary for run-backed and standalone materialization/verification plus host-native dispatch and result-link records. `inputs` resolves the path arguments this model-facing surface cannot trust and `emit` writes the result; above them `run_identity` refuses a role the run never issued and `dynamic_verifier` reserves a re-verification slot only after that role qualifies; `materialize` authors the specification (every report-writer prompt gets the okstra-rendered `## Output`; with `--corrections` it runs the ledger check in `corrections` and prepends `## Corrections`; without one it refuses a corrective dispatch over a parsing narrative), `results` links what came back, and `cli` is the argparse surface with the command's canonical USAGE epilog (`check-corrections` runs the ledger check without materializing; `apply-corrections` writes a mechanical ledger to the narrative and records the `lead-correction-applied` activity row via `corrections.run_corrections_apply`) |
|
|
339
|
+
| `agent/prompt_cli/` | CLI boundary for run-backed and standalone materialization/verification plus host-native dispatch and result-link records. `inputs` resolves the path arguments this model-facing surface cannot trust and `emit` writes the result; above them `run_identity` refuses a role the run never issued and `dynamic_verifier` reserves a re-verification slot only after that role qualifies; `materialize` authors the specification (every report-writer prompt gets the okstra-rendered `## Output`; with `--corrections` it runs the ledger check in `corrections` and prepends `## Corrections`; without one it refuses a corrective dispatch over a parsing narrative), `results` links what came back, `batch` runs `materialize --batch` (each entry through the same parser and `materialize`, then the `jobs` generator for `--jobs-out`), and `cli` is the argparse surface with the command's canonical USAGE epilog (`check-corrections` runs the ledger check without materializing; `apply-corrections` writes a mechanical ledger to the narrative and records the `lead-correction-applied` activity row via `corrections.run_corrections_apply`) |
|
|
338
340
|
| `dispatch_state.py` | Provider-neutral `WorkerJob`, invocation metadata validation, immutable host-native dispatch/result-link recording, and shared team-state mutation helpers |
|
|
339
341
|
| `dispatch_core.py` | Backend-neutral worker dispatch core — verifies invocation metadata immediately before worker execution, then records and collects code-owned process/pane attempts shared by every lead runtime |
|
|
340
342
|
| `worker_dispatch.py` | Provider-neutral deterministic dispatcher for every `runner=cli-wrapper` assignment; it never composes or rewrites a prompt |
|
|
341
343
|
| `cmux.py` | cmux-pane worker backend — a worker that gets a pane frees the lead process, and anything that stops a pane opening degrades quietly to the blocking wrapper. Detects a usable cmux session before selecting the backend (CLI resolves + ping answers PONG + the lead's workspace is resolvable), derives placement from the workspace geometry each dispatch, relays lead/worker events to the cmux sidebar, and records the run's terminal backend in the manifest so both phases of a run land on one backend. A sandbox that hides cmux (`PermissionError` on the socket) stops dispatch with the remedy instead of degrading into the same broken fallback; a quit app (`FileNotFoundError`) still degrades |
|
|
342
344
|
| `codex_dispatch.py` | Compatibility adapter delegating `okstra codex-dispatch` to the provider-neutral `worker_dispatch` path |
|
|
343
345
|
| `analysis_packet.py` | assembles the compact analysis-worker input packet for a task run from worker-owned profile sections; report/lead procedure stays outside the packet |
|
|
344
|
-
| `
|
|
346
|
+
| `analysis_scope.py` | Shared normalized project-relative path and scope-inclusion predicates for analysis evidence and project-map validation |
|
|
347
|
+
| `technical_verification_facts.py` | Shared unresolved technical-fact identities, candidate safety checks and user-decision gate consumed by option selection and technical verification |
|
|
348
|
+
| `handoff.py`, `handoff_verification.py`, `handoff_error.py` | Common verification recording, accepted-evidence reading and handoff error type; release-specific preparation and remote-operation policy live in `phases/release_handoff/` |
|
|
349
|
+
| `analysis_inputs.py` | shared input boundary for `project-analysis`, `feature-analysis`, and `change-impact-analysis` — validates evidence-report identity and review status, enforces the type-to-type relation allowlist, computes `exact`/`stale` freshness, and exposes report candidates to the phase-owned feature-target resolver |
|
|
345
350
|
| `user_response.py` | parses clarification/approval responses and the analysis-review sidecar; `parse_analysis_review` validates accepted, revision-requested, and rejected decisions plus their affected IDs and reason; `format_show_view` prints why-asked, linked plan items, and cited artifacts for the in-session picker |
|
|
346
351
|
| `context_cost.py` | read-side context-cost estimator for a prepared okstra task bundle (the `okstra context-cost` backend) |
|
|
347
352
|
| `schema_excerpt.py` | generates a task-type-scoped excerpt of the final-report schema — a schema reduction to inject into the worker/lead prompt |
|
|
@@ -366,10 +371,10 @@ Important modules:
|
|
|
366
371
|
| `plan_items.py`, `plan_items_cli.py` | deterministic extraction of the report-writer narrative `P-*` plan-item queue plus the `okstra plan-items extract` / `validate` / `seed` / `collect-verdicts` / `apply-verdicts` / `derivations` adapter; v2 data.json remains a read input |
|
|
367
372
|
| `claim_reproduction.py` | reproduces a plan-body single-vote `fact` claim before it can block on one vote — runs the declared probe (`path-exists` / `path-absent` / `literal-present` / `literal-absent` / `citations-differ`) inside the resolved project root and returns `reproduced` / `not-reproduced` / `not-runnable`, which `plan-items apply-verdicts --run-manifest` writes into `reproductionResult` (always overwriting the worker-sent value so a verifier cannot score its own claim). A `judgement` claim, or a `fact` that does not reproduce, takes the quorum route |
|
|
368
373
|
| `plan_derivations.py` | the supersession sweep `_common-contract.md` requires an author to do by hand — extracts the symbols, paths, and ids an answered clarification names and reports every plan string that mentions one. Advisory: it locates candidates and never judges which are now false |
|
|
369
|
-
| `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 `
|
|
374
|
+
| `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 `scripts/okstra_ctl/phases/requirements_discovery/validation.py` so the planning report and fan-out packets cannot drift |
|
|
370
375
|
| `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 |
|
|
371
376
|
| `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 |
|
|
372
|
-
| `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 |
|
|
377
|
+
| `report_finalize.py` | Phase 7 post-report sequence **SSOT** — runs `translate` → `token-usage` → `render-views` → `spawn-followups` → `record-verified` → `validate-run` → `record-group-memory` → `teardown-stages` → `prune-run-artifacts` 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; `prune-run-artifacts` (removes `node_modules` / `.next` under the run directory, and a validated run's dispatch snapshots and publication locks) always runs. 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 |
|
|
373
378
|
| `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` |
|
|
374
379
|
| `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 |
|
|
375
380
|
| `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 |
|
|
@@ -382,7 +387,7 @@ Important modules:
|
|
|
382
387
|
| `contract_refreeze.py` | re-freezes a running run's frozen contracts in the installed format. A run freezes its duty/role/common contracts at start and pins their digest, so installing a release that changed the contract format leaves that run unable to produce another prompt (`run duty snapshot catalog digest does not match`). Backs `okstra agent-prompt refreeze-contracts`, rewrites the frozen copies and the manifest digest only, and never touches a prompt, result or ledger |
|
|
383
388
|
| `operation_invocation.py` | prepares an Okstra-owned LLM operation that runs outside `okstra-run` — the operation contract (`agents/operations/<id>.json`) owns the duty and the worker count, and the role is derived from that duty's `roleId`, so a skill passes the operation name instead of assembling role/provider/model itself (ADR-0017). Backs `okstra agent-prompt resolve-operation` |
|
|
384
389
|
| `phases/catalog.py` | Fixed map from the 12 public task types to their phase package names, whether each phase has moved into `phases/<package>/`, and its HTML view builder. Resolves a task type's profile Markdown/JSON and phase-owned report templates inside one asset root (repo checkout, `runtime/python`, or `~/.okstra/lib/python`) and resolves `{{INCLUDE:...}}` targets for a phase `profile.md`. Importing it loads no phase module |
|
|
385
|
-
| `phases/final_verification/` |
|
|
390
|
+
| `phases/final_verification/` | Final-verification policy and assets: `profile.md`/`profile.json` (recorded under the logical paths `prompts/profiles/final-verification.*`), `spec.md` (process note and guarantees), `entry.py` (verification-target request, snapshot writer, prepare-flag checks), `validation.py` (added-surface, verdict, and scope checks that `validate-run` calls before its routing check), `wizard.py` (whole-task pick condition), `target.py` (`acquire_final_verification_target()`: chooses single-stage, containing-stage, or integrated whole-task target behind one task-key mutex), `report.py` (HTML view builder and `verificationScope` reader), and `report_assets/` (report body templates). Its `tests/` directory is collected by pytest and left out of the runtime copy |
|
|
386
391
|
| `report_template_loader.py` | Jinja loader for report templates: a logical name owned by a migrated phase opens from that phase's `report_assets/`, and every other name opens from `templates/reports` |
|
|
387
392
|
| `contract_graph.py`, `contract_graph_cli.py` | runtime-contract graph loader + cross-reference/dependency-closure validator and its `okstra contract-check --root <dir> (--profile\|--operation)` CLI boundary. Loads the agent contract schemas (`common`/`role`/`duty`/`profile`/`operation`), validates known role capabilities, and reports the dependency closure with per-file `path`/`schemaVersion`/`sha256`; an invalid contract raises `ContractGraphError` |
|
|
388
393
|
| `json_boundary.py` | strict JSON persistence boundaries for okstra-owned artifacts — a sealed `ExternalJsonSource` (validated producer + path) is the only way owned JSON is read, and `JsonBoundaryError` names artifact / reason / path when a write cannot satisfy its contract; the SSOT that keeps the model out of internal JSON key/path authorship |
|
|
@@ -416,6 +421,27 @@ Important modules:
|
|
|
416
421
|
|
|
417
422
|
> `i18n.py` (the final-report i18n dictionary loader + Jinja2 lookup) is an intentionally undocumented internal helper — it is a render helper that users and contributors do not need to know about in the canonical docs, so it is excluded from the module map.
|
|
418
423
|
|
|
424
|
+
#### Phase packages
|
|
425
|
+
|
|
426
|
+
All 12 task types have a phase package. Each phase owns `profile.md`, `profile.json`, `boundary.json`, `spec.md`, `report.py`, dedicated `report_assets/` and its policy tests. The catalog resolves the existing logical profile and template names to these files. Pytest collects phase-local tests; the runtime copy excludes them. Common report shells, schemas, worker dispatch and evidence readers remain shared.
|
|
427
|
+
|
|
428
|
+
| Task type and specification | Phase-owned policy |
|
|
429
|
+
|---|---|
|
|
430
|
+
| [requirements-discovery](../scripts/okstra_ctl/phases/requirements_discovery/spec.md) | `fanout.py` orders decomposed units; `validation.py` checks their provenance, dependencies and index. |
|
|
431
|
+
| [improvement-discovery](../scripts/okstra_ctl/phases/improvement_discovery/spec.md) | `lenses.py` defines scan lenses and bounds; `validation.py` checks candidate scope, sources and report branches. [Input template](../scripts/okstra_ctl/phases/improvement_discovery/report_assets/improvement-discovery-input.template.md). |
|
|
432
|
+
| [project-analysis](../scripts/okstra_ctl/phases/project_analysis/spec.md) | `entry.py` rejects upstream inputs; `validation.py` checks entry-point scope and component references. [Input template](../scripts/okstra_ctl/phases/project_analysis/report_assets/project-analysis-input.template.md). |
|
|
433
|
+
| [feature-analysis](../scripts/okstra_ctl/phases/feature_analysis/spec.md) | `entry.py` resolves the feature target; `wizard.py` owns target questions; `validation.py` checks the report target against the resolved input. [Input template](../scripts/okstra_ctl/phases/feature_analysis/report_assets/feature-analysis-input.template.md). |
|
|
434
|
+
| [change-impact-analysis](../scripts/okstra_ctl/phases/change_impact_analysis/spec.md) | `entry.py` collects feature evidence; `validation.py` limits planning inputs to constraints and unknowns. [Input template](../scripts/okstra_ctl/phases/change_impact_analysis/report_assets/change-impact-analysis-input.template.md). |
|
|
435
|
+
| [error-analysis](../scripts/okstra_ctl/phases/error_analysis/spec.md) | `validation.py` checks reproduction evidence and cause relationships. [Input template](../scripts/okstra_ctl/phases/error_analysis/report_assets/error-analysis-input.template.md). |
|
|
436
|
+
| [technical-verification](../scripts/okstra_ctl/phases/technical_verification/spec.md) | `entry.py` freezes experiment inputs; `validation.py` checks observed evidence against those inputs. |
|
|
437
|
+
| [implementation-option-selection](../scripts/okstra_ctl/phases/implementation_option_selection/spec.md) | `entry.py`, `validation.py`, `votes.py` and `comparison.py` own direction comparison, feasibility and ranking; `authoring.py` supplies report instructions. |
|
|
438
|
+
| [implementation-planning](../scripts/okstra_ctl/phases/implementation_planning/spec.md) | `entry.py`, `wizard.py`, `validation.py`, `plan_body.py` and `authoring.py` own selected-direction preparation and plan verification; `instructions/` contains plan-body guidance. [Input template](../scripts/okstra_ctl/phases/implementation_planning/report_assets/implementation-planning-input.template.md). |
|
|
439
|
+
| [implementation](../scripts/okstra_ctl/phases/implementation/spec.md) | `entry.py` claims and publishes a stage run; `wizard.py` owns stage selection; `validation.py` checks verifier independence; `instructions/` contains executor and verifier guidance. [Input template](../scripts/okstra_ctl/phases/implementation/report_assets/implementation-input.template.md). |
|
|
440
|
+
| [final-verification](../scripts/okstra_ctl/phases/final_verification/spec.md) | `entry.py`, `target.py`, `wizard.py` and `validation.py` own the prepared verification target, scope and acceptance checks. [Input template](../scripts/okstra_ctl/phases/final_verification/report_assets/final-verification-input.template.md). |
|
|
441
|
+
| [release-handoff](../scripts/okstra_ctl/phases/release_handoff/spec.md) | `entry.py`, `operations.py` and `wizard.py` own handoff input, eligibility, selected remote operations and delivery choices. [Input template](../scripts/okstra_ctl/phases/release_handoff/report_assets/release-handoff-input.template.md). |
|
|
442
|
+
|
|
443
|
+
`prompts/lead/phase-routing.md` owns the lead's continuation decisions. Common `next_phase.py`, release gates, verification evidence, stage state and selected-direction readers consume recorded facts without importing another phase's execution policy. CLI modules such as `option_votes.py`, `option_comparison.py` and `handoff.py` remain assembly entrypoints.
|
|
444
|
+
|
|
419
445
|
### 4.4 `scripts/okstra_project/`
|
|
420
446
|
|
|
421
447
|
Project resolver and read-only state helpers:
|
|
@@ -442,9 +468,7 @@ Token/cost accounting:
|
|
|
442
468
|
| `launch.template.md` | Lead prompt template rendered for each run |
|
|
443
469
|
| `duties/<duty>.json` | Canonical functional duty contracts composed into every Okstra-owned LLM invocation, alongside the common contract at `agents/common.json` and the role contract at `agents/roles/<role>.json`; `direction-selection-worker` owns direction comparison/validation while `planning-worker` realizes the selected direction; provider/model identity does not select the duty |
|
|
444
470
|
| `profiles/_common-contract.md` | Shared phase contract |
|
|
445
|
-
| `profiles
|
|
446
|
-
| `implementation-option-selection.md` | Read-only lifecycle profile for candidate comparison or preselected-direction validation before detailed planning |
|
|
447
|
-
| `project-analysis.md`, `feature-analysis.md`, `change-impact-analysis.md` | Read-only sidetrack profiles for project mapping, one-feature behavior tracing, and proposed-change impact mapping |
|
|
471
|
+
| `profiles/_*.md` | Shared include fragments; task profiles are canonical under `scripts/okstra_ctl/phases/<package>/profile.md`, never a translated mirror |
|
|
448
472
|
| `wizard/prompts.ko.json` | Korean wizard prompt single source of truth |
|
|
449
473
|
|
|
450
474
|
### 4.7 `templates/`
|
|
@@ -453,11 +477,11 @@ Token/cost accounting:
|
|
|
453
477
|
|---|---|
|
|
454
478
|
| `templates/reports/final-report-v2.template.md` | Full reading copy Markdown spine |
|
|
455
479
|
| `templates/reports/final-report-v2.template.md` | Schema v2 full reading copy Markdown spine |
|
|
456
|
-
| `templates/reports/md/
|
|
457
|
-
| `templates/reports/html/base.template.html`, `html/
|
|
480
|
+
| `templates/reports/md/macros/sections.md` | Shared Markdown sections; dedicated task bodies live in each phase's `report_assets/` |
|
|
481
|
+
| `templates/reports/html/base.template.html`, `html/macros/` | Shared HTML shell and macros; dedicated task templates live in each phase's `report_assets/` |
|
|
458
482
|
| `templates/reports/report.css`, `report.js` | Inline assets for self-contained HTML report views |
|
|
459
483
|
| `templates/reports/*.template.md` | Inputs, schedule, user-response, settings templates |
|
|
460
|
-
|
|
|
484
|
+
| Phase `report_assets/*-input.template.md` | Dedicated brief input templates for task types that provide one; common inputs remain under `templates/reports/` |
|
|
461
485
|
| `user-response.template.md`, `report.js` | Analysis Review sidecar block and the browser control that exports accept/revision/reject without changing the source report |
|
|
462
486
|
| `templates/project-docs/task-index.template.md` | Project task index template |
|
|
463
487
|
| `templates/worker-prompt-preamble.md` | Initial analysis audience procedure and output contract |
|
|
@@ -488,7 +512,6 @@ Optional (v1.0 backward-compatible) top-level keys:
|
|
|
488
512
|
| `validate_analysis_report.py` | Cross-field validation for the three read-only analysis reports: frozen target/evidence snapshots, current-code evidence, review-source identity, and exact affected-ID resolution coverage on revision reruns |
|
|
489
513
|
| `validate-schedule.py` | Schedule section/order/code validation |
|
|
490
514
|
| `validate-implementation-plan-stages.py` | enforces the Stage Map structure — checks the S1–S8 rules (`## 5.5 Stage Map` + `## 5.5.<i> Stage <i>` sections, ≤ 8 steps per stage, etc.) |
|
|
491
|
-
| `validate_improvement_report.py` | enforces the 11-item contract of the improvement-discovery final-report. Automatically invoked by `validate-run.py` when `task_type == "improvement-discovery"` |
|
|
492
515
|
| `detect_self_mock.py` | self-mock detector — runs BOTH gates and writes the run's sidecar. Gate A (static) scans the changed TEST files for SUT-stub signals (patterns imported from the SSOT `scripts/okstra_ctl/self_mock_signals.py`, never redefined here), matching each file as one whole-file string so multi-line signals are caught. Python strings and comments are token-masked without changing line positions before those regexes run, so examples in docstrings and comments do not become findings while executable `patch.object(self, ...)` and `sut._private` accesses remain detectable. Writes a `qa/self-mock[-stage-<N>].json` sidecar and prints `QA-RESULT: PASS|FAIL` as its last line (exit 0 = no hits, exit 1 = at least one hit). The sidecar records `scannedFiles`/`skippedFiles` so the gate can prove every changed test file was actually scanned (a run that skips them cannot pass on empty input). An optional `--waivers <path>` moves hits matching `(file,line,signal)` from `staticDetect.hits` to `staticDetect.waived` (each carrying the user's `reason`/`acknowledgedBy`) and records the file as `waiverSource`. Gate B (mutation) runs in the same call: `--changed-file` takes the stage's WHOLE changed set (each adapter selects its own production sources out of it), `--diff` and `--worktree` scope it, and `scripts/okstra_ctl/mutation_probe.py` writes the result into the sidecar's `mutation` block; the received set is recorded as `changedFiles` so the gate can prove gate B was not handed an empty input. `overall` and the exit code follow BOTH gates — a mutation FAIL with a clean static scan still exits 1. The same `--waivers` file feeds both (gate A reads its `signal` entries, gate B its `mutant` ones). Its verdict feeds the fail-closed `_validate_selfmock` gate in `validate-run.py` (implementation / final-verification): a diff that touches test files with no readable PASS sidecar blocks the run; a `waived` entry missing `reason`/`acknowledgedBy`, or a `waiverSource` that is not the task's own `qa/self-mock-waivers.json`, also blocks |
|
|
493
516
|
| `validate-workflow.sh` | End-to-end fixture workflow validation |
|
|
494
517
|
| `lib/*.sh` | Shared shell validator helpers and fixtures |
|
|
@@ -610,7 +633,7 @@ Current report pipeline:
|
|
|
610
633
|
3. Report-writer worker writes `worker-results/report-writer-narrative-<task-type>-<seq>.md`, including `humanSummary` and one task-type deliverable; Phase 7 later assembles the schema v3 report record.
|
|
611
634
|
4. For implementation-planning, `okstra plan-items extract` creates the complete `P-*` queue, `validate` proves it still matches data.json, and the analyser instances run the separate plan-body verification round.
|
|
612
635
|
5. Token usage substitution fills usage/cost cells in the report record. The full reading copy is rendered on demand with `okstra render-final-report` from `templates/reports/final-report-v2.template.md`.
|
|
613
|
-
6. `scripts/okstra-render-report-views.py` independently selects one of
|
|
636
|
+
6. `scripts/okstra-render-report-views.py` independently selects one of twelve dedicated task templates and emits human-facing HTML directly from the same data.json; run validation checks the record and the human HTML. A quick Markdown input retains its legacy conditional path.
|
|
614
637
|
|
|
615
638
|
For the three analysis sidetracks, the HTML view also exports an immutable-source `## ANALYSIS REVIEW` sidecar. A revision rerun carries that sidecar, reanalyzes the whole confirmed scope, and records one `analysisReviewResolution` row for every affected ID before `validate_analysis_report.py` accepts the result.
|
|
616
639
|
|
|
@@ -721,7 +744,7 @@ When changing code, keep these docs in sync:
|
|
|
721
744
|
- New runtime source copied to users: update `tools/build.mjs`, install/uninstall manifests if applicable, and this file.
|
|
722
745
|
- New skill/agent: update `README.md`, this file, install/uninstall fallback lists, and `CHANGES.md`.
|
|
723
746
|
- New report field/section: update schema, template, report-writer worker, validator tests, this file's report model if user-visible.
|
|
724
|
-
- New phase/profile behavior: update the phase directory under `scripts/okstra_ctl/phases/`
|
|
747
|
+
- New phase/profile behavior: update the phase directory under `scripts/okstra_ctl/phases/` and its `spec.md`, plus `docs/architecture.md`, `docs/cli.md`, and `README.md` if user-facing.
|
|
725
748
|
|
|
726
749
|
Edit English canonical Markdown sources directly; nothing asks you to touch the Korean mirror in the same change. A maintainer session reconciles the mirrors on its own schedule with `$sync-korean-sources` or `/sync-korean-sources`, which begins by reading `node tools/korean-sources/cli.mjs status`. `.project-docs/ko-sources/**` is maintainer-local only: it is neither published nor committed.
|
|
727
750
|
|
package/package.json
CHANGED
package/runtime/BUILD.json
CHANGED
|
@@ -97,7 +97,7 @@ options:
|
|
|
97
97
|
--lead-provider Compatibility assertion for the lead assignment. Must match the selected host adapter's native provider.
|
|
98
98
|
--lead-model Model for the host-native lead. Default: the selected provider's lead policy.
|
|
99
99
|
--claude-model Model for Claude worker. Default: OKSTRA_DEFAULT_CLAUDE_MODEL or opus
|
|
100
|
-
--codex-model Model for Codex worker. Default: OKSTRA_DEFAULT_CODEX_MODEL or gpt-6-sol
|
|
100
|
+
--codex-model Model for Codex worker. Default: OKSTRA_DEFAULT_CODEX_MODEL or gpt-6.1-sol
|
|
101
101
|
--antigravity-model Model for Antigravity worker. Default: OKSTRA_DEFAULT_ANTIGRAVITY_MODEL or gemini-3.1-pro
|
|
102
102
|
--worker-model Provider-qualified worker override CSV, e.g. grok=grok-4.7,kimi=kimi-k3.
|
|
103
103
|
--report-writer-provider
|
|
@@ -130,10 +130,10 @@ options:
|
|
|
130
130
|
-h, --help Show this help.
|
|
131
131
|
|
|
132
132
|
model defaults:
|
|
133
|
-
Host-native lead: provider policy (Claude default: opus; Codex default: gpt-6-sol)
|
|
133
|
+
Host-native lead: provider policy (Claude default: opus; Codex default: gpt-6.1-sol)
|
|
134
134
|
Report writer worker: selected provider policy (Claude default: sonnet)
|
|
135
135
|
Claude worker: OKSTRA_DEFAULT_CLAUDE_MODEL or opus
|
|
136
|
-
Codex worker: OKSTRA_DEFAULT_CODEX_MODEL or gpt-6-sol
|
|
136
|
+
Codex worker: OKSTRA_DEFAULT_CODEX_MODEL or gpt-6.1-sol
|
|
137
137
|
Antigravity worker: OKSTRA_DEFAULT_ANTIGRAVITY_MODEL or gemini-3.1-pro
|
|
138
138
|
Grok worker: grok-4.7
|
|
139
139
|
Kimi worker: kimi-k3
|
|
@@ -23,7 +23,7 @@ while IFS= read -r run_dir; do
|
|
|
23
23
|
[ -n "$run_dir" ] || continue
|
|
24
24
|
cat <<EOF
|
|
25
25
|
An okstra run is in progress for this project: ${run_dir}
|
|
26
|
-
For this run, the panes of dispatches that have finished are closed at every worker round/phase boundary and immediately before the lead asks the user for any approval, clarification, or decision.
|
|
26
|
+
For this run, the panes of dispatches that have finished are closed at every worker round/phase boundary and immediately before the lead asks the user for any approval, clarification, or decision. \`okstra team reclaim --project-root <PROJECT_ROOT> --run-manifest <RUN_MANIFEST>\` closes them and records \`phase-batch-cleanup panes=<n>\`; before a user gate add \`--gate\`. Emit the \`PROGRESS:\` line it prints. In-progress dispatches keep their panes. The completed workers' background tasks are then stopped with TaskStop; TaskStop alone idles the roster task and closes no pane, so it is not cleanup on its own.
|
|
27
27
|
EOF
|
|
28
28
|
done < <(python3 -m okstra_ctl.pane_reclaim --in-flight-run-dirs-for "$cwd" 2>/dev/null || true)
|
|
29
29
|
|
|
@@ -56,13 +56,13 @@ prefer_colocated_modules(__file__, "okstra_ctl/next_phase.py")
|
|
|
56
56
|
from okstra_ctl import next_phase # noqa: E402
|
|
57
57
|
from okstra_ctl.final_report_paths import final_report_markdown_path # noqa: E402
|
|
58
58
|
from okstra_ctl.paths import task_manifest_file # noqa: E402
|
|
59
|
-
from okstra_ctl.
|
|
59
|
+
from okstra_ctl.phases.catalog import task_types as phase_task_types # noqa: E402
|
|
60
60
|
from okstra_project.dirs import tasks_root # noqa: E402
|
|
61
61
|
|
|
62
62
|
|
|
63
63
|
SLUG_RE = re.compile(r"[^a-zA-Z0-9-]+")
|
|
64
64
|
|
|
65
|
-
ALLOWED_TASK_TYPES = set(
|
|
65
|
+
ALLOWED_TASK_TYPES = set(phase_task_types())
|
|
66
66
|
ALLOWED_ORIGINS = {
|
|
67
67
|
"phase-continuation",
|
|
68
68
|
"out-of-plan",
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"Compare feasible directions before planning in `candidate-comparison` mode, or validate one preselected direction in `preselected-validation` mode."
|
|
7
7
|
],
|
|
8
8
|
"requiredConduct": [
|
|
9
|
-
"In `candidate-comparison` mode, inspect the evidence needed to distinguish candidates, submit no more than three candidates, give each one a feasibility verdict (`feasible`, `not-feasible`, or `uncertain`) with a
|
|
9
|
+
"In `candidate-comparison` mode, inspect the evidence needed to distinguish candidates, submit no more than three candidates, give each one a feasibility verdict (`feasible`, `not-feasible`, or `uncertain`) with a rationale as long as the argument needs, each claim citing inspected evidence, state the strongest counterevidence for each one, and map every candidate to the stable brief end-state IDs it satisfies, preserves, or leaves unresolved. In `preselected-validation` mode, validate the one preselected direction against that evidence and mapping with the same verdict; the worker must not generate new candidates."
|
|
10
10
|
],
|
|
11
11
|
"decisionPrinciples": [
|
|
12
12
|
"Score candidates against the same stated criteria. Prefer evidence-backed feasibility over familiarity, and preserve a rejected candidate when its evidence or trade-off could affect the later planning decision."
|