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,100 @@
|
|
|
1
|
+
"""미확정 사실의 시험 입력과 관측 결과를 연결하며 도입 승인은 만들지 않는다."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import hashlib
|
|
6
|
+
import re
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import TypedDict
|
|
9
|
+
|
|
10
|
+
from okstra_ctl.final_report_schema import load_schema_for_data, validate
|
|
11
|
+
from okstra_ctl.implementation_direction import validate_task_artifact_path
|
|
12
|
+
from okstra_ctl.json_boundary import load_owned_object_snapshot, serialize_owned_object
|
|
13
|
+
from okstra_ctl.technical_verification_facts import (
|
|
14
|
+
TechnicalVerificationError,
|
|
15
|
+
VerificationFact,
|
|
16
|
+
technical_verification_facts,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class VerificationInput(TypedDict):
|
|
21
|
+
sourceReport: str
|
|
22
|
+
sourceDataSha256: str
|
|
23
|
+
scope: str
|
|
24
|
+
facts: list[VerificationFact]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def resolve_technical_verification_input(
|
|
28
|
+
report: Path, project_root: Path, task_root: Path, task_key: str
|
|
29
|
+
) -> VerificationInput:
|
|
30
|
+
"""같은 작업의 후보 비교 기록을 시험 입력으로 고정한다."""
|
|
31
|
+
report = report if report.is_absolute() else project_root / report
|
|
32
|
+
validate_task_artifact_path(report, task_root, "technical verification source")
|
|
33
|
+
expected_parent = task_root / "runs/implementation-option-selection/reports"
|
|
34
|
+
if report.parent != expected_parent or not re.fullmatch(
|
|
35
|
+
r"final-report-implementation-option-selection-\d{3,}\.data\.json", report.name
|
|
36
|
+
):
|
|
37
|
+
raise TechnicalVerificationError(
|
|
38
|
+
"source must be this task's option-selection record"
|
|
39
|
+
)
|
|
40
|
+
snapshot = load_owned_object_snapshot(
|
|
41
|
+
report, artifact="technical verification source"
|
|
42
|
+
)
|
|
43
|
+
data = snapshot.value
|
|
44
|
+
errors = validate(data, load_schema_for_data(data))
|
|
45
|
+
if errors:
|
|
46
|
+
raise TechnicalVerificationError("invalid source report: " + "; ".join(errors))
|
|
47
|
+
if data["header"]["taskKey"] != task_key:
|
|
48
|
+
raise TechnicalVerificationError(
|
|
49
|
+
"source taskKey does not match verification task"
|
|
50
|
+
)
|
|
51
|
+
return {
|
|
52
|
+
"sourceReport": report.relative_to(project_root).as_posix(),
|
|
53
|
+
"sourceDataSha256": hashlib.sha256(snapshot.raw_bytes).hexdigest(),
|
|
54
|
+
"scope": "technical-evidence-only",
|
|
55
|
+
"facts": technical_verification_facts(data),
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def write_technical_verification_input(
|
|
60
|
+
payload: VerificationInput, run_root: Path, seq: str
|
|
61
|
+
) -> Path:
|
|
62
|
+
"""실행 순번별 입력을 저장해 후속 실행이 이전 시험 범위를 덮지 않게 한다."""
|
|
63
|
+
path = run_root / "state" / f"technical-verification-input-{seq}.json"
|
|
64
|
+
serialized = serialize_owned_object(path, payload, artifact="technical verification input")
|
|
65
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
66
|
+
with path.open("x", encoding="utf-8") as output:
|
|
67
|
+
output.write(serialized)
|
|
68
|
+
return path
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def prepare_technical_verification_input(
|
|
72
|
+
source_path: str, project_root: Path, task_root: Path, task_key: str
|
|
73
|
+
) -> VerificationInput:
|
|
74
|
+
"""공통 준비가 부수효과를 시작하기 전에 필수 입력과 오류 형식을 고정한다."""
|
|
75
|
+
from okstra_ctl.prepare_error import PrepareError
|
|
76
|
+
|
|
77
|
+
if not source_path:
|
|
78
|
+
raise PrepareError("technical-verification requires --clarification-response pointing to this task's option-selection record")
|
|
79
|
+
try:
|
|
80
|
+
return resolve_technical_verification_input(
|
|
81
|
+
Path(source_path), project_root, task_root, task_key,
|
|
82
|
+
)
|
|
83
|
+
except ValueError as exc:
|
|
84
|
+
raise PrepareError(str(exc)) from exc
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def materialize_technical_input_packet(payload_json: str, run_root: Path, seq: str) -> str:
|
|
88
|
+
"""입력 저장과 패킷 안내를 함께 구성해 실행 순번별 증거 위치를 보존한다."""
|
|
89
|
+
import json
|
|
90
|
+
|
|
91
|
+
verification_path = write_technical_verification_input(
|
|
92
|
+
json.loads(payload_json), run_root, seq,
|
|
93
|
+
)
|
|
94
|
+
return (
|
|
95
|
+
"\n## Technical Verification Input\n\n"
|
|
96
|
+
f"- Frozen input: `{verification_path}`\n"
|
|
97
|
+
f"- Experiment copies only: `{run_root}/experiments/{seq}/<worker-id>/`\n"
|
|
98
|
+
"- Read the input before planning experiments; copy each fact identity verbatim into results.\n"
|
|
99
|
+
+ "\n```json\n" + payload_json + "\n```\n"
|
|
100
|
+
)
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
1. Read the frozen technical input linked in the analysis packet. Preserve the source hash, candidate IDs and fact identities. `resolve_technical_verification_input` enforces same-task source ownership, schema validity, eligible technical facts and unresolved user-decision gates.
|
|
13
13
|
2. Before executing a probe, write its plan under `experiments/<seq>/<worker-id>/`: hypothesis, procedure, commands, confirming and rejecting signals, environment, and inconclusive criteria. Retain the plan with the evidence.
|
|
14
14
|
3. Create a separate source copy in that directory. Record the source commit and any uncommitted input differences. Read the project and task worktree as inputs; perform source edits, installations and builds only in your own copy. Do not share writable dependency directories or use real credentials. Use synthetic local accounts for request-boundary experiments.
|
|
15
|
-
4. Preserve the baseline lockfile. When the hypothesis needs a deliberate dependency change, retain the resulting lockfile and diff, then use a frozen install against that experimental lockfile. Record command, working directory, stdout/stderr and exit code in run-local logs. Distinguish infrastructure failure from a falsified compatibility claim.
|
|
15
|
+
4. Phase 7 removes every `node_modules` and `.next` directory under the run directory, so evidence must not live inside them. Preserve the baseline lockfile. When the hypothesis needs a deliberate dependency change, retain the resulting lockfile and diff, then use a frozen install against that experimental lockfile. Record command, working directory, stdout/stderr and exit code in run-local logs. Distinguish infrastructure failure from a falsified compatibility claim.
|
|
16
16
|
5. Classify each fact as `supported`, `refuted`, `inconclusive` or `not-run` using the declared signals. A zero exit code alone does not establish compatibility. Record limitations and all failed or unavailable probes.
|
|
17
17
|
6. During convergence, inspect plans and logs; rerun disputed probes in a separate copy when feasible. An independent report is not a substitute for command evidence.
|
|
18
18
|
|
|
@@ -22,7 +22,7 @@ Copy boundaries and pre-execution plans are worker instructions reviewed during
|
|
|
22
22
|
|
|
23
23
|
Copy `sourceReport`, `sourceDataSha256` and `scope` from the frozen input into `technicalVerification`. Emit exactly one check per fact, preserving its `id`, `candidateId`, `factIndex` and `fact`. Each check records its hypothesis, procedure, signals, command evidence, observation, status and limitations. Use project-relative evidence paths. Mark contested results inconclusive.
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
Do not edit the source comparison, clear unrelated uncertainties, rank candidates, approve implementation, merge code or expand the user's pilot scope.
|
|
26
26
|
|
|
27
27
|
`validate_technical_verification_report` checks frozen-input identity and evidence before publication and during run validation. The report schema restricts the routing target and requires `frontmatter.approved=false`.
|
|
28
28
|
{{INCLUDE:_coverage-critic.md}}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from
|
|
6
|
-
from
|
|
5
|
+
from okstra_ctl.report_html.common import evidence_index
|
|
6
|
+
from okstra_ctl.report_html.models import HumanReportView
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
def build_technical_verification_view(data: dict) -> HumanReportView:
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Technical verification phase
|
|
2
|
+
|
|
3
|
+
## Purpose and boundaries
|
|
4
|
+
|
|
5
|
+
This phase collects experimental evidence for unresolved technical facts. It does not rank candidates, select a direction, approve implementation or modify the source comparison. The lead chooses the continuation using `prompts/lead/phase-routing.md`.
|
|
6
|
+
|
|
7
|
+
## Input and preparation
|
|
8
|
+
|
|
9
|
+
The existing `--clarification-response` argument identifies this task's option-selection data record. `entry.prepare_technical_verification_input` checks the required argument before run creation. `entry.resolve_technical_verification_input` checks ownership, the canonical record name, schema and task key, then freezes the source-byte SHA-256 and eligible fact identities. Shared `technical_verification_facts.py` retains candidate safety and unresolved user-decision rules for both producer and consumer phases.
|
|
10
|
+
|
|
11
|
+
`entry.materialize_technical_input_packet` writes `state/technical-verification-input-<seq>.json` without replacing an existing snapshot and appends the input and experiment directory to the existing analysis packet. Artifact names, CLI inputs and preparation order are unchanged.
|
|
12
|
+
|
|
13
|
+
## Execution and output
|
|
14
|
+
|
|
15
|
+
`profile.md` owns experiment preparation, isolated source copies, command evidence, convergence and fact classification. `profile.json` owns role requirements. Worker write boundaries remain in the common invocation write contract.
|
|
16
|
+
|
|
17
|
+
The report's `technicalVerification` block preserves `sourceReport`, `sourceDataSha256`, `scope` and each fact's identity. Checks record hypothesis, procedure, confirming and rejecting signals, observations, limitations and commands. Status values are `supported`, `refuted`, `inconclusive` and `not-run`.
|
|
18
|
+
|
|
19
|
+
Report schemas remain common: `schemas/final-report-v2.0.schema.json` and `schemas/final-report-v3.0.schema.json`, including the `technicalVerification` definition and approval/continuation constraints. `report.py` and `report_assets/` own the phase body; the common report engine owns publication and page layout.
|
|
20
|
+
|
|
21
|
+
## Validation and failure behavior
|
|
22
|
+
|
|
23
|
+
`validation.validate_technical_verification_report` checks frozen-input metadata, exactly one check per input fact, unchanged fact identity and execution evidence. Observed checks need commands; supported checks cannot cite a nonzero exit code. Log and working-directory evidence stays inside the matching run's experiment sequence and rejects symlink escapes. `not-run` may omit commands.
|
|
24
|
+
|
|
25
|
+
Both `report_assembly.py` and `validators/validate-run.py` call this validation and the common `report_routing.technical_verification_routing_errors` check. Publication rejects invalid evidence before replacing the report. These checks do not prove that a declared command produced a log or sandbox arbitrary shell commands. Copy isolation and pre-execution plan quality remain worker instructions reviewed during convergence.
|
|
26
|
+
|
|
27
|
+
## Tests
|
|
28
|
+
|
|
29
|
+
`tests/test_technical_verification.py` covers input ownership, unsafe/unclassified sources, source preservation, exclusive snapshot creation, fact completeness, failed or missing commands, logs, sequence and symlink boundaries, full preparation and schema-v2/v3 report rendering. `tests/report/test_report_assembly.py::test_technical_assembly_requires_evidence_before_replacing_record` checks publication preserves an existing record when evidence fails.
|
|
30
|
+
|
|
31
|
+
## Guarantees
|
|
32
|
+
|
|
33
|
+
| ID | Guarantee | Enforcement |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| TV-1 | Report checks preserve the frozen input metadata and cover every input fact exactly once. | `scripts/okstra_ctl/phases/technical_verification/validation.py::validate_technical_verification_report` |
|
|
36
|
+
| TV-2 | Observed results require execution evidence within the matching experiment sequence. | `scripts/okstra_ctl/phases/technical_verification/validation.py::_check_execution_evidence` |
|
|
37
|
+
| TV-3 | The continuation targets implementation option selection. | `scripts/okstra_ctl/report_routing.py::technical_verification_routing_errors` |
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""관측 판정과 실행별 시험 증거의 일치 검사."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import re
|
|
5
|
+
from collections.abc import Mapping
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from okstra_ctl.implementation_direction import validate_task_artifact_path
|
|
10
|
+
from okstra_ctl.json_boundary import load_owned_object_snapshot
|
|
11
|
+
from okstra_ctl.technical_verification_facts import TechnicalVerificationError
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _check_execution_evidence(
|
|
15
|
+
check: Mapping[str, Any], project_root: Path, run_root: Path, seq: str
|
|
16
|
+
) -> list[str]:
|
|
17
|
+
"""관측 판정은 실행 기록과 실행별 시험 디렉터리를 요구한다."""
|
|
18
|
+
errors = []
|
|
19
|
+
commands = check.get("commands") or []
|
|
20
|
+
if check.get("status") != "not-run" and not commands:
|
|
21
|
+
errors.append(f"{check['id']}: an observed result requires command evidence")
|
|
22
|
+
for command in commands:
|
|
23
|
+
try:
|
|
24
|
+
log = project_root / command["logPath"]
|
|
25
|
+
experiment_root = run_root / "experiments" / seq
|
|
26
|
+
validate_task_artifact_path(log, experiment_root, "verification log")
|
|
27
|
+
if not log.read_text(encoding="utf-8").strip():
|
|
28
|
+
errors.append(f"{check['id']}: verification log is empty")
|
|
29
|
+
cwd = project_root / command["cwd"]
|
|
30
|
+
cwd.resolve(strict=True).relative_to(experiment_root.resolve(strict=True))
|
|
31
|
+
relative = cwd.relative_to(experiment_root)
|
|
32
|
+
current = run_root
|
|
33
|
+
for part in ("experiments", seq, *relative.parts):
|
|
34
|
+
current = current / part
|
|
35
|
+
if current.is_symlink():
|
|
36
|
+
raise TechnicalVerificationError(
|
|
37
|
+
"experiment cwd contains a symlink"
|
|
38
|
+
)
|
|
39
|
+
if not cwd.is_dir() or cwd.is_symlink():
|
|
40
|
+
errors.append(f"{check['id']}: experiment cwd must be a directory")
|
|
41
|
+
except (OSError, ValueError) as exc:
|
|
42
|
+
errors.append(f"{check['id']}: invalid execution evidence: {exc}")
|
|
43
|
+
if check.get("status") == "supported" and command.get("exitCode") != 0:
|
|
44
|
+
errors.append(f"{check['id']}: a supported result has a failed command")
|
|
45
|
+
return errors
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def validate_technical_verification_report(
|
|
49
|
+
data: Mapping[str, Any], report_path: Path, project_root: Path
|
|
50
|
+
) -> list[str]:
|
|
51
|
+
"""발행·최종 검증에서 같은 사실 집합과 실제 시험 산출물을 대조한다."""
|
|
52
|
+
if (data.get("header") or {}).get("taskType") != "technical-verification":
|
|
53
|
+
return []
|
|
54
|
+
match = re.fullmatch(
|
|
55
|
+
r"final-report-technical-verification-(\d{3,})\.data\.json", report_path.name
|
|
56
|
+
)
|
|
57
|
+
if match is None:
|
|
58
|
+
return ["technical verification report must use its canonical record path"]
|
|
59
|
+
run_root = report_path.parent.parent
|
|
60
|
+
path = run_root / "state" / f"technical-verification-input-{match[1]}.json"
|
|
61
|
+
try:
|
|
62
|
+
validate_task_artifact_path(path, run_root, "technical verification input")
|
|
63
|
+
source = load_owned_object_snapshot(
|
|
64
|
+
path, artifact="technical verification input"
|
|
65
|
+
).value
|
|
66
|
+
except (OSError, ValueError) as exc:
|
|
67
|
+
return [str(exc)]
|
|
68
|
+
block = data.get("technicalVerification") or {}
|
|
69
|
+
errors = []
|
|
70
|
+
for key in ("sourceReport", "sourceDataSha256", "scope"):
|
|
71
|
+
if block.get(key) != source.get(key):
|
|
72
|
+
errors.append(f"technicalVerification.{key} must match the run input")
|
|
73
|
+
expected = {fact["id"]: fact for fact in source["facts"]}
|
|
74
|
+
checks = block.get("checks") or []
|
|
75
|
+
ids = [check.get("id") for check in checks]
|
|
76
|
+
if len(ids) != len(set(ids)) or set(ids) != set(expected):
|
|
77
|
+
errors.append(
|
|
78
|
+
"technicalVerification.checks must cover each input fact exactly once"
|
|
79
|
+
)
|
|
80
|
+
for check in checks:
|
|
81
|
+
fact = expected.get(check.get("id"))
|
|
82
|
+
if fact is None:
|
|
83
|
+
continue
|
|
84
|
+
for key in ("candidateId", "factIndex", "fact"):
|
|
85
|
+
if check.get(key) != fact[key]:
|
|
86
|
+
errors.append(f"{check['id']}: {key} must preserve the input fact")
|
|
87
|
+
errors.extend(
|
|
88
|
+
_check_execution_evidence(check, project_root, run_root, match[1])
|
|
89
|
+
)
|
|
90
|
+
return errors
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""계획 승인 상태를 보고서와 사용자 응답에 동일하게 제공한다."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Mapping, Any
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass(frozen=True)
|
|
10
|
+
class PlanApprovalState:
|
|
11
|
+
option_names: tuple[str, ...]
|
|
12
|
+
recommended_option: str
|
|
13
|
+
disabled_reason: str
|
|
14
|
+
blocker_ids: tuple[str, ...]
|
|
15
|
+
show_option_selector: bool = True
|
|
16
|
+
reentry_command: str = ""
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def resolve_recommended_option(rec_name: str, names: tuple[str, ...]) -> str:
|
|
20
|
+
if rec_name in names:
|
|
21
|
+
return rec_name
|
|
22
|
+
matches = [
|
|
23
|
+
name
|
|
24
|
+
for name in names
|
|
25
|
+
if rec_name and (name.startswith(rec_name) or rec_name.startswith(name))
|
|
26
|
+
]
|
|
27
|
+
return matches[0] if len(matches) == 1 else names[0]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def plan_approval_state(data: dict) -> PlanApprovalState | None:
|
|
31
|
+
planning = data.get("implementationPlanning")
|
|
32
|
+
if not isinstance(planning, dict):
|
|
33
|
+
return None
|
|
34
|
+
blockers = tuple(
|
|
35
|
+
row["id"]
|
|
36
|
+
for row in data.get("clarificationItems", [])
|
|
37
|
+
if row.get("blocks") == "approval" and row.get("status") in {"open", "answered"}
|
|
38
|
+
)
|
|
39
|
+
reason = f"{len(blockers)} approval blocker(s) unresolved" if blockers else ""
|
|
40
|
+
if planning.get("planningContract") == "selected-direction":
|
|
41
|
+
if planning.get("outcome") == "direction-invalidated" and not reason:
|
|
42
|
+
reason = "selected direction invalidated"
|
|
43
|
+
task_key = (data.get("header") or {}).get("taskKey", "")
|
|
44
|
+
reentry_command = (
|
|
45
|
+
f"/okstra-run task-key={task_key} task-type=implementation-option-selection"
|
|
46
|
+
if planning.get("outcome") == "direction-invalidated" and task_key
|
|
47
|
+
else ""
|
|
48
|
+
)
|
|
49
|
+
return PlanApprovalState((), "", reason, blockers, False, reentry_command)
|
|
50
|
+
names = tuple(
|
|
51
|
+
row["name"]
|
|
52
|
+
for row in planning.get("optionCandidates", [])
|
|
53
|
+
if isinstance(row, dict) and row.get("name")
|
|
54
|
+
)
|
|
55
|
+
if not names:
|
|
56
|
+
return None
|
|
57
|
+
recommended = planning.get("recommendedOption", {}).get("name", "")
|
|
58
|
+
return PlanApprovalState(
|
|
59
|
+
names,
|
|
60
|
+
resolve_recommended_option(recommended, names),
|
|
61
|
+
reason,
|
|
62
|
+
blockers,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def plan_is_approved(report_data: Mapping[str, Any] | None) -> bool:
|
|
67
|
+
if not isinstance(report_data, Mapping):
|
|
68
|
+
return False
|
|
69
|
+
frontmatter = report_data.get("frontmatter")
|
|
70
|
+
return isinstance(frontmatter, Mapping) and frontmatter.get("approved") is True
|