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
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# release-handoff process
|
|
2
|
+
|
|
3
|
+
This directory owns the handoff preparation, stage selection, PR planning, remote reconciliation, and report presentation. Shared verification evidence stays in `okstra_ctl.handoff_verification`; verification recording and CLI assembly stay in `okstra_ctl.handoff`. Generic Git and stage lifecycle operations stay in their common modules.
|
|
4
|
+
|
|
5
|
+
Report shapes remain in `schemas/final-report-v2.0.schema.json` and `schemas/final-report-v3.0.schema.json`, under `releaseHandoff`. Routing remains in `prompts/lead/phase-routing.md`. The tests beside this specification exercise stage PR bases, origin reconciliation, checkout occupancy, conflict probes, and optional report fields. Common `tests/handoff/` tests cover verification recording and the prepare/CLI boundary.
|
|
6
|
+
|
|
7
|
+
## Guarantees
|
|
8
|
+
|
|
9
|
+
| ID | Guarantee | Enforcement |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| RH-1 | A PR carries a release-ready stage's recorded commit and dependency base | `scripts/okstra_ctl/phases/release_handoff/operations.py::pr_plan` |
|
|
12
|
+
| RH-2 | Diverged origin branches are rejected without force-pushing | `scripts/okstra_ctl/phases/release_handoff/tests/test_handoff_pr_plan.py::test_pr_plan_refuses_a_branch_it_cannot_deliver` |
|
|
13
|
+
| RH-3 | An actively reserved stage is not handed to the main worktree | `scripts/okstra_ctl/phases/release_handoff/tests/test_local_checkout_occupancy.py::test_an_active_stage_row_is_refused` |
|
|
14
|
+
| RH-4 | Missing optional report fields do not prevent rendering | `scripts/okstra_ctl/phases/release_handoff/tests/test_release_handoff_optional_keys.py::test_the_shape_a_skipped_run_writes_renders_end_to_end` |
|
|
15
|
+
|
|
16
|
+
## Index
|
|
17
|
+
|
|
18
|
+
- [1. Purpose](#1-purpose)
|
|
19
|
+
- [2. okstra-run wizard flow](#2-okstra-run-wizard-flow)
|
|
20
|
+
- [3. prepare stage](#3-prepare-stage)
|
|
21
|
+
- [4. entry gate](#4-entry-gate)
|
|
22
|
+
- [5. lead-only execution flow](#5-lead-only-execution-flow)
|
|
23
|
+
- [6. PR template resolution](#6-pr-template-resolution)
|
|
24
|
+
- [7. Deliverables](#7-deliverables)
|
|
25
|
+
- [8. Forbidden actions](#8-forbidden-actions)
|
|
26
|
+
- [9. Verified code](#9-verified-code)
|
|
27
|
+
|
|
28
|
+
## 1. Purpose
|
|
29
|
+
|
|
30
|
+
`release-handoff` is the terminal phase that pushes already-committed implementation stages with a release-ready verdict, or hands them off as pull requests. **One stage is one PR.** The PR head is that stage's stack branch; the base comes from its `depends-on` — the release base for a stage with no live dependency, the predecessor's branch for a stage with one (a stacked PR), and a branch merging the predecessors for a stage with several. The only commits this phase may create are the merge commits `okstra handoff pr-plan` makes on such a merge-base branch.
|
|
31
|
+
|
|
32
|
+
Because the PRs are a stack, they must be merged in ascending stage order with a merge commit or a rebase-merge. A squash replaces the commits the next PR's base points at, so the stack breaks — every PR body states this, and the lead never merges.
|
|
33
|
+
|
|
34
|
+
This phase has no worker dispatch. It does not use a provider or report-writer roster; the host-native Okstra lead performs git/gh inspection, user questions, the PR draft, and the final report inline.
|
|
35
|
+
|
|
36
|
+
## 2. okstra-run wizard flow
|
|
37
|
+
|
|
38
|
+
```mermaid
|
|
39
|
+
flowchart TD
|
|
40
|
+
Start[/okstra-run/] --> Common[common task identity flow]
|
|
41
|
+
Common --> Type[task-type = release-handoff]
|
|
42
|
+
Type --> Plan[approved plan auto/pick]
|
|
43
|
+
Plan --> Scope[handoff stage pick<br/>eligible stages, one PR each]
|
|
44
|
+
Scope --> Worktree{active task worktree?}
|
|
45
|
+
Worktree -->|yes| RoleCount[role-count min..max<br/>omit uses recommended; skip if min==max]
|
|
46
|
+
Worktree -->|no| BaseRef[base-ref pick/text]
|
|
47
|
+
BaseRef --> RoleCount
|
|
48
|
+
RoleCount --> RoleModel[role-model provider/model per slot]
|
|
49
|
+
RoleModel --> RoleAdd[min=0 roles via role-add only<br/>default skip]
|
|
50
|
+
RoleAdd --> Extras[directive, related tasks, clarification]
|
|
51
|
+
Extras --> Template[PR template override?]
|
|
52
|
+
Template --> TemplateScope[save template to project/global?]
|
|
53
|
+
TemplateScope --> Confirm[confirmation]
|
|
54
|
+
Confirm --> Render[render-bundle]
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`release-handoff` has no analysis-worker dispatch. Launch selection still shows any applicable role-count / role-model steps; current-session lead is this session and is listed on the confirmation summary. There is no provider roster multi-pick and no `Use defaults / Customize` fork. Dynamic verifiers are not chosen at launch. `--workers` is not a launch picker, and the runtime forces the worker list to empty. The wizard outcome's `renderArgs` includes `pr-template-path` only for release-handoff. Scope selection finishes before prepare, and the project/global save runs before `render-bundle` via the `config.set pr-template-path` action of `outcome.persistActions[]`. Only the stages that were marked `verified` by a release-ready verification in the Stage Lifecycle Snapshot and are not yet covered by a `pr` become candidates; leaving `--stages` empty takes all of them, and the wizard picker offers an all-stages option beside the individual ones. Both verification scopes mark a stage: a single-stage report marks its own stage, and a whole-task report marks every stage in its `stageReports` whose completed commit the verified head contains.
|
|
58
|
+
|
|
59
|
+
Note that this phase is also a target of task worktree provisioning. The normal flow reuses the implementation/final-verification result of the same task-key. Starting a new task may create a new branch, and it is likely to be blocked at the entry gate's "implementation commit exists" condition.
|
|
60
|
+
|
|
61
|
+
## 3. prepare stage
|
|
62
|
+
|
|
63
|
+
```mermaid
|
|
64
|
+
sequenceDiagram
|
|
65
|
+
participant W as okstra-run
|
|
66
|
+
participant P as prepare_task_bundle
|
|
67
|
+
participant T as PR template resolver
|
|
68
|
+
participant WT as worktree registry
|
|
69
|
+
participant FS as task artifacts
|
|
70
|
+
|
|
71
|
+
W->>P: task-type=release-handoff, approved-plan, stages csv, optional pr-template-path
|
|
72
|
+
P->>P: enforce stage eligibility (Stage Lifecycle Snapshot)
|
|
73
|
+
P->>FS: generate release-handoff-input.md (cited verification reports)
|
|
74
|
+
P->>P: force workers=[]
|
|
75
|
+
P->>T: resolve PR template
|
|
76
|
+
P->>WT: reuse or provision task worktree
|
|
77
|
+
P->>FS: write manifests with empty roster
|
|
78
|
+
P->>FS: expose PR_TEMPLATE_PATH and PR_TEMPLATE_SOURCE
|
|
79
|
+
P-->>W: lead prompt for current session
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The profile has no `Required workers:` block, and `run.py` also empties the worker override for `release-handoff`. So not going through the general TeamCreate / convergence / report-writer flow of `prompts/lead/okstra-lead-contract.md` is the intended behavior.
|
|
83
|
+
|
|
84
|
+
## 4. entry gate
|
|
85
|
+
|
|
86
|
+
```mermaid
|
|
87
|
+
flowchart TD
|
|
88
|
+
Brief[release-handoff-input.md<br/>generated by prepare] --> Source{Source Verification Report present?}
|
|
89
|
+
Source -->|no| Block[blocked<br/>route final-verification]
|
|
90
|
+
Source -->|yes| Verdict{Verdict Token == accepted?}
|
|
91
|
+
Verdict -->|no| Block
|
|
92
|
+
Verdict -->|yes| Eligible[each selected stage<br/>verified and not in PR]
|
|
93
|
+
Eligible --> Status{git status --short clean?}
|
|
94
|
+
Status -->|no| Dirty[blocked<br/>dirty tree]
|
|
95
|
+
Status -->|yes| Commits{each stage has commits<br/>over its own base?}
|
|
96
|
+
Commits -->|no| ImplBlock[blocked<br/>route implementation]
|
|
97
|
+
Commits -->|yes| Ready[handoff questions may begin]
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Before asking the user whether to push/PR, the lead confirms the following.
|
|
101
|
+
|
|
102
|
+
- The `## Source Verification Report` of the input document (`release-handoff-input.md`) generated by prepare lists the selected stages (`HANDOFF_STAGES`) and the cited report table. The brief is the input of the entry phase, so it does not exist in release-handoff — the user's stage selection finishes before prepare via the wizard `handoff_stage_pick` or the CLI `--stages` (empty takes every eligible stage).
|
|
103
|
+
- Each cited report must be the latest validated execution for the run it belongs to — the stage's own run for a single-stage report, the task's run for a whole-task one — and must match the recorded implementation commit. A newer unfinished, broken, or blocked execution prevents fallback to an older success. Prepare and `okstra handoff pr-plan` re-check this evidence. A new implementation start or completion invalidates the earlier approval.
|
|
104
|
+
- The working tree is clean.
|
|
105
|
+
- The current branch is recorded as evidence, not used as a PR head: every head comes from `okstra handoff pr-plan`. A release base branch such as `main`, `master`, `prod`, `preprod`, `staging`, or `dev` is never pushed.
|
|
106
|
+
- Each stage's `<base_commit>..<head_commit>` range is non-empty.
|
|
107
|
+
|
|
108
|
+
`accepted` is release-ready. `conditional-accept` is release-ready only when its non-empty condition list explicitly sets every `blocksReleaseHandoff` to `false`; those conditions remain in the generated input and PR body. `blocked`, missing conditions, and ambiguous verdicts stop delivery. `okstra_ctl.release_gate.release_handoff_allowed` owns this rule.
|
|
109
|
+
|
|
110
|
+
Verification targets are preserved per execution under the run's state directory. Old records without provable task/stage/commit evidence require re-verification; they are not rewritten. The checks are enforced by `okstra_ctl.handoff_verification`, `consumers.verified_accepted_stages`, and the handoff regression tests.
|
|
111
|
+
|
|
112
|
+
## 5. lead-only execution flow
|
|
113
|
+
|
|
114
|
+
```mermaid
|
|
115
|
+
stateDiagram-v2
|
|
116
|
+
[*] --> Gate: entry gate
|
|
117
|
+
Gate --> Q1: action selection
|
|
118
|
+
Q1 --> LocalCheckout: local checkout
|
|
119
|
+
Q1 --> Skip: skip
|
|
120
|
+
Q1 --> Q2: push + PR
|
|
121
|
+
state "okstra handoff pr-plan (head/base per stage)" as Plan
|
|
122
|
+
Q2 --> Plan: choose release base
|
|
123
|
+
Plan --> Probe: rows ready
|
|
124
|
+
Probe --> Q3: no conflict
|
|
125
|
+
Probe --> Conflict: conflict detected
|
|
126
|
+
Conflict --> Q2: change base branch
|
|
127
|
+
Conflict --> Q3: proceed anyway
|
|
128
|
+
Conflict --> Cancel: cancel
|
|
129
|
+
Q3 --> Push: use as-is or edit then proceed
|
|
130
|
+
Q3 --> Cancel: cancel
|
|
131
|
+
Push --> ReuseOrCreate: push each branch in stage order
|
|
132
|
+
ReuseOrCreate --> FinalReport: gh pr list / gh pr create per stage
|
|
133
|
+
LocalCheckout --> FinalReport
|
|
134
|
+
Skip --> FinalReport
|
|
135
|
+
Cancel --> FinalReport
|
|
136
|
+
FinalReport --> [*]
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
User interaction is exactly three steps.
|
|
140
|
+
|
|
141
|
+
1. Q1 action: `local checkout`, `push + PR`, `skip`
|
|
142
|
+
2. Q2 release base: a branch from the profile menu such as `staging`, `preprod`, `main`, or Enter directly
|
|
143
|
+
3. Q3 PR title/body: every stage's draft in one question — `use as-is`, `edit then proceed`, `cancel`
|
|
144
|
+
|
|
145
|
+
The merge-conflict probe happens only for `push + PR`, once per stage against that stage's own base.
|
|
146
|
+
|
|
147
|
+
`local checkout` takes one stage and hands that stage's branch to the main worktree; there is no whole-task target.
|
|
148
|
+
|
|
149
|
+
```mermaid
|
|
150
|
+
flowchart TD
|
|
151
|
+
PushPR[push + PR selected] --> Fetch[git fetch origin chosen-base]
|
|
152
|
+
Fetch --> MergeTree[git merge-tree --write-tree<br/>stage head vs its own PR base]
|
|
153
|
+
MergeTree --> Conflict{any stage conflicts?}
|
|
154
|
+
Conflict -->|no| Draft[show PR draft]
|
|
155
|
+
Conflict -->|yes| Ask[ask proceed/change base/cancel]
|
|
156
|
+
Ask -->|proceed anyway| Draft
|
|
157
|
+
Ask -->|change base branch| Base[return to Q2]
|
|
158
|
+
Ask -->|cancel| Report[final report without push/PR]
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
The probe must not change the working tree. `git merge`, `git rebase`, and `git pull` are not part of this probe.
|
|
162
|
+
|
|
163
|
+
## 6. PR template resolution
|
|
164
|
+
|
|
165
|
+
```mermaid
|
|
166
|
+
flowchart TD
|
|
167
|
+
Override[--pr-template-path from wizard] --> Chosen{exists?}
|
|
168
|
+
Chosen -->|yes| UseOverride[use override]
|
|
169
|
+
Chosen -->|no| Project[project config template]
|
|
170
|
+
Project -->|exists| UseProject[use project template]
|
|
171
|
+
Project -->|missing| Global[global config template]
|
|
172
|
+
Global -->|exists| UseGlobal[use global template]
|
|
173
|
+
Global -->|missing| Default[okstra skill default template]
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
When the user picks a template on the customize path, the okstra-run skill performs the project/global scope save before render-bundle. The runtime puts the resolved `PR_TEMPLATE_PATH` and `PR_TEMPLATE_SOURCE` into the run context, and the lead reads this file as-is, removes the HTML comments, and fills the placeholders. The section structure must not be hard-coded.
|
|
177
|
+
|
|
178
|
+
## 7. Deliverables
|
|
179
|
+
|
|
180
|
+
```mermaid
|
|
181
|
+
flowchart TD
|
|
182
|
+
Verdict[Source Verification Report<br/>accepted token] --> Report[release-handoff final report]
|
|
183
|
+
State[feature branch + clean status] --> Report
|
|
184
|
+
User[Q1/Q2/Q2b/Q3 user selections] --> Report
|
|
185
|
+
Commands[git/gh commands + exit codes] --> Report
|
|
186
|
+
Commits[git log base..HEAD commit list] --> Report
|
|
187
|
+
Probe[Merge Conflict Probe] --> Report
|
|
188
|
+
PR[one PR row per stage:<br/>created / reused / skipped] --> Report
|
|
189
|
+
Report --> Done[routing recommendation: done]
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
The final report requires at least the following.
|
|
193
|
+
|
|
194
|
+
- per selected stage, the originating final-verification report path and its quoted verdict row
|
|
195
|
+
- the selected stages and the chosen release base
|
|
196
|
+
- the pr-plan rows: stage, head branch, base kind, base branch — the merge order of the stack
|
|
197
|
+
- the run's current branch and run start `git status --short`
|
|
198
|
+
- record of user selections
|
|
199
|
+
- all executed git/gh commands and exit codes
|
|
200
|
+
- the implementation commit list, attributed per stage
|
|
201
|
+
- merge-conflict probe result
|
|
202
|
+
- one PR outcome row per stage: created, reused, or skipped
|
|
203
|
+
- routing recommendation `done`
|
|
204
|
+
|
|
205
|
+
## 8. Forbidden actions
|
|
206
|
+
|
|
207
|
+
```mermaid
|
|
208
|
+
flowchart TD
|
|
209
|
+
RH[release-handoff] --> Allowed[read git/gh, fetch base, merge-tree probe,<br/>push feature branch, create/reuse PR]
|
|
210
|
+
RH -. forbidden .-> Commit[git add / commit / stash]
|
|
211
|
+
RH -. forbidden .-> Force[force push or +refspec]
|
|
212
|
+
RH -. forbidden .-> BasePush[push directly to a release base branch]
|
|
213
|
+
RH -. forbidden .-> NoVerify[--no-verify / -n]
|
|
214
|
+
RH -. forbidden .-> Publish[release publish / deploy]
|
|
215
|
+
RH -. forbidden .-> Edit[source edit]
|
|
216
|
+
RH -. forbidden .-> Team[TeamCreate or Agent dispatch]
|
|
217
|
+
RH -. forbidden .-> Merge[gh pr merge or squash-merge]
|
|
218
|
+
RH -. forbidden .-> Rewrite[rebase / amend / cherry-pick a stage branch]
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
A failed `git push` must not be retried with weaker safeguards. When a failure such as non-fast-forward occurs, stop and take the user's instruction, and `--force`-family flags are forbidden even if the user requests them.
|
|
222
|
+
|
|
223
|
+
## 9. Verified code
|
|
224
|
+
|
|
225
|
+
- [`profile.md`](profile.md)
|
|
226
|
+
- [`report_assets/release-handoff-input.template.md`](report_assets/release-handoff-input.template.md)
|
|
227
|
+
- [`skills/okstra-run/SKILL.md`](../../../../skills/okstra-run/SKILL.md)
|
|
228
|
+
- [`scripts/okstra_ctl/wizard/`](../../../../scripts/okstra_ctl/wizard/)
|
|
229
|
+
- [`scripts/okstra_ctl/run.py`](../../../../scripts/okstra_ctl/run.py)
|
|
230
|
+
- [`scripts/okstra_ctl/pr_template.py`](../../../../scripts/okstra_ctl/pr_template.py)
|
|
231
|
+
- [`src/commands/lifecycle/config.mts`](../../../../src/commands/lifecycle/config.mts)
|
|
232
|
+
- [`scripts/okstra_ctl/handoff.py`](../../../../scripts/okstra_ctl/handoff.py)
|
|
233
|
+
- [`scripts/okstra_ctl/worktree/`](../../../../scripts/okstra_ctl/worktree/)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""검증된 단계의 전달 선택과 PR 템플릿 저장 요청."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import TYPE_CHECKING, Callable, Optional
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from okstra_ctl.wizard.state import Prompt, WizardState
|
|
8
|
+
|
|
9
|
+
ALL_ELIGIBLE_STAGES = "all"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _handoff_msgs(state: WizardState) -> dict:
|
|
13
|
+
"""handoff_stage_pick 의 JSON 텍스트 묶음 (label 미사용 조회용)."""
|
|
14
|
+
from okstra_ctl.wizard.prompts import _p
|
|
15
|
+
|
|
16
|
+
return _p(state.workspace_root, "handoff_stage_pick", blocked="")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def build_handoff_stage_pick(state: WizardState, eligibility: list) -> Prompt:
|
|
20
|
+
from okstra_ctl.wizard.ids import S_HANDOFF_STAGE_PICK
|
|
21
|
+
from okstra_ctl.wizard.state import Option, Prompt, WizardError
|
|
22
|
+
from okstra_ctl.wizard.prompts import _opt, _p
|
|
23
|
+
|
|
24
|
+
elig = eligibility
|
|
25
|
+
eligible = [e for e in elig if e["eligible"]]
|
|
26
|
+
blocked = [e for e in elig if not e["eligible"]]
|
|
27
|
+
msgs = _handoff_msgs(state)
|
|
28
|
+
blocked_summary = ("; ".join(
|
|
29
|
+
f"stage {e['stage']} ({', '.join(e['reasons'])})" for e in blocked)
|
|
30
|
+
or msgs["labels"]["blocked_none"])
|
|
31
|
+
if not eligible:
|
|
32
|
+
raise WizardError(
|
|
33
|
+
msgs["errors"]["nothing_eligible"].format(blocked=blocked_summary))
|
|
34
|
+
t = _p(state.workspace_root, "handoff_stage_pick", blocked=blocked_summary)
|
|
35
|
+
stage_label = t["labels"]["stage"]
|
|
36
|
+
options: list[Option] = []
|
|
37
|
+
if len(eligible) > 1:
|
|
38
|
+
options.append(_opt(ALL_ELIGIBLE_STAGES, t["labels"]["all_stages"].format(
|
|
39
|
+
stages=", ".join(str(e["stage"]) for e in eligible))))
|
|
40
|
+
for e in eligible:
|
|
41
|
+
deps = ", ".join(str(d) for d in e["depends_on"]) or "-"
|
|
42
|
+
options.append(_opt(str(e["stage"]),
|
|
43
|
+
stage_label.format(stage=e["stage"], deps=deps)))
|
|
44
|
+
return Prompt(
|
|
45
|
+
step=S_HANDOFF_STAGE_PICK, kind="pick", multi=True,
|
|
46
|
+
label=t["label"], options=options,
|
|
47
|
+
echo_template=t["echo_template"],
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def submit_handoff_stage_pick(state: WizardState, value: str, eligibility: Callable[[], list]) -> Optional[str]:
|
|
52
|
+
from okstra_ctl.wizard.state import WizardError
|
|
53
|
+
|
|
54
|
+
t = _handoff_msgs(state)
|
|
55
|
+
picks = [v.strip() for v in (value or "").split(",") if v.strip()]
|
|
56
|
+
if not picks:
|
|
57
|
+
raise WizardError(t["errors"]["none_selected"])
|
|
58
|
+
eligible = {str(e["stage"]) for e in eligibility()
|
|
59
|
+
if e["eligible"]}
|
|
60
|
+
if ALL_ELIGIBLE_STAGES in picks:
|
|
61
|
+
picks = sorted(eligible, key=int)
|
|
62
|
+
bad = [p for p in picks if p not in eligible]
|
|
63
|
+
if bad:
|
|
64
|
+
raise WizardError(t["errors"]["not_eligible"].format(
|
|
65
|
+
bad=", ".join(bad), eligible=", ".join(sorted(eligible))))
|
|
66
|
+
nums = sorted({int(p) for p in picks})
|
|
67
|
+
state.handoff_stages = ",".join(str(n) for n in nums)
|
|
68
|
+
return t["echo_variants"]["stages"].format(stages=state.handoff_stages)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def pr_template_persist_actions(state: WizardState) -> list[dict[str, str]]:
|
|
73
|
+
if not state.pr_template_path:
|
|
74
|
+
return []
|
|
75
|
+
if state.pr_template_scope not in ("project", "global"):
|
|
76
|
+
return []
|
|
77
|
+
return [
|
|
78
|
+
{
|
|
79
|
+
"command": "config.set",
|
|
80
|
+
"key": "pr-template-path",
|
|
81
|
+
"scope": state.pr_template_scope,
|
|
82
|
+
"value": state.pr_template_path,
|
|
83
|
+
}
|
|
84
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""요구사항 확인과 작업 분해 단계의 정책."""
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"allowed": " - work-category classification (bugfix / feature / refactor / ops / improvement)\n - routing decision as the `routing` object `{nextTaskType, readyWhen, rationale}`: `nextTaskType` is `error-analysis` or `implementation-option-selection` and nothing else — this phase never hands off directly to planning or implementation. Prose alone does not route the task — Phase 7 projects `workflow.nextRecommendedPhase` from `nextTaskType`\n - missing-input list and clarification requests\n - approval / confirmation checkpoints recorded for the next phase\n - one endStateCoverage row per brief end-state id (this phase authors no goal of its own)",
|
|
3
|
+
"forbidden": [
|
|
4
|
+
"source code edits of any kind",
|
|
5
|
+
"implementation planning or detailed design beyond what is required to choose the next phase",
|
|
6
|
+
"executing builds, migrations, deployments, or any state-mutating command",
|
|
7
|
+
"starting `error-analysis`, `implementation-planning`, or `implementation` inside this run (each must be a separate run, and `implementation` additionally requires an approved `implementation-planning` deliverable)"
|
|
8
|
+
]
|
|
9
|
+
}
|
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
- state the reporter's rejection criteria, missing routing inputs, and the evidence boundary behind each recommendation
|
|
25
25
|
- Primary focus areas:
|
|
26
26
|
- classify the work as bugfix, feature, improvement, refactor, or ops
|
|
27
|
-
- determine whether `error-analysis` or `implementation-option-selection` is the next safe step. Direct `implementation-planning` or `implementation` handoff is never a valid routing target — implementation requires direction selection followed by an approved `implementation-planning` report
|
|
28
27
|
- capture the reporter's **rejection criteria** — the delivered outcome that would make this work wrong or unacceptable — as a routing input. Consume it from the brief's `Desired Outcome` / `Out of Scope` / `Source Material` when present; when it is absent AND it would change the classification (e.g. bugfix vs feature) or the next-phase choice, raise it as one `decision` clarification row with `Evidence checked: none — reporter intent`. Never infer it — this is a reporter-intent signal, the mirror of improvement-discovery's `Anti-goals`
|
|
29
28
|
- record the rejection criteria in `requirementsDiscovery.rejectionCriteria` with the
|
|
30
29
|
`source` that produced it. When it was absent and would not have changed the
|
|
@@ -41,11 +40,11 @@
|
|
|
41
40
|
- A single-item / single-domain request is not fanned out (preserving the current single-routing behaviour).
|
|
42
41
|
- When a request spans two or more domains, or has two or more independently-startable work items,
|
|
43
42
|
publish each item as a `runs/requirements-discovery/fan-out/unit-<NNN>.md` packet.
|
|
44
|
-
The packet follows the `
|
|
43
|
+
The packet follows the `scripts/okstra_ctl/phases/requirements_discovery/report_assets/fan-out-unit.template.md` format, and its frontmatter
|
|
45
44
|
`domain`(work-category 5-enum: bugfix / feature / refactor / ops / improvement),
|
|
46
45
|
`depends-on`(an inline list of unit-ids within the same fan-out `[unit-001]`, or `[]` if none),
|
|
47
46
|
`recommended-next-phase`(error-analysis | implementation-option-selection) are filled in.
|
|
48
|
-
Each packet MUST carry a non-empty `## Requirement Provenance` section whose every bullet is `brief:EB-001` / `brief:PB-001` / `brief:EO-001` — an end-state id the brief declares — or `contract:<rule>`. When the brief pins ids, citing a heading is rejected: every brief carries the same generic headings, so a heading cannot say WHICH reporter line demanded this unit, and a fan-out unit becomes the brief for a whole downstream task. Only a brief authored before the end-state sections existed still takes the older `brief:<heading>` form, and there the heading must literally exist in it. `derived:` is not admissible in a packet — cross-packet derivation cannot be resolved from a single packet, so each unit anchors directly on the brief. A unit you cannot source that way is not a work item: raise it as a clarification row instead of publishing a packet for it. **Enforced:** `
|
|
47
|
+
Each packet MUST carry a non-empty `## Requirement Provenance` section whose every bullet is `brief:EB-001` / `brief:PB-001` / `brief:EO-001` — an end-state id the brief declares — or `contract:<rule>`. When the brief pins ids, citing a heading is rejected: every brief carries the same generic headings, so a heading cannot say WHICH reporter line demanded this unit, and a fan-out unit becomes the brief for a whole downstream task. Only a brief authored before the end-state sections existed still takes the older `brief:<heading>` form, and there the heading must literally exist in it. `derived:` is not admissible in a packet — cross-packet derivation cannot be resolved from a single packet, so each unit anchors directly on the brief. A unit you cannot source that way is not a work item: raise it as a clarification row instead of publishing a packet for it. **Enforced:** `scripts/okstra_ctl/phases/requirements_discovery/validation.py` `_check_provenance`.
|
|
49
48
|
- in `runs/requirements-discovery/fan-out/index.md`, list the packets in depends-on topological order
|
|
50
49
|
as a numbered list (`1. unit-001`) (a generated view; explicitly do not hand-edit). The depends-on graph
|
|
51
50
|
must be a DAG — `validate_fanout` rejects a cycle as a validation failure, so if a cycle appears,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"""Human-first requirements-discovery view model."""
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
|
-
from
|
|
5
|
-
from
|
|
6
|
-
from
|
|
4
|
+
from okstra_ctl.report_html.common import evidence_index
|
|
5
|
+
from okstra_ctl.report_html.models import HumanReportView, VisualEdge, VisualNode
|
|
6
|
+
from okstra_ctl.report_html.visualizations import decision_flow_figure
|
|
7
7
|
|
|
8
8
|
# Record fields this template anchors as `id-<row id>` (see
|
|
9
9
|
# `HumanReportView.anchored_fields`); ids elsewhere land in the ledger.
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# requirements-discovery process
|
|
2
|
+
|
|
3
|
+
## Guarantees
|
|
4
|
+
|
|
5
|
+
| ID | Guarantee | Enforcement |
|
|
6
|
+
|---|---|---|
|
|
7
|
+
| RD-1 | Optional fan-out absence is accepted | `scripts/okstra_ctl/phases/requirements_discovery/validation.py::validate_fanout` |
|
|
8
|
+
| RD-2 | Each packet cites an admissible brief or contract source | `scripts/okstra_ctl/phases/requirements_discovery/validation.py::_check_provenance` |
|
|
9
|
+
| RD-3 | Dependency cycles and unknown units are rejected | `scripts/okstra_ctl/phases/requirements_discovery/fanout.py::topological_order` |
|
|
10
|
+
| RD-4 | The index lists every packet in dependency order | `scripts/okstra_ctl/phases/requirements_discovery/validation.py::validate_fanout` |
|
|
11
|
+
| RD-5 | Packet destinations use the common routing contract | `scripts/okstra_ctl/report_routing.py::fanout_routing_errors` |
|
|
12
|
+
| RD-6 | Human intent and terminology are resolved from inspected evidence | unenforced — worker instructions and lead review; no generic validator proves intent semantics |
|
|
13
|
+
|
|
14
|
+
## Index
|
|
15
|
+
|
|
16
|
+
- [1. Purpose](#1-purpose)
|
|
17
|
+
- [2. okstra-run wizard flow](#2-okstra-run-wizard-flow)
|
|
18
|
+
- [3. prepare_task_bundle handling](#3-prepare_task_bundle-handling)
|
|
19
|
+
- [4. lead execution flow](#4-lead-execution-flow)
|
|
20
|
+
- [5. Deliverables and routing](#5-deliverables-and-routing)
|
|
21
|
+
- [6. Code reviewed](#6-code-reviewed)
|
|
22
|
+
|
|
23
|
+
## 1. Purpose
|
|
24
|
+
|
|
25
|
+
`requirements-discovery` classifies the request before implementation. It determines which of bugfix, feature, improvement, refactor, or ops it is, and chooses whether the next safe phase is `error-analysis` or `implementation-option-selection`. Going directly to planning or implementation is not valid for a new direction. Implementation can only start once a selected direction has been expanded into a separately approved `implementation-planning` report.
|
|
26
|
+
|
|
27
|
+
## 2. okstra-run wizard flow
|
|
28
|
+
|
|
29
|
+
```mermaid
|
|
30
|
+
flowchart TD
|
|
31
|
+
Start[/okstra-run/] --> Check[ensure-installed / paths / check-project]
|
|
32
|
+
Check --> Pick{new task or existing task?}
|
|
33
|
+
Pick -->|new| Brief[brief path]
|
|
34
|
+
Brief --> Suggest{brief frontmatter suggestions?}
|
|
35
|
+
Suggest -->|yes| GroupPick[task-group pick]
|
|
36
|
+
Suggest -->|no| GroupText[task-group text]
|
|
37
|
+
GroupPick --> Id
|
|
38
|
+
GroupText --> Id
|
|
39
|
+
Id[task-id pick/text] --> Type[task-type = requirements-discovery]
|
|
40
|
+
Pick -->|existing| Type
|
|
41
|
+
Type --> Keep{existing brief?}
|
|
42
|
+
Keep -->|keep| Base
|
|
43
|
+
Keep -->|change/no brief| Brief
|
|
44
|
+
Type --> Base{active task worktree?}
|
|
45
|
+
Base -->|yes| RoleCount[role-count min..max<br/>omit uses recommended; skip if min==max]
|
|
46
|
+
Base -->|no| BaseRef[base-ref pick/text]
|
|
47
|
+
BaseRef --> RoleCount
|
|
48
|
+
RoleCount --> RoleModel[role-model provider/model per slot]
|
|
49
|
+
RoleModel --> RoleAdd[min=0 roles via role-add only<br/>default skip]
|
|
50
|
+
RoleAdd --> Extras[directive, related tasks, clarification]
|
|
51
|
+
Extras --> Confirm
|
|
52
|
+
Confirm --> Render[render-bundle]
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Launch selection uses role slots and model refs only: current-session lead is this session (listed on the confirmation summary), then each static role's count in `min..max` (default **recommended**; the count step is skipped when `min == max`), then one `provider/model` per slot. Roles with `min = 0` stay closed unless the user opens them with role-add (default skip). Duplicate model refs in the same role are rejected. There is no provider roster multi-pick and no `Use defaults / Customize` fork. Dynamic verifiers are not chosen at launch. `--workers` is a CLI compatibility input only, not a launch picker.
|
|
56
|
+
|
|
57
|
+
## 3. prepare_task_bundle handling
|
|
58
|
+
|
|
59
|
+
```mermaid
|
|
60
|
+
sequenceDiagram
|
|
61
|
+
participant W as wizard/render-bundle
|
|
62
|
+
participant P as prepare_task_bundle
|
|
63
|
+
participant Prof as requirements-discovery.md
|
|
64
|
+
participant Git as worktree registry
|
|
65
|
+
participant FS as task artifacts
|
|
66
|
+
|
|
67
|
+
W->>P: task-type=requirements-discovery, brief, base-ref, workers
|
|
68
|
+
P->>Prof: profile exists, Required workers parsed
|
|
69
|
+
P->>P: verify installation, upsert project.json
|
|
70
|
+
P->>P: resolve workers from profile + override
|
|
71
|
+
P->>Git: create or reuse task worktree
|
|
72
|
+
P->>P: expand _common-contract include
|
|
73
|
+
P->>FS: write instruction-set and manifests
|
|
74
|
+
P->>FS: render workflow currentPhase=requirements-discovery
|
|
75
|
+
P-->>W: prepared lead prompt
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
There is no additional hard gate in the runtime for this phase alone. The important gates are: the profile file exists, the brief file exists, the worktree gate requiring base-ref to be resolvable at the first phase, and the gate requiring worker overrides to stay within the profile roster range.
|
|
79
|
+
|
|
80
|
+
## 4. lead execution flow
|
|
81
|
+
|
|
82
|
+
```mermaid
|
|
83
|
+
flowchart TD
|
|
84
|
+
P1[Phase 1 intake<br/>manifest, brief, profile, run manifest, team-state] --> P2[Phase 2 prompts]
|
|
85
|
+
P2 --> P3[Phase 3 TeamCreate]
|
|
86
|
+
P3 --> P4[Phase 4/5 dispatch analysers<br/>claude/codex + optional antigravity]
|
|
87
|
+
P4 --> C[Phase 5.5 convergence<br/>default maxRounds = 1]
|
|
88
|
+
C --> R[Phase 6 report-writer authors final report]
|
|
89
|
+
R --> P7[Phase 7 token usage, validate, persist]
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`requirements-discovery` has a convergence default of 1 round. This exception is stated in both `render._build_convergence_block()` and `prompts/lead/okstra-lead-contract.md`.
|
|
93
|
+
|
|
94
|
+
## 5. Deliverables and routing
|
|
95
|
+
|
|
96
|
+
```mermaid
|
|
97
|
+
flowchart LR
|
|
98
|
+
RD[requirements-discovery final report] --> Class[work-category classification]
|
|
99
|
+
RD --> Missing[missing materials / clarification items]
|
|
100
|
+
RD --> Domain[Domain Alignment<br/>terminology resolution]
|
|
101
|
+
RD --> Route{next safe phase}
|
|
102
|
+
Route --> EA[error-analysis]
|
|
103
|
+
Route --> IOS[implementation-option-selection]
|
|
104
|
+
Route -. invalid .-> Impl[implementation<br/>not allowed directly]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The final report emphasizes the following in particular.
|
|
108
|
+
|
|
109
|
+
- evidence-backed routing decision
|
|
110
|
+
- missing input and uncertainty boundary
|
|
111
|
+
- the next phase and safe resume guidance
|
|
112
|
+
- canonical term resolution for `terminology:*` brief items
|
|
113
|
+
- if there is blocking input, `Blocks=next-phase` in the `## 1. Clarification Items` unified table
|
|
114
|
+
|
|
115
|
+
Non-goals are source edit, plan authoring, build, and deployment.
|
|
116
|
+
|
|
117
|
+
## 6. Code reviewed
|
|
118
|
+
|
|
119
|
+
- [`skills/okstra-run/SKILL.md`](../../../../skills/okstra-run/SKILL.md)
|
|
120
|
+
- [`scripts/okstra_ctl/wizard/`](../../wizard)
|
|
121
|
+
- [`scripts/okstra_ctl/run.py`](../../run.py)
|
|
122
|
+
- [`scripts/okstra_ctl/workflow.py`](../../workflow.py)
|
|
123
|
+
- [`scripts/okstra_ctl/phases/requirements_discovery/profile.md`](profile.md)
|
|
124
|
+
- [`prompts/lead/okstra-lead-contract.md`](../../../../prompts/lead/okstra-lead-contract.md)
|
|
125
|
+
|
|
126
|
+
## Phase ownership and validation
|
|
127
|
+
|
|
128
|
+
`profile.md` owns request discovery and decomposition instructions; `profile.json` owns roles. `validation.py` owns fan-out packet identity, work category, requirement provenance, dependency and index checks. `fanout.py` orders dependencies and rejects cycles and unknown units. `report.py` and `report_assets/` own the report body and fan-out packet template.
|
|
129
|
+
|
|
130
|
+
Common scope-provenance helpers continue to define brief end-state identifiers and citation grammar. Shared schemas remain in `schemas/final-report-v2.0.schema.json` and `schemas/final-report-v3.0.schema.json` under `requirementsDiscovery`. The common lead's `prompts/lead/phase-routing.md` owns destination selection; `report_routing.py` checks packet destinations.
|
|
131
|
+
|
|
132
|
+
`tests/test_fanout.py` checks real packet files, missing and invalid provenance, dependency cycles, missing dependencies and index order. The common validator calls `validate_requirements_discovery_fanout` only for this task type, preserving the optional fan-out behavior and the `requirements-discovery:` error prefix. Source inspection and human-intent decisions remain worker instructions rather than machine-enforced semantic claims.
|
|
@@ -6,25 +6,19 @@ and a `fan-out/` directory exists under the run dir.
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
8
|
import re
|
|
9
|
-
import sys
|
|
10
9
|
from dataclasses import dataclass, field
|
|
11
10
|
from pathlib import Path
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
from okstra_ctl.work_categories import WORK_CATEGORIES # noqa: E402
|
|
19
|
-
from okstra_ctl.fanout import topological_order, CycleError # noqa: E402
|
|
20
|
-
from okstra_ctl.scope_provenance import ( # noqa: E402
|
|
12
|
+
from okstra_ctl.report_routing import fanout_routing_errors
|
|
13
|
+
from okstra_ctl.work_categories import WORK_CATEGORIES
|
|
14
|
+
from .fanout import topological_order, CycleError
|
|
15
|
+
from okstra_ctl.scope_provenance import (
|
|
21
16
|
brief_citation_problem,
|
|
22
17
|
brief_end_state_ids,
|
|
23
18
|
brief_headings,
|
|
24
19
|
parse_source,
|
|
25
20
|
)
|
|
26
21
|
|
|
27
|
-
_NEXT_PHASES = ("error-analysis", "implementation-planning")
|
|
28
22
|
_UNIT_RE = re.compile(r"unit-\d{3}")
|
|
29
23
|
# index.md 번호목록 항목에서만 unit-NNN 을 추출 — 내러티브 문장 중복 방지
|
|
30
24
|
_INDEX_ENTRY_RE = re.compile(r"^\s*\d+\.\s+(unit-\d{3})\b", re.MULTILINE)
|
|
@@ -138,8 +132,7 @@ def validate_fanout(run_dir: Path, brief_path: Path | None = None) -> Validation
|
|
|
138
132
|
errors.append(f"{pkt.name}: unit-id {uid!r} != filename stem {pkt.stem!r}")
|
|
139
133
|
if fm.get("domain") not in WORK_CATEGORIES:
|
|
140
134
|
errors.append(f"{pkt.name}: domain {fm.get('domain')!r} not in {WORK_CATEGORIES}")
|
|
141
|
-
|
|
142
|
-
errors.append(f"{pkt.name}: recommended-next-phase not in {_NEXT_PHASES}")
|
|
135
|
+
errors.extend(fanout_routing_errors(pkt.name, fm.get("recommended-next-phase")))
|
|
143
136
|
units[pkt.stem] = _parse_deps(fm.get("depends-on", ""))
|
|
144
137
|
|
|
145
138
|
if not units:
|
|
@@ -167,3 +160,9 @@ def validate_fanout(run_dir: Path, brief_path: Path | None = None) -> Validation
|
|
|
167
160
|
errors.append(f"index.md order {listed} is not the topological order {order}")
|
|
168
161
|
|
|
169
162
|
return ValidationResult(ok=not errors, errors=errors)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def validate_requirements_discovery_fanout(run_dir, failures, brief_path=None) -> None:
|
|
166
|
+
"""단계 산출물 오류를 공통 실행 검증의 오류 목록에 같은 접두로 전달한다."""
|
|
167
|
+
result = validate_fanout(Path(run_dir), brief_path)
|
|
168
|
+
failures.extend(f"requirements-discovery: {error}" for error in result.errors)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""기술 검증 단계의 입력과 관측 증거 정책."""
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"allowed": " - falsifiable experiment plans for the frozen unresolved facts\n - dependency installation, source experiments, tests and builds only in this run's experiment copies\n - command logs, observed signals and per-fact supported/refuted/inconclusive/not-run results\n - return to implementation-option-selection with evidence, without adoption or plan approval",
|
|
3
|
+
"forbidden": [
|
|
4
|
+
"source edits or installs in the project checkout, task worktree, or another worker's experiment copy",
|
|
5
|
+
"production credentials, remote writes, deployments, migrations, publishing, commits or merging experiments into product branches",
|
|
6
|
+
"marking candidates feasible, selecting a direction, approving a plan, or declaring task acceptance",
|
|
7
|
+
"starting another lifecycle phase inside this run; return the evidence to implementation-option-selection"
|
|
8
|
+
]
|
|
9
|
+
}
|