okstra 0.205.1 → 0.206.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/commands/lifecycle/install.mjs +2 -1
- package/dist/commands/lifecycle/install.mjs.map +1 -1
- package/docs/architecture.md +16 -16
- package/docs/cli.md +4 -4
- package/docs/contributor-change-matrix.md +3 -2
- package/docs/performance-improvement-plan-v2.md +1 -1
- package/docs/project-structure-overview.md +45 -21
- package/package.json +2 -3
- package/runtime/BUILD.json +2 -2
- package/runtime/bin/okstra-spawn-followups.py +2 -2
- package/runtime/prompts/launch.template.md +1 -1
- package/runtime/prompts/lead/context-loader.md +1 -1
- package/runtime/prompts/lead/convergence.md +3 -3
- package/runtime/prompts/lead/okstra-lead-contract.md +14 -55
- package/runtime/prompts/lead/phase-routing.md +82 -0
- package/runtime/prompts/lead/report-writer.md +2 -2
- package/runtime/prompts/lead/team-contract.md +1 -1
- package/runtime/prompts/profiles/_coding-conventions-preflight.md +1 -1
- package/runtime/prompts/profiles/_common-contract.md +1 -1
- package/runtime/prompts/profiles/_coverage-critic.md +1 -1
- package/runtime/prompts/profiles/forbidden-actions.json +0 -94
- package/runtime/python/okstra_ctl/agent/prompt_cli/corrections.py +1 -1
- 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/asset_roots.py +19 -0
- package/runtime/python/okstra_ctl/consumers.py +12 -0
- package/runtime/python/okstra_ctl/contract_graph.py +75 -10
- package/runtime/python/okstra_ctl/dispatch_state.py +22 -0
- package/runtime/python/okstra_ctl/doctor.py +15 -4
- package/runtime/python/okstra_ctl/execution_mutation_audit.py +27 -1
- 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 +9 -485
- package/runtime/python/okstra_ctl/initial_prompt_materialization.py +8 -1
- package/runtime/python/okstra_ctl/next_phase.py +2 -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 +22 -6
- package/runtime/python/okstra_ctl/phases/__init__.py +4 -0
- package/runtime/python/okstra_ctl/phases/catalog.py +260 -0
- 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/{docs/task-process/error-analysis.md → runtime/python/okstra_ctl/phases/error_analysis/spec.md} +22 -7
- 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/__init__.py +4 -0
- package/runtime/python/okstra_ctl/phases/final_verification/boundary.json +8 -0
- package/runtime/python/okstra_ctl/phases/final_verification/entry.py +166 -0
- package/runtime/{prompts/profiles/final-verification.md → python/okstra_ctl/phases/final_verification/profile.md} +5 -5
- package/runtime/python/okstra_ctl/{report_html/view_models/final_verification.py → phases/final_verification/report.py} +12 -3
- package/runtime/{templates/reports → python/okstra_ctl/phases/final_verification/report_assets}/final-verification-input.template.md +1 -1
- package/{docs/task-process/final-verification.md → runtime/python/okstra_ctl/phases/final_verification/spec.md} +42 -25
- package/runtime/python/okstra_ctl/phases/final_verification/target.py +296 -0
- package/runtime/python/okstra_ctl/phases/final_verification/validation.py +190 -0
- package/runtime/python/okstra_ctl/phases/final_verification/wizard.py +38 -0
- 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 +4 -4
- 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/{docs/task-process/implementation.md → runtime/python/okstra_ctl/phases/implementation/spec.md} +20 -8
- 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} +2 -2
- package/runtime/python/okstra_ctl/{report_html/view_models/implementation_option_selection.py → phases/implementation_option_selection/report.py} +2 -2
- package/{docs/task-process/implementation-option-selection.md → runtime/python/okstra_ctl/phases/implementation_option_selection/spec.md} +20 -7
- 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/{docs/task-process/implementation-planning.md → runtime/python/okstra_ctl/phases/implementation_planning/spec.md} +30 -6
- 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/{docs/task-process/release-handoff.md → runtime/python/okstra_ctl/phases/release_handoff/spec.md} +22 -9
- 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/{docs/task-process/requirements-discovery.md → runtime/python/okstra_ctl/phases/requirements_discovery/spec.md} +25 -6
- 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} +1 -1
- 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/profile_show.py +9 -3
- package/runtime/python/okstra_ctl/render.py +9 -2
- package/runtime/python/okstra_ctl/render_final_report.py +3 -2
- package/runtime/python/okstra_ctl/report_assembly.py +14 -93
- package/runtime/python/okstra_ctl/report_html/context_links.py +1 -1
- package/runtime/python/okstra_ctl/report_html/render.py +3 -2
- package/runtime/python/okstra_ctl/report_html/router.py +9 -33
- 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_template_loader.py +35 -0
- package/runtime/python/okstra_ctl/report_validation_identity.py +38 -0
- package/runtime/python/okstra_ctl/report_views.py +18 -2
- package/runtime/python/okstra_ctl/run.py +113 -503
- package/runtime/python/okstra_ctl/stage_map.py +13 -0
- package/runtime/python/okstra_ctl/stage_targets.py +9 -286
- package/runtime/python/okstra_ctl/technical_verification_facts.py +52 -0
- package/runtime/python/okstra_ctl/user_response.py +199 -4
- package/runtime/python/okstra_ctl/verification_target.py +1 -1
- 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/state.py +6 -2
- package/runtime/python/okstra_ctl/wizard/steps_analysis.py +0 -97
- package/runtime/python/okstra_ctl/wizard/steps_plan.py +27 -278
- 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_prompt_contract.py +36 -0
- package/runtime/python/okstra_ctl/workflow.py +26 -143
- package/runtime/skills/okstra-brief-gen/SKILL.md +3 -3
- package/runtime/skills/okstra-run/SKILL.md +1 -1
- package/runtime/skills/okstra-user-response/SKILL.md +23 -4
- 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 +287 -4091
- package/runtime/validators/validate_analysis_report.py +14 -126
- package/docs/task-process/README.md +0 -82
- package/docs/task-process/common-flow.md +0 -173
- 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/final-verification.json → python/okstra_ctl/phases/final_verification/profile.json} +0 -0
- /package/runtime/{templates/reports/html/tasks → python/okstra_ctl/phases/final_verification/report_assets}/final-verification.template.html +0 -0
- /package/runtime/{templates/reports/md/tasks → python/okstra_ctl/phases/final_verification/report_assets}/final-verification.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
|
@@ -15,6 +15,16 @@ for _ssot_dir in (_VALIDATORS_DIR.parent / "scripts", _VALIDATORS_DIR.parent / "
|
|
|
15
15
|
sys.path.insert(0, str(_ssot_dir))
|
|
16
16
|
|
|
17
17
|
from okstra_ctl.analysis_inputs import ANALYSIS_TASK_TYPES
|
|
18
|
+
from okstra_ctl.phases.change_impact_analysis.validation import (
|
|
19
|
+
EVIDENCE_COLLECTIONS as CHANGE_IMPACT_EVIDENCE_COLLECTIONS,
|
|
20
|
+
validate_change_impact_semantics,
|
|
21
|
+
)
|
|
22
|
+
from okstra_ctl.phases.feature_analysis.validation import (
|
|
23
|
+
EVIDENCE_COLLECTIONS as FEATURE_EVIDENCE_COLLECTIONS,
|
|
24
|
+
_validate_feature_semantics,
|
|
25
|
+
)
|
|
26
|
+
from okstra_ctl.analysis_scope import _normalized_project_path, _path_is_included
|
|
27
|
+
from okstra_ctl.phases.project_analysis.validation import validate_project_semantics
|
|
18
28
|
from okstra_ctl.final_report_paths import final_report_data_path
|
|
19
29
|
from okstra_ctl.paths import RunRef
|
|
20
30
|
from okstra_ctl.report_views import analysis_review_context
|
|
@@ -35,19 +45,8 @@ _EVIDENCE_COLLECTIONS = {
|
|
|
35
45
|
"externalSystems",
|
|
36
46
|
"featureIndex",
|
|
37
47
|
),
|
|
38
|
-
"feature-analysis":
|
|
39
|
-
|
|
40
|
-
"domainRules",
|
|
41
|
-
"stateChanges",
|
|
42
|
-
"externalInteractions",
|
|
43
|
-
),
|
|
44
|
-
"change-impact-analysis": (
|
|
45
|
-
"preservedBehaviors",
|
|
46
|
-
"impactItems",
|
|
47
|
-
"dependencyBlastRadius",
|
|
48
|
-
"testImpact",
|
|
49
|
-
"operationalImpact",
|
|
50
|
-
),
|
|
48
|
+
"feature-analysis": FEATURE_EVIDENCE_COLLECTIONS,
|
|
49
|
+
"change-impact-analysis": CHANGE_IMPACT_EVIDENCE_COLLECTIONS,
|
|
51
50
|
}
|
|
52
51
|
_ANALYSIS_PARENT_KEYS = {
|
|
53
52
|
"project-analysis": "projectAnalysis",
|
|
@@ -111,33 +110,6 @@ def validate_analysis_snapshot(
|
|
|
111
110
|
)
|
|
112
111
|
|
|
113
112
|
|
|
114
|
-
def _normalized_project_path(path: object) -> PurePosixPath | None:
|
|
115
|
-
if not isinstance(path, str):
|
|
116
|
-
return None
|
|
117
|
-
raw = path.strip().rstrip("/")
|
|
118
|
-
if not raw or raw == "." or raw.startswith("/"):
|
|
119
|
-
return None
|
|
120
|
-
if any(part in {"", ".", ".."} for part in raw.split("/")):
|
|
121
|
-
return None
|
|
122
|
-
normalized = PurePosixPath(raw)
|
|
123
|
-
if normalized.is_absolute():
|
|
124
|
-
return None
|
|
125
|
-
return normalized
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
def _path_is_included(path: object, included_paths: list[object]) -> bool:
|
|
129
|
-
candidate = _normalized_project_path(path)
|
|
130
|
-
if candidate is None:
|
|
131
|
-
return False
|
|
132
|
-
for raw in included_paths:
|
|
133
|
-
included = _normalized_project_path(raw)
|
|
134
|
-
if included is not None and (
|
|
135
|
-
candidate == included or included in candidate.parents
|
|
136
|
-
):
|
|
137
|
-
return True
|
|
138
|
-
return False
|
|
139
|
-
|
|
140
|
-
|
|
141
113
|
def _validate_included_paths(included_paths: list[object], errors: list[str]) -> None:
|
|
142
114
|
for index, path in enumerate(included_paths):
|
|
143
115
|
if _normalized_project_path(path) is None:
|
|
@@ -201,90 +173,6 @@ def _validate_all_current_code_evidence(
|
|
|
201
173
|
)
|
|
202
174
|
|
|
203
175
|
|
|
204
|
-
def _validate_project_semantics(data: dict, errors: list[str]) -> None:
|
|
205
|
-
common = data.get("analysisCommon") or {}
|
|
206
|
-
included = ((common.get("scope") or {}).get("includedPaths") or [])
|
|
207
|
-
analysis = data.get("projectAnalysis") or {}
|
|
208
|
-
for row in analysis.get("featureIndex") or []:
|
|
209
|
-
if not isinstance(row, dict):
|
|
210
|
-
continue
|
|
211
|
-
entry = row.get("representativeEntryPoint") or {}
|
|
212
|
-
if not _path_is_included(entry.get("path"), included):
|
|
213
|
-
errors.append(
|
|
214
|
-
f"projectAnalysis.featureIndex `{row.get('id') or '?'}` representative "
|
|
215
|
-
"entry point must be inside analysisCommon.scope.includedPaths"
|
|
216
|
-
)
|
|
217
|
-
_validate_component_references(analysis, errors)
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
def _validate_component_references(analysis: dict, errors: list[str]) -> None:
|
|
221
|
-
"""Every componentId a row names has to be a component this report declares.
|
|
222
|
-
|
|
223
|
-
The reader clicks these — they render as links to the component's row — so
|
|
224
|
-
a reference to a component that was never listed is a dead anchor, and one
|
|
225
|
-
to a component that exists under a different id is worse: it reads as a
|
|
226
|
-
relationship the analysis never found.
|
|
227
|
-
"""
|
|
228
|
-
declared = {
|
|
229
|
-
row.get("id")
|
|
230
|
-
for row in analysis.get("components") or []
|
|
231
|
-
if isinstance(row, dict) and row.get("id")
|
|
232
|
-
}
|
|
233
|
-
if not declared:
|
|
234
|
-
return
|
|
235
|
-
|
|
236
|
-
def check(component_id: object, where: str) -> None:
|
|
237
|
-
if isinstance(component_id, str) and component_id and component_id not in declared:
|
|
238
|
-
errors.append(f"{where} names component `{component_id}`, which is not declared")
|
|
239
|
-
|
|
240
|
-
for row in analysis.get("internalInterfaces") or []:
|
|
241
|
-
if not isinstance(row, dict):
|
|
242
|
-
continue
|
|
243
|
-
where = f"projectAnalysis.internalInterfaces `{row.get('id') or '?'}`"
|
|
244
|
-
check(row.get("ownerComponentId"), where)
|
|
245
|
-
for consumer in row.get("consumers") or []:
|
|
246
|
-
check(consumer, where)
|
|
247
|
-
for row in analysis.get("workflows") or []:
|
|
248
|
-
if not isinstance(row, dict):
|
|
249
|
-
continue
|
|
250
|
-
for step in row.get("steps") or []:
|
|
251
|
-
if isinstance(step, dict):
|
|
252
|
-
check(step.get("componentId"), f"projectAnalysis.workflows `{row.get('id') or '?'}`")
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
def _validate_feature_semantics(data: dict, errors: list[str]) -> None:
|
|
256
|
-
analysis = data.get("featureAnalysis") or {}
|
|
257
|
-
common_target = (((data.get("analysisCommon") or {}).get("scope") or {}).get(
|
|
258
|
-
"resolvedTarget"
|
|
259
|
-
) or {})
|
|
260
|
-
feature_target = analysis.get("target") or {}
|
|
261
|
-
for field in ("inputMode", "requestedValue"):
|
|
262
|
-
if feature_target.get(field) != common_target.get(field):
|
|
263
|
-
errors.append(
|
|
264
|
-
f"featureAnalysis.target.{field} must match "
|
|
265
|
-
f"analysisCommon.scope.resolvedTarget.{field}"
|
|
266
|
-
)
|
|
267
|
-
resolved_feature = common_target.get("feature") or {}
|
|
268
|
-
if common_target.get("inputMode") == "feature-index" and (
|
|
269
|
-
feature_target.get("featureId") != resolved_feature.get("id")
|
|
270
|
-
):
|
|
271
|
-
errors.append(
|
|
272
|
-
"featureAnalysis.target.featureId must match the resolved feature id"
|
|
273
|
-
)
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
def _validate_change_impact_semantics(data: dict, errors: list[str]) -> None:
|
|
277
|
-
analysis = data.get("changeImpactAnalysis") or {}
|
|
278
|
-
allowed = {"constraint", "unknown"}
|
|
279
|
-
for index, row in enumerate(analysis.get("planningInputs") or []):
|
|
280
|
-
if not isinstance(row, dict):
|
|
281
|
-
continue
|
|
282
|
-
for field in sorted(set(row) - allowed):
|
|
283
|
-
errors.append(
|
|
284
|
-
f"changeImpactAnalysis.planningInputs[{index}] forbids `{field}`; "
|
|
285
|
-
"planning inputs may contain constraints and unknowns only"
|
|
286
|
-
)
|
|
287
|
-
|
|
288
176
|
|
|
289
177
|
def _required_worker_roles(
|
|
290
178
|
run_manifest: dict, errors: list[str]
|
|
@@ -475,11 +363,11 @@ def validate_analysis_semantics(
|
|
|
475
363
|
)
|
|
476
364
|
_validate_all_current_code_evidence(task_type, data, errors)
|
|
477
365
|
if task_type == "project-analysis":
|
|
478
|
-
|
|
366
|
+
validate_project_semantics(data, errors)
|
|
479
367
|
elif task_type == "feature-analysis":
|
|
480
368
|
_validate_feature_semantics(data, errors)
|
|
481
369
|
elif task_type == "change-impact-analysis":
|
|
482
|
-
|
|
370
|
+
validate_change_impact_semantics(data, errors)
|
|
483
371
|
_validate_scope_before_dispatch(
|
|
484
372
|
data, analysis_worker_roles, reporter_confirmation, errors
|
|
485
373
|
)
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
# okstra-run task process
|
|
2
|
-
|
|
3
|
-
## Index
|
|
4
|
-
|
|
5
|
-
- [1. Reading order](#1-reading-order)
|
|
6
|
-
- [2. Big picture](#2-big-picture)
|
|
7
|
-
- [3. task-type documents](#3-task-type-documents)
|
|
8
|
-
- [4. Key code locations](#4-key-code-locations)
|
|
9
|
-
- [5. Quick comparison table](#5-quick-comparison-table)
|
|
10
|
-
|
|
11
|
-
## 1. Reading order
|
|
12
|
-
|
|
13
|
-
`okstra-run` is the path that starts a task inside a supported Claude Code, Codex, or Antigravity host session. This folder organizes that execution flow into two layers.
|
|
14
|
-
|
|
15
|
-
1. First read [common-flow.md](common-flow.md). It is the wizard, render-bundle, lead phase, and artifact flow shared by every task-type.
|
|
16
|
-
2. Then read the document for the task-type you want to run.
|
|
17
|
-
3. Check the per-task-type differences across three places: "what the wizard additionally asks", "what `prepare_task_bundle()` blocks in the runtime", and "what the lead profile enforces within the phase".
|
|
18
|
-
|
|
19
|
-
## 2. Big picture
|
|
20
|
-
|
|
21
|
-
```mermaid
|
|
22
|
-
flowchart TD
|
|
23
|
-
U[User in supported host] --> S[okstra-run skill]
|
|
24
|
-
S --> R[Step 1<br/>ensure-installed / paths / check-project]
|
|
25
|
-
R --> W[okstra wizard<br/>state machine]
|
|
26
|
-
W --> A[render-args]
|
|
27
|
-
A --> B[okstra render-bundle<br/>--render-only]
|
|
28
|
-
B --> P[prepare_task_bundle()]
|
|
29
|
-
P --> I["runs/task-type/prompts<br/>lead-execution-prompt-*.md"]
|
|
30
|
-
I --> L[Current host session<br/>takes over as Okstra lead]
|
|
31
|
-
L --> F[Phase 1-7 lead workflow]
|
|
32
|
-
F --> O[final-report + manifests + status]
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
`okstra-run` does not call `scripts/okstra.sh`. Instead it goes through `okstra wizard` and `okstra render-bundle` and converges on the same single Python entrypoint, `prepare_task_bundle()`.
|
|
36
|
-
|
|
37
|
-
Launch selection is role slots and model refs, not a provider roster. The wizard asks one screen per static role: a checkbox of candidate models for a role that runs several instances (the number checked is the instance count, rendered as `--role-count <role>=<N>` plus one `--role-model <role>=<provider>/<model>` per checked model; the label states the profile range and recommended count), a single pick for a fixed single-instance role. current-session lead is this session and is listed on the confirmation summary. Roles with `min = 0` stay closed unless the user adds them. There is no provider multi-pick and no `Use defaults / Customize` fork for worker selection. `--workers` is compatibility-only. `lead` is a compatibility alias for `leader`. `executor` is a compatibility alias for `implementer`. New records write `leader` and `implementer`.
|
|
38
|
-
|
|
39
|
-
## 3. task-type documents
|
|
40
|
-
|
|
41
|
-
| task-type | Document | One-line purpose |
|
|
42
|
-
|---|---|---|
|
|
43
|
-
| `requirements-discovery` | [requirements-discovery.md](requirements-discovery.md) | Classify the request and choose the next safe phase. |
|
|
44
|
-
| `error-analysis` | [error-analysis.md](error-analysis.md) | Find cause candidates and validation paths from symptoms and evidence. |
|
|
45
|
-
| `implementation-option-selection` | [implementation-option-selection.md](implementation-option-selection.md) | Compare or validate exact-coverage directions before detailed planning. |
|
|
46
|
-
| `implementation-planning` | [implementation-planning.md](implementation-planning.md) | Realize one selected direction as an exact-coverage plan with a separate approval gate. |
|
|
47
|
-
| `implementation` | [implementation.md](implementation.md) | The executor implements the approved plan and the verifier verifies it independently. |
|
|
48
|
-
| `final-verification` | [final-verification.md](final-verification.md) | Judge whole-task or single-stage acceptance of the implementation result. |
|
|
49
|
-
| `release-handoff` | [release-handoff.md](release-handoff.md) | Perform the push/PR handoff lead-only after an accepted verdict. |
|
|
50
|
-
|
|
51
|
-
## 4. Key code locations
|
|
52
|
-
|
|
53
|
-
| Concern | Source of truth |
|
|
54
|
-
|---|---|
|
|
55
|
-
| okstra-run skill procedure | [`skills/okstra-run/SKILL.md`](../../skills/okstra-run/SKILL.md) |
|
|
56
|
-
| wizard state machine | [`scripts/okstra_ctl/wizard/`](../../scripts/okstra_ctl/wizard/) |
|
|
57
|
-
| wizard prompt text | [`prompts/wizard/prompts.ko.json`](../../prompts/wizard/prompts.ko.json) |
|
|
58
|
-
| render-bundle Node shim | [`src/commands/execute/render-bundle.mts`](../../src/commands/execute/render-bundle.mts) |
|
|
59
|
-
| single entrypoint for bundle creation | [`scripts/okstra_ctl/run.py`](../../scripts/okstra_ctl/run.py) |
|
|
60
|
-
| implementation stage selection/provisioning | [`scripts/okstra_ctl/implementation_stage.py`](../../scripts/okstra_ctl/implementation_stage.py) |
|
|
61
|
-
| Stage Lifecycle Snapshot + stage target/base/verification policy | [`scripts/okstra_ctl/stage_targets.py`](../../scripts/okstra_ctl/stage_targets.py) |
|
|
62
|
-
| phase boundary | [`scripts/okstra_ctl/workflow.py`](../../scripts/okstra_ctl/workflow.py) |
|
|
63
|
-
| task worktree | [`scripts/okstra_ctl/worktree/`](../../scripts/okstra_ctl/worktree/) |
|
|
64
|
-
| stage-group handoff | [`scripts/okstra_ctl/handoff.py`](../../scripts/okstra_ctl/handoff.py) |
|
|
65
|
-
| worker roster parser | [`scripts/okstra_ctl/workers.py`](../../scripts/okstra_ctl/workers.py) |
|
|
66
|
-
| lead operating contract | [`prompts/lead/okstra-lead-contract.md`](../../prompts/lead/okstra-lead-contract.md) |
|
|
67
|
-
| phase profiles | [`prompts/profiles/`](../../prompts/profiles/) |
|
|
68
|
-
| final report shape / HTML view | [`templates/reports/final-report-v2.template.md`](../../templates/reports/final-report-v2.template.md), [`scripts/okstra_ctl/report_views.py`](../../scripts/okstra_ctl/report_views.py) |
|
|
69
|
-
|
|
70
|
-
## 5. Quick comparison table
|
|
71
|
-
|
|
72
|
-
The last column is the `workflow.nextRecommendedPhase` pointer Phase 7 leaves behind — an object `{phase, status, rationale}`, projected from the report's own routing field. There is no static default: a run that settles no route ends `pending` with no phase. The routing field's `rationale` is carried into the pointer, and the lead's closeout quotes it. The rule for authoring that field is stated once, in the Phase 6 checklist of [`prompts/lead/report-writer.md`](../../prompts/lead/report-writer.md).
|
|
73
|
-
|
|
74
|
-
| task-type | wizard special question | runtime prepare gate | lead/worker mode | next-phase pointer |
|
|
75
|
-
|---|---|---|---|---|
|
|
76
|
-
| `requirements-discovery` | common questions only | profile/brief/base-ref exist | multi-worker analysis, convergence 1 round default | `ready` at `error-analysis` or `implementation-option-selection`; `pending` when neither is settled |
|
|
77
|
-
| `error-analysis` | common questions only | profile/brief/base-ref exist | multi-worker analysis, convergence 2 rounds default | `ready` at `implementation-option-selection`, or at `error-analysis` while the investigation continues |
|
|
78
|
-
| `implementation-option-selection` | comparison or preselected-validation context | stable brief IDs and at least three analysers | read-only candidate validation, exact coverage, separate direction confirmation | `ready` at `implementation-planning` (a confirmed direction, or ranked candidates the planning wizard lets the user pick from), `pending` when no candidate was ranked, or `blocked` |
|
|
79
|
-
| `implementation-planning` | selected-direction report for a new plan | selection report/sidecar/digest or same-task planning rerun | one-direction realization + Phase 6 plan-body verification | `ready` at `implementation` on approvable `plan-ready` (`awaitingApproval` until the user flips `approved`); `blocked` when the gate is blocking or a `Blocks=approval` row is open; `ready` at `implementation-option-selection` on `direction-invalidated` |
|
|
80
|
-
| `implementation` | approved plan, stage multi-pick, executor | approved marker, Stage Lifecycle Snapshot, stage-key reservation, QA command deny-list | one run = one stage; executor writes in isolated stage worktree, verifiers read-only | `ready` at the stage report's `routingRecommendation.target` — `final-verification` on a clean stage |
|
|
81
|
-
| `final-verification` | approved plan, stage pick (whole-task or single-stage) | `VERIFICATION_TARGET` resolved; whole-task auto integration/teardown or single-stage worktree reuse | whole-task may integrate stages first; analyser verification itself is read-only | `ready` at `release-handoff` on an `accepted` verdict, otherwise at the phase owning the defect; `terminal` on `done` |
|
|
82
|
-
| `release-handoff` | handoff scope (stage-group or whole-task), PR template override/scope | Stage Lifecycle Snapshot eligibility, generated `release-handoff-input.md`, empty worker roster | single-lead; whole-task PR or stage-group collector branch/PR | always `terminal` |
|
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
# okstra-run common flow
|
|
2
|
-
|
|
3
|
-
## Index
|
|
4
|
-
|
|
5
|
-
- [1. One-line summary](#1-one-line-summary)
|
|
6
|
-
- [2. Where the two entrypoints meet](#2-where-the-two-entrypoints-meet)
|
|
7
|
-
- [3. wizard input collection flow](#3-wizard-input-collection-flow)
|
|
8
|
-
- [4. render-bundle and prepare_task_bundle](#4-render-bundle-and-prepare_task_bundle)
|
|
9
|
-
- [5. Okstra lead phase 1-7](#5-okstra-lead-phase-1-7)
|
|
10
|
-
- [6. artifact layout](#6-artifact-layout)
|
|
11
|
-
- [7. Common branching rules](#7-common-branching-rules)
|
|
12
|
-
- [8. Inconsistencies to watch for](#8-inconsistencies-to-watch-for)
|
|
13
|
-
|
|
14
|
-
## 1. One-line summary
|
|
15
|
-
|
|
16
|
-
`okstra-run` is not a "skill that decides questions on its own" but a thin loop that relays the `okstra wizard` JSON state machine to the user. Once input collection finishes, it calls `okstra render-bundle`, and that command builds the task bundle through `python3 -m okstra_ctl.run --render-only`. After that, the current Claude Code, Codex, or Antigravity session switches over to the host-native `Okstra lead`.
|
|
17
|
-
|
|
18
|
-
## 2. Where the two entrypoints meet
|
|
19
|
-
|
|
20
|
-
```mermaid
|
|
21
|
-
flowchart LR
|
|
22
|
-
subgraph InSession["supported host session"]
|
|
23
|
-
A[okstra-run skill] --> B[okstra wizard]
|
|
24
|
-
B --> C[okstra render-bundle<br/>forces --render-only]
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
subgraph Terminal["terminal path"]
|
|
28
|
-
D[scripts/okstra.sh] --> E[CLI parse / prompt / confirm]
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
C --> P[prepare_task_bundle()]
|
|
32
|
-
E --> P
|
|
33
|
-
P --> G[task bundle artifacts]
|
|
34
|
-
G --> H{launch mode}
|
|
35
|
-
H -->|render-only| I[current host reads lead prompt]
|
|
36
|
-
H -->|non-render-only| J[exec claude --session-id ...]
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
The common principle is that `prepare_task_bundle()` is the single authority for task bundle creation. Neither the wizard nor the shell wrapper duplicates the path computation, manifest creation, or worktree creation logic.
|
|
40
|
-
|
|
41
|
-
## 3. wizard input collection flow
|
|
42
|
-
|
|
43
|
-
```mermaid
|
|
44
|
-
stateDiagram-v2
|
|
45
|
-
[*] --> VerifyRuntime: okstra ensure-installed / paths / check-project
|
|
46
|
-
VerifyRuntime --> NewState: okstra wizard new-state-file
|
|
47
|
-
NewState --> TaskPick: wizard init
|
|
48
|
-
TaskPick --> BriefPath: brand-new task
|
|
49
|
-
TaskPick --> TaskType: existing task
|
|
50
|
-
BriefPath --> TaskGroup: new task, brief accepted
|
|
51
|
-
TaskGroup --> TaskId
|
|
52
|
-
TaskId --> TaskType
|
|
53
|
-
TaskType --> BriefKeep: existing task with existing brief
|
|
54
|
-
BriefKeep --> BriefPath: change
|
|
55
|
-
BriefKeep --> BaseRef: keep
|
|
56
|
-
TaskType --> BaseRef: no active worktree
|
|
57
|
-
TaskType --> ImplementationExtras: implementation only
|
|
58
|
-
BaseRef --> ImplementationExtras: implementation only
|
|
59
|
-
BaseRef --> LeaderSession: non-implementation
|
|
60
|
-
ImplementationExtras --> LeaderSession
|
|
61
|
-
LeaderSession --> RoleSlots: one model screen per role
|
|
62
|
-
RoleSlots --> OptionalInputs: directive / related / clarification
|
|
63
|
-
OptionalInputs --> Confirm
|
|
64
|
-
Confirm --> EditTarget: Edit
|
|
65
|
-
EditTarget --> TaskType: rewind selected step
|
|
66
|
-
Confirm --> Done: Proceed
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
A new task receives its brief first. If the brief frontmatter has `task-group:` and `brief-id:`, the wizard shows the task group/id as recommended picks. An existing task shows the manifest's `workflow.nextRecommendedPhase.phase` as the recommended task-type, but only while that pointer's `status` is `ready`. Under any other status the recommended slot stays empty and the list falls back to rerunning `workflow.currentPhase` plus the full task-type choices. If an existing brief path exists it asks whether to keep or change it.
|
|
70
|
-
|
|
71
|
-
## 4. render-bundle and prepare_task_bundle
|
|
72
|
-
|
|
73
|
-
```mermaid
|
|
74
|
-
sequenceDiagram
|
|
75
|
-
participant Skill as okstra-run skill
|
|
76
|
-
participant Node as okstra CLI
|
|
77
|
-
participant Py as okstra_ctl.run
|
|
78
|
-
participant FS as .okstra
|
|
79
|
-
participant Home as ~/.okstra
|
|
80
|
-
|
|
81
|
-
Skill->>Node: okstra wizard outcome
|
|
82
|
-
Node-->>Skill: { renderArgs: ..., persistActions: ... }
|
|
83
|
-
opt persistActions present
|
|
84
|
-
Skill->>Node: okstra config set ...
|
|
85
|
-
end
|
|
86
|
-
Skill->>Node: okstra render-bundle --... --render-only
|
|
87
|
-
Node->>Py: python3 -m okstra_ctl.run --render-only --...
|
|
88
|
-
Py->>Py: validate profile, brief, task-type gates
|
|
89
|
-
Py->>Home: reserve/reuse task worktree registry
|
|
90
|
-
Py->>FS: write run-context and instruction-set
|
|
91
|
-
Py->>FS: write task/run manifests, team-state, timeline, discovery
|
|
92
|
-
Py->>Home: record_start status=prepared
|
|
93
|
-
Py-->>Node: task root, instruction-set, rendered lead prompt
|
|
94
|
-
Node-->>Skill: stdout
|
|
95
|
-
Skill->>FS: read lead-execution-prompt.md
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
The Node shim for `render-bundle` is [`src/commands/execute/render-bundle.mts`](../../src/commands/execute/render-bundle.mts). This shim attaches the `--workspace-root`, `--render-only`, and runtime resolution arguments directly. As a result, on the okstra-run path the initial run status starts at `prepared` and the task status starts at `ready-for-lead`.
|
|
99
|
-
|
|
100
|
-
## 5. Okstra lead phase 1-7
|
|
101
|
-
|
|
102
|
-
```mermaid
|
|
103
|
-
flowchart TD
|
|
104
|
-
P1[Phase 1<br/>task bundle intake] --> P2[Phase 2<br/>worker prompt preparation]
|
|
105
|
-
P2 --> P3[Phase 3<br/>resolve persisted runners]
|
|
106
|
-
P3 -->|native session| P4[Phase 4<br/>host-native dispatch]
|
|
107
|
-
P3 -->|CLI wrapper| P5[Phase 4<br/>provider CLI dispatch]
|
|
108
|
-
P4 --> C[Phase 5.5<br/>convergence]
|
|
109
|
-
P5 --> C
|
|
110
|
-
C --> P6[Phase 6<br/>report-writer synthesis]
|
|
111
|
-
P6 --> PV{implementation-planning?}
|
|
112
|
-
PV -->|yes| PBV[Plan-body verification]
|
|
113
|
-
PV -->|no| P7[Phase 7<br/>persist + validate]
|
|
114
|
-
PBV --> P7
|
|
115
|
-
P7 --> Done[final report + manifests updated]
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
The roles of the analysis workers and the report-writer are separated. `report-writer` is not a Phase 4/5 analysis worker but the Phase 6 final report author. Note, however, that `release-handoff` is a single-lead phase, so it deliberately does not follow this phase graph.
|
|
119
|
-
|
|
120
|
-
## 6. artifact layout
|
|
121
|
-
|
|
122
|
-
```mermaid
|
|
123
|
-
flowchart TD
|
|
124
|
-
Root["<PROJECT_ROOT>/.okstra/tasks/<group>/<task>/"] --> IS[instruction-set/]
|
|
125
|
-
Root --> Runs[runs/<task-type>/]
|
|
126
|
-
Root --> Hist[history/timeline.json]
|
|
127
|
-
IS --> Profile[analysis-profile.md]
|
|
128
|
-
IS --> Brief[task-brief.md]
|
|
129
|
-
Runs --> Lead["prompts/lead-execution-prompt-*.md"]
|
|
130
|
-
Runs --> Man[manifests/run-manifest-*.json]
|
|
131
|
-
Runs --> Prompts[prompts/*-worker-prompt-*.md]
|
|
132
|
-
Runs --> Results[worker-results/*.md]
|
|
133
|
-
Runs --> Reports[reports/final-report-*.md<br/>reports/*.data.json<br/>reports/final-report-*.html]
|
|
134
|
-
Runs --> State[state/*.json]
|
|
135
|
-
Runs --> Status[status/final-status-*.json]
|
|
136
|
-
Runs --> ImplStage[implementation/stage-N/...]
|
|
137
|
-
Runs --> FvStage[final-verification/stage-N/...]
|
|
138
|
-
Runs --> Carry[implementation/carry/stage-N.json]
|
|
139
|
-
Runs --> Consumers[implementation-planning/consumers.jsonl]
|
|
140
|
-
Root --> Handoff[release-handoff-input.md]
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
`implementation` and single-stage `final-verification` isolate their run deliverables under `stage-<N>/`. The `implementation` carry sidecar and `consumers.jsonl` are cross-stage coordination ledgers, so they remain at the phase root. The runtime reads this ledger and the registry reservations as a Stage Lifecycle Snapshot to compute stage selection and handoff eligibility. `release-handoff` does not receive a brief; prepare generates `release-handoff-input.md`.
|
|
144
|
-
|
|
145
|
-
`runtime/` is build output, so when you fix this flow you edit the sources `scripts/`, `skills/`, `agents/`, `prompts/`, `templates/`, `validators/` and refresh with `npm run build`.
|
|
146
|
-
|
|
147
|
-
## 7. Common branching rules
|
|
148
|
-
|
|
149
|
-
```mermaid
|
|
150
|
-
flowchart TD
|
|
151
|
-
T[task-type selected] --> W{active worktree in registry?}
|
|
152
|
-
W -->|yes| Reuse[reuse existing worktree<br/>base-ref prompt skipped]
|
|
153
|
-
W -->|no| Base[ask base-ref<br/>validate with git rev-parse]
|
|
154
|
-
Base --> M[one screen per static role<br/>checkbox: models checked = instances<br/>single pick: fixed single role]
|
|
155
|
-
Reuse --> M
|
|
156
|
-
M --> O[directive / related / clarification]
|
|
157
|
-
O --> Special{release-handoff?}
|
|
158
|
-
Special -->|yes| PR[PR template override/scope]
|
|
159
|
-
Special -->|no| Confirm
|
|
160
|
-
PR --> Confirm
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
Launch selection is role slots and model refs. The wizard does not show a provider roster multi-pick and does not fork on `Use defaults / Customize` for workers. A multi-instance role is one checkbox screen whose checked models become the instances (the wizard renders `--role-count` from that number); on the CLI, omitting `--role-count` keeps each static role at its profile **recommended** count within `min..max`. Duplicate model refs in the same role are rejected. `--workers` remains a CLI compatibility input only.
|
|
164
|
-
|
|
165
|
-
Worktree rules differ per phase. From `requirements-discovery` through `implementation-planning`, the task-key worktree is reused. `implementation` uses the task-key worktree as an anchor but does the actual execution isolated one stage at a time in a stage-key (`stage-<N>`) worktree and the `runs/implementation/stage-<N>/` deliverables. `final-verification --stage N` reuses that implementation stage worktree as a read target, and whole-task mode auto-integrates the stage commits into the task-key worktree and then builds the verification target. The Stage Lifecycle Snapshot is a read-side view that does not change this storage structure.
|
|
166
|
-
|
|
167
|
-
## 8. Inconsistencies to watch for
|
|
168
|
-
|
|
169
|
-
- The `okstra-run` wizard path passes only if the implementation approved plan already has an approval marker. `scripts/okstra.sh` has `--approve`, which can flip the checkbox with a CLI ack, but the current wizard `render_args()` has no `approve` flag.
|
|
170
|
-
- `release-handoff` has no brief. Prepare cites the accepted final-verification report to build `release-handoff-input.md`, and the wizard's `handoff_stage_pick` or the CLI `--stages` fixes the whole-task/stage-group scope.
|
|
171
|
-
- `release-handoff` is also a target for task worktree provisioning. A healthy handoff is safest when it reuses the implementation/final-verification results of the same task-key. Starting a new task creates a new worktree, which may be blocked at the profile's "an implementation commit must exist" entry gate.
|
|
172
|
-
- `release-handoff` has no `Required workers:` block in its profile. The runtime also forces the worker roster to be empty.
|
|
173
|
-
- No task-type starts the next lifecycle phase within a single run. "Proceed to the next step" is interpreted only as wrapping up the current phase's output.
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
"""Human-first implementation-planning view and approval state."""
|
|
2
|
-
from __future__ import annotations
|
|
3
|
-
|
|
4
|
-
import re
|
|
5
|
-
from dataclasses import dataclass
|
|
6
|
-
|
|
7
|
-
from ..common import evidence_index
|
|
8
|
-
from ..models import HumanReportView, VisualEdge, VisualNode
|
|
9
|
-
from ..visualizations import stage_map_figure
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
@dataclass(frozen=True)
|
|
13
|
-
class PlanApprovalState:
|
|
14
|
-
option_names: tuple[str, ...]
|
|
15
|
-
recommended_option: str
|
|
16
|
-
disabled_reason: str
|
|
17
|
-
blocker_ids: tuple[str, ...]
|
|
18
|
-
show_option_selector: bool = True
|
|
19
|
-
reentry_command: str = ""
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def resolve_recommended_option(rec_name: str, names: tuple[str, ...]) -> str:
|
|
23
|
-
if rec_name in names:
|
|
24
|
-
return rec_name
|
|
25
|
-
matches = [
|
|
26
|
-
name
|
|
27
|
-
for name in names
|
|
28
|
-
if rec_name and (name.startswith(rec_name) or rec_name.startswith(name))
|
|
29
|
-
]
|
|
30
|
-
return matches[0] if len(matches) == 1 else names[0]
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def plan_approval_state(data: dict) -> PlanApprovalState | None:
|
|
34
|
-
planning = data.get("implementationPlanning")
|
|
35
|
-
if not isinstance(planning, dict):
|
|
36
|
-
return None
|
|
37
|
-
blockers = tuple(
|
|
38
|
-
row["id"]
|
|
39
|
-
for row in data.get("clarificationItems", [])
|
|
40
|
-
if row.get("blocks") == "approval"
|
|
41
|
-
and row.get("status") in {"open", "answered"}
|
|
42
|
-
)
|
|
43
|
-
reason = f"{len(blockers)} approval blocker(s) unresolved" if blockers else ""
|
|
44
|
-
if planning.get("planningContract") == "selected-direction":
|
|
45
|
-
if planning.get("outcome") == "direction-invalidated" and not reason:
|
|
46
|
-
reason = "selected direction invalidated"
|
|
47
|
-
task_key = (data.get("header") or {}).get("taskKey", "")
|
|
48
|
-
reentry_command = (
|
|
49
|
-
f"/okstra-run task-key={task_key} "
|
|
50
|
-
"task-type=implementation-option-selection"
|
|
51
|
-
if planning.get("outcome") == "direction-invalidated" and task_key
|
|
52
|
-
else ""
|
|
53
|
-
)
|
|
54
|
-
return PlanApprovalState(
|
|
55
|
-
(), "", reason, blockers, False, reentry_command
|
|
56
|
-
)
|
|
57
|
-
names = tuple(
|
|
58
|
-
row["name"]
|
|
59
|
-
for row in planning.get("optionCandidates", [])
|
|
60
|
-
if isinstance(row, dict) and row.get("name")
|
|
61
|
-
)
|
|
62
|
-
if not names:
|
|
63
|
-
return None
|
|
64
|
-
recommended = planning.get("recommendedOption", {}).get("name", "")
|
|
65
|
-
return PlanApprovalState(
|
|
66
|
-
names,
|
|
67
|
-
resolve_recommended_option(recommended, names),
|
|
68
|
-
reason,
|
|
69
|
-
blockers,
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def _stage_figure(planning: dict):
|
|
74
|
-
nodes = tuple(
|
|
75
|
-
VisualNode(
|
|
76
|
-
f"stage-{row['stage']}",
|
|
77
|
-
f"Stage {row['stage']} · {row['title']}",
|
|
78
|
-
"stage",
|
|
79
|
-
"planned",
|
|
80
|
-
row["exitContractSummary"],
|
|
81
|
-
)
|
|
82
|
-
for row in planning["stageMap"]
|
|
83
|
-
)
|
|
84
|
-
edges = tuple(
|
|
85
|
-
VisualEdge(f"stage-{dependency}", f"stage-{row['stage']}", "precedes", "dependency")
|
|
86
|
-
for row in planning["stageMap"]
|
|
87
|
-
for dependency in re.findall(r"\d+", row["dependsOn"])
|
|
88
|
-
)
|
|
89
|
-
return stage_map_figure(nodes=nodes, edges=edges, title="Implementation stage dependencies")
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
# Record fields this template anchors as `id-<row id>` (see
|
|
93
|
-
# `HumanReportView.anchored_fields`). The implementer-facing tables the
|
|
94
|
-
# approver does not read — validation checklist, cross-project dependencies,
|
|
95
|
-
# migration risk, rollback — are not drawn, so their rows land in the ledger.
|
|
96
|
-
ANCHORED_FIELDS = (
|
|
97
|
-
"implementationPlanning.directionRealization.fileStructure",
|
|
98
|
-
"implementationPlanning.directionRealization.planningInvariants",
|
|
99
|
-
"implementationPlanning.optionCandidates.fileStructure",
|
|
100
|
-
"implementationPlanning.designPreparation.items",
|
|
101
|
-
"implementationPlanning.requirementCoverage",
|
|
102
|
-
"implementationPlanning.planBodyVerification.planItems",
|
|
103
|
-
"implementationPlanning.supersessionLedger",
|
|
104
|
-
)
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
def build_implementation_planning_view(data: dict) -> HumanReportView:
|
|
108
|
-
planning = data["implementationPlanning"]
|
|
109
|
-
figure = _stage_figure(planning) if planning.get("stageMap") else None
|
|
110
|
-
approval = plan_approval_state(data)
|
|
111
|
-
activities = tuple(
|
|
112
|
-
row for row in data.get("agentActivity", []) if isinstance(row, dict)
|
|
113
|
-
)
|
|
114
|
-
decision_cards = tuple(
|
|
115
|
-
row
|
|
116
|
-
for row in data.get("clarificationItems", [])
|
|
117
|
-
if isinstance(row, dict)
|
|
118
|
-
and row.get("blocks") == "approval"
|
|
119
|
-
and isinstance(row.get("approvalContext"), dict)
|
|
120
|
-
)
|
|
121
|
-
context = {
|
|
122
|
-
"humanSummary": data["humanSummary"],
|
|
123
|
-
"planning": planning,
|
|
124
|
-
"narrative": planning.get("userNarrative", {}),
|
|
125
|
-
"stageFigure": figure,
|
|
126
|
-
"approval": approval,
|
|
127
|
-
"openDecisions": [
|
|
128
|
-
row
|
|
129
|
-
for row in data.get("clarificationItems", [])
|
|
130
|
-
if isinstance(row, dict)
|
|
131
|
-
and row.get("blocks") == "approval"
|
|
132
|
-
and row.get("status") in {"open", "answered"}
|
|
133
|
-
],
|
|
134
|
-
"agentActivities": activities,
|
|
135
|
-
"activityById": {
|
|
136
|
-
row["activityId"]: row for row in activities if row.get("activityId")
|
|
137
|
-
},
|
|
138
|
-
"decisionCards": decision_cards,
|
|
139
|
-
"evidenceIndex": evidence_index(data, ANCHORED_FIELDS),
|
|
140
|
-
}
|
|
141
|
-
return HumanReportView(
|
|
142
|
-
"implementation-planning",
|
|
143
|
-
"html/tasks/implementation-planning.template.html",
|
|
144
|
-
context,
|
|
145
|
-
(figure,) if figure is not None else (),
|
|
146
|
-
anchored_fields=ANCHORED_FIELDS,
|
|
147
|
-
)
|