phase-loop-runtime 0.2.0__py3-none-any.whl
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.
- phase_loop_runtime/__init__.py +20 -0
- phase_loop_runtime/_contract_docs/phase-loop/extraction-readiness.md +90 -0
- phase_loop_runtime/_contract_docs/phase-loop/granular-execution-policy.md +137 -0
- phase_loop_runtime/_contract_docs/phase-loop/harness-capability-matrix.md +510 -0
- phase_loop_runtime/_contract_docs/phase-loop/harness-skill-matrix.md +125 -0
- phase_loop_runtime/_contract_docs/phase-loop/harness-substrate-manifest.md +232 -0
- phase_loop_runtime/_contract_docs/phase-loop/pi-loop-control.md +247 -0
- phase_loop_runtime/_contract_docs/phase-loop/protocol.md +2759 -0
- phase_loop_runtime/_contract_docs/phase-loop/runtime-boundary.md +289 -0
- phase_loop_runtime/_contract_docs/phase-loop/spec-discovery-roots.md +47 -0
- phase_loop_runtime/_contract_docs/phase-loop/substrate-soak-governed-pipeline.md +42 -0
- phase_loop_runtime/_contract_docs/phase-loop/substrate-soak-portal-projection.md +34 -0
- phase_loop_runtime/_contract_docs/phase-loop/substrate-soak-regenesis.md +29 -0
- phase_loop_runtime/_contract_docs/phase-loop/substrate-soak-report.md +32 -0
- phase_loop_runtime/_contract_docs/runtime/verification-evidence-contract.md +52 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/borderline/borderline-mixed-signals/commands.txt +2 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/borderline/borderline-mixed-signals/manifest.json +16 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/borderline/borderline-mixed-signals/mixed.json +5 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/borderline/borderline-provider-timeout/manifest.json +16 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/borderline/borderline-provider-timeout/timeout-note.txt +2 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/borderline/borderline-redacted-summary/manifest.json +16 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/borderline/borderline-redacted-summary/redacted-summary.json +6 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/borderline/borderline-small-sample/manifest.json +16 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/borderline/borderline-small-sample/sample.json +7 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/borderline/borderline-threshold-edge/edge.txt +2 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/borderline/borderline-threshold-edge/manifest.json +16 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-duplicate-png/manifest.json +16 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-duplicate-png/shot-a.txt +1 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-duplicate-png/shot-b.txt +1 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-duplicate-png/shot-c.txt +1 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-missing-references/claimed-results.json +5 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-missing-references/manifest.json +16 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-subtle-low-variance/manifest.json +16 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-subtle-low-variance/metrics.json +9 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-templated-prose/findings.md +10 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-templated-prose/manifest.json +16 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-uniform-scores/manifest.json +16 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-uniform-scores/scores.json +4 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-uniform-scores/summary.txt +1 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-adoption-bundle/bundle-check.json +8 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-adoption-bundle/manifest.json +16 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-adoption-bundle/operator-note.txt +2 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-handoff-ledger/events-sample.jsonl +3 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-handoff-ledger/manifest.json +16 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-handoff-ledger/receipt.txt +1 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-runner-diff/evidence.json +13 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-runner-diff/manifest.json +16 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-runner-diff/summary.txt +2 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-test-matrix/manifest.json +16 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-test-matrix/matrix.json +9 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-test-matrix/notes.md +4 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-ui-screenshot-standin/console-summary.txt +2 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-ui-screenshot-standin/manifest.json +16 -0
- phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-ui-screenshot-standin/screenshot-standin.ppm +5 -0
- phase_loop_runtime/adoption_bundle.py +273 -0
- phase_loop_runtime/advisor_board/CONTRACTS.md +257 -0
- phase_loop_runtime/advisor_board/__init__.py +288 -0
- phase_loop_runtime/advisor_board/backing.py +137 -0
- phase_loop_runtime/advisor_board/backing_omnigent.py +498 -0
- phase_loop_runtime/advisor_board/config.py +225 -0
- phase_loop_runtime/advisor_board/events.py +115 -0
- phase_loop_runtime/advisor_board/fixtures/advisor-boards.example.toml +59 -0
- phase_loop_runtime/advisor_board/fixtures.py +91 -0
- phase_loop_runtime/advisor_board/harness_mapping.py +125 -0
- phase_loop_runtime/advisor_board/matrix.py +146 -0
- phase_loop_runtime/advisor_board/observability.py +481 -0
- phase_loop_runtime/advisor_board/presets.py +188 -0
- phase_loop_runtime/advisor_board/registries.py +309 -0
- phase_loop_runtime/advisor_board/resolver.py +253 -0
- phase_loop_runtime/advisor_board/schema.py +269 -0
- phase_loop_runtime/advisor_board/standin.py +166 -0
- phase_loop_runtime/advisor_board/validation.py +159 -0
- phase_loop_runtime/agent_runtime_provider.py +676 -0
- phase_loop_runtime/baml_modular.py +656 -0
- phase_loop_runtime/baml_src/dotfiles_adoption_manifest.baml +37 -0
- phase_loop_runtime/baml_src/dotfiles_c4_document.baml +14 -0
- phase_loop_runtime/baml_src/dotfiles_plan_manifest.baml +50 -0
- phase_loop_runtime/baml_src/dotfiles_runtime_projection.baml +16 -0
- phase_loop_runtime/baml_src/dotfiles_task_catalog.baml +20 -0
- phase_loop_runtime/baml_src/emit_phase_closeout.baml +86 -0
- phase_loop_runtime/baml_src/evaluate_suspected_fake_evidence.baml +36 -0
- phase_loop_runtime/baml_src/verification_evidence.baml +40 -0
- phase_loop_runtime/broker.py +181 -0
- phase_loop_runtime/build_bundle.py +294 -0
- phase_loop_runtime/capability_registry.py +835 -0
- phase_loop_runtime/classifier.py +87 -0
- phase_loop_runtime/claude_agent_view.py +625 -0
- phase_loop_runtime/claude_channel_sidecar.py +1086 -0
- phase_loop_runtime/cli.py +2599 -0
- phase_loop_runtime/closeout.py +865 -0
- phase_loop_runtime/closeout_classifier.py +120 -0
- phase_loop_runtime/closeout_evidence_audit.py +112 -0
- phase_loop_runtime/closeout_validation.py +144 -0
- phase_loop_runtime/closeout_validators.py +203 -0
- phase_loop_runtime/consiliency_gates.py +374 -0
- phase_loop_runtime/consiliency_ingest.py +399 -0
- phase_loop_runtime/consiliency_layout.py +176 -0
- phase_loop_runtime/consiliency_scaffold.py +305 -0
- phase_loop_runtime/cross_repo_channel.py +331 -0
- phase_loop_runtime/discovery.py +2368 -0
- phase_loop_runtime/dispatch_lock.py +167 -0
- phase_loop_runtime/doc_delta_validator.py +98 -0
- phase_loop_runtime/docs_audit.py +285 -0
- phase_loop_runtime/docs_freshness.py +468 -0
- phase_loop_runtime/docs_surfaces.py +150 -0
- phase_loop_runtime/dotfiles_profile_plugin.py +96 -0
- phase_loop_runtime/events.py +154 -0
- phase_loop_runtime/events_migration.py +96 -0
- phase_loop_runtime/evidence_audit.py +1082 -0
- phase_loop_runtime/evidence_audit_config.py +172 -0
- phase_loop_runtime/fleet_map.py +426 -0
- phase_loop_runtime/fleet_metrics.py +298 -0
- phase_loop_runtime/fleet_metrics_export.py +196 -0
- phase_loop_runtime/git_discipline.py +479 -0
- phase_loop_runtime/git_ops.py +122 -0
- phase_loop_runtime/git_topology.py +252 -0
- phase_loop_runtime/governed_bundle.py +137 -0
- phase_loop_runtime/governed_premerge.py +219 -0
- phase_loop_runtime/governed_review.py +264 -0
- phase_loop_runtime/handoff.py +932 -0
- phase_loop_runtime/handoff_path.py +14 -0
- phase_loop_runtime/injection.py +740 -0
- phase_loop_runtime/install_status.py +88 -0
- phase_loop_runtime/lane_scheduler.py +317 -0
- phase_loop_runtime/launcher.py +2760 -0
- phase_loop_runtime/lease_store.py +553 -0
- phase_loop_runtime/maintenance.py +401 -0
- phase_loop_runtime/migrate_handoffs.py +201 -0
- phase_loop_runtime/models.py +2144 -0
- phase_loop_runtime/observability.py +1290 -0
- phase_loop_runtime/panel_invoker.py +1638 -0
- phase_loop_runtime/phase_loop_drift_audit.py +388 -0
- phase_loop_runtime/phase_worktree_executor.py +433 -0
- phase_loop_runtime/pipeline_adapter/__init__.py +12 -0
- phase_loop_runtime/pipeline_adapter/branch_ops.py +274 -0
- phase_loop_runtime/pipeline_adapter/flag.py +55 -0
- phase_loop_runtime/pipeline_adapter/markers.py +13 -0
- phase_loop_runtime/pipeline_adapter/merge_policy.py +72 -0
- phase_loop_runtime/pipeline_adapter/ratification.py +100 -0
- phase_loop_runtime/pipeline_adapter/sibling_matcher.py +123 -0
- phase_loop_runtime/plan_ir.py +523 -0
- phase_loop_runtime/plan_manifest.py +415 -0
- phase_loop_runtime/planner_validation.py +176 -0
- phase_loop_runtime/profiles.py +462 -0
- phase_loop_runtime/prompts.py +365 -0
- phase_loop_runtime/provenance.py +165 -0
- phase_loop_runtime/publishing.py +339 -0
- phase_loop_runtime/py.typed +1 -0
- phase_loop_runtime/reconcile.py +1550 -0
- phase_loop_runtime/redaction.py +184 -0
- phase_loop_runtime/reflection_sync.py +293 -0
- phase_loop_runtime/release_guard.py +186 -0
- phase_loop_runtime/render.py +432 -0
- phase_loop_runtime/repo_validation.py +427 -0
- phase_loop_runtime/review_summary.py +150 -0
- phase_loop_runtime/roadmap_lint.py +425 -0
- phase_loop_runtime/route_log.py +59 -0
- phase_loop_runtime/route_policy/__init__.py +11 -0
- phase_loop_runtime/route_policy/fixtures/route_selection.golden.json +263 -0
- phase_loop_runtime/runner.py +8400 -0
- phase_loop_runtime/runtime_paths.py +225 -0
- phase_loop_runtime/runtime_projection.py +113 -0
- phase_loop_runtime/runtime_resources.py +36 -0
- phase_loop_runtime/schema_export.py +292 -0
- phase_loop_runtime/schemas/phase_loop_closeout.schema.json +366 -0
- phase_loop_runtime/skill_install.py +176 -0
- phase_loop_runtime/skill_inventory.py +662 -0
- phase_loop_runtime/skill_paths.py +42 -0
- phase_loop_runtime/skill_sources_plugin.py +37 -0
- phase_loop_runtime/skills_bundle/claude-advisor-board/README.md +1 -0
- phase_loop_runtime/skills_bundle/claude-advisor-board/SKILL.md +38 -0
- phase_loop_runtime/skills_bundle/claude-advisor-panel/README.md +1 -0
- phase_loop_runtime/skills_bundle/claude-advisor-panel/SKILL.md +38 -0
- phase_loop_runtime/skills_bundle/claude-execute-detailed/README.md +1 -0
- phase_loop_runtime/skills_bundle/claude-execute-detailed/SKILL.md +152 -0
- phase_loop_runtime/skills_bundle/claude-execute-phase/README.md +1 -0
- phase_loop_runtime/skills_bundle/claude-execute-phase/SKILL.md +745 -0
- phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/allocate_worktree_name.sh +33 -0
- phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/audit_lane_file_touches.py +197 -0
- phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/cleanup_lane_worktrees.sh +103 -0
- phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/parent_tree_leakage_check.sh +125 -0
- phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/post_merge_import_smoke.sh +62 -0
- phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/pre_merge_destructiveness_check.sh +127 -0
- phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/resolve_branch_from_sha.sh +51 -0
- phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/state.py +274 -0
- phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/sweep_stale_worktrees.sh +62 -0
- phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/team_teardown.sh +32 -0
- phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/validate_plan_doc.py +642 -0
- phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/verify_harness.sh +96 -0
- phase_loop_runtime/skills_bundle/claude-phase-loop/README.md +1 -0
- phase_loop_runtime/skills_bundle/claude-phase-loop/SKILL.md +115 -0
- phase_loop_runtime/skills_bundle/claude-phase-roadmap-builder/README.md +1 -0
- phase_loop_runtime/skills_bundle/claude-phase-roadmap-builder/SKILL.md +439 -0
- phase_loop_runtime/skills_bundle/claude-phase-roadmap-builder/assets/review_prompt.md +19 -0
- phase_loop_runtime/skills_bundle/claude-phase-roadmap-builder/references/parallelization-heuristics.md +111 -0
- phase_loop_runtime/skills_bundle/claude-phase-roadmap-builder/references/roadmap-template.md +193 -0
- phase_loop_runtime/skills_bundle/claude-phase-roadmap-builder/scripts/validate_roadmap.py +32 -0
- phase_loop_runtime/skills_bundle/claude-plan-detailed/README.md +1 -0
- phase_loop_runtime/skills_bundle/claude-plan-detailed/SKILL.md +334 -0
- phase_loop_runtime/skills_bundle/claude-plan-detailed/assets/review_prompt.md +25 -0
- phase_loop_runtime/skills_bundle/claude-plan-phase/README.md +1 -0
- phase_loop_runtime/skills_bundle/claude-plan-phase/SKILL.md +776 -0
- phase_loop_runtime/skills_bundle/claude-plan-phase/assets/review_prompt.md +17 -0
- phase_loop_runtime/skills_bundle/claude-plan-phase/scripts/validate_plan_doc.py +1092 -0
- phase_loop_runtime/skills_bundle/claude-run-train/README.md +1 -0
- phase_loop_runtime/skills_bundle/claude-run-train/SKILL.md +75 -0
- phase_loop_runtime/skills_bundle/claude-skill-editor/README.md +1 -0
- phase_loop_runtime/skills_bundle/claude-skill-editor/SKILL.md +243 -0
- phase_loop_runtime/skills_bundle/claude-skill-editor/assets/editor_prompt.md +72 -0
- phase_loop_runtime/skills_bundle/claude-skill-improvement-planner/README.md +1 -0
- phase_loop_runtime/skills_bundle/claude-skill-improvement-planner/SKILL.md +249 -0
- phase_loop_runtime/skills_bundle/claude-skill-improvement-planner/assets/aggregator_prompt.md +79 -0
- phase_loop_runtime/skills_bundle/claude-task-contextualizer/README.md +1 -0
- phase_loop_runtime/skills_bundle/claude-task-contextualizer/SKILL.md +74 -0
- phase_loop_runtime/skills_bundle/claude-task-contextualizer/references/task-templates.md +103 -0
- phase_loop_runtime/skills_bundle/codex-advisor-board/README.md +1 -0
- phase_loop_runtime/skills_bundle/codex-advisor-board/SKILL.md +38 -0
- phase_loop_runtime/skills_bundle/codex-advisor-panel/README.md +1 -0
- phase_loop_runtime/skills_bundle/codex-advisor-panel/SKILL.md +38 -0
- phase_loop_runtime/skills_bundle/codex-execute-detailed/README.md +1 -0
- phase_loop_runtime/skills_bundle/codex-execute-detailed/SKILL.md +154 -0
- phase_loop_runtime/skills_bundle/codex-execute-phase/README.md +1 -0
- phase_loop_runtime/skills_bundle/codex-execute-phase/SKILL.md +231 -0
- phase_loop_runtime/skills_bundle/codex-execute-phase/scripts/allocate_worktree_name.sh +33 -0
- phase_loop_runtime/skills_bundle/codex-execute-phase/scripts/audit_lane_file_touches.py +197 -0
- phase_loop_runtime/skills_bundle/codex-execute-phase/scripts/cleanup_lane_worktrees.sh +103 -0
- phase_loop_runtime/skills_bundle/codex-execute-phase/scripts/parent_tree_leakage_check.sh +125 -0
- phase_loop_runtime/skills_bundle/codex-execute-phase/scripts/post_merge_import_smoke.sh +62 -0
- phase_loop_runtime/skills_bundle/codex-execute-phase/scripts/pre_merge_destructiveness_check.sh +127 -0
- phase_loop_runtime/skills_bundle/codex-execute-phase/scripts/resolve_branch_from_sha.sh +51 -0
- phase_loop_runtime/skills_bundle/codex-execute-phase/scripts/state.py +274 -0
- phase_loop_runtime/skills_bundle/codex-execute-phase/scripts/sweep_stale_worktrees.sh +62 -0
- phase_loop_runtime/skills_bundle/codex-execute-phase/scripts/team_teardown.sh +32 -0
- phase_loop_runtime/skills_bundle/codex-execute-phase/scripts/validate_plan_doc.py +642 -0
- phase_loop_runtime/skills_bundle/codex-execute-phase/scripts/verify_harness.sh +96 -0
- phase_loop_runtime/skills_bundle/codex-phase-loop/README.md +1 -0
- phase_loop_runtime/skills_bundle/codex-phase-loop/SKILL.md +248 -0
- phase_loop_runtime/skills_bundle/codex-phase-roadmap-builder/README.md +1 -0
- phase_loop_runtime/skills_bundle/codex-phase-roadmap-builder/SKILL.md +150 -0
- phase_loop_runtime/skills_bundle/codex-phase-roadmap-builder/assets/review_prompt.md +19 -0
- phase_loop_runtime/skills_bundle/codex-phase-roadmap-builder/references/parallelization-heuristics.md +111 -0
- phase_loop_runtime/skills_bundle/codex-phase-roadmap-builder/references/roadmap-template.md +193 -0
- phase_loop_runtime/skills_bundle/codex-phase-roadmap-builder/scripts/validate_roadmap.py +32 -0
- phase_loop_runtime/skills_bundle/codex-plan-detailed/README.md +1 -0
- phase_loop_runtime/skills_bundle/codex-plan-detailed/SKILL.md +119 -0
- phase_loop_runtime/skills_bundle/codex-plan-detailed/assets/review_prompt.md +25 -0
- phase_loop_runtime/skills_bundle/codex-plan-phase/README.md +1 -0
- phase_loop_runtime/skills_bundle/codex-plan-phase/SKILL.md +307 -0
- phase_loop_runtime/skills_bundle/codex-plan-phase/assets/review_prompt.md +17 -0
- phase_loop_runtime/skills_bundle/codex-plan-phase/scripts/validate_plan_doc.py +1092 -0
- phase_loop_runtime/skills_bundle/codex-run-train/README.md +1 -0
- phase_loop_runtime/skills_bundle/codex-run-train/SKILL.md +75 -0
- phase_loop_runtime/skills_bundle/codex-skill-editor/README.md +1 -0
- phase_loop_runtime/skills_bundle/codex-skill-editor/SKILL.md +94 -0
- phase_loop_runtime/skills_bundle/codex-skill-editor/assets/editor_prompt.md +72 -0
- phase_loop_runtime/skills_bundle/codex-skill-improvement-planner/README.md +1 -0
- phase_loop_runtime/skills_bundle/codex-skill-improvement-planner/SKILL.md +114 -0
- phase_loop_runtime/skills_bundle/codex-skill-improvement-planner/assets/aggregator_prompt.md +79 -0
- phase_loop_runtime/skills_bundle/codex-task-contextualizer/README.md +1 -0
- phase_loop_runtime/skills_bundle/codex-task-contextualizer/SKILL.md +102 -0
- phase_loop_runtime/skills_bundle/codex-task-contextualizer/references/task-templates.md +103 -0
- phase_loop_runtime/skills_bundle/gemini-advisor-board/README.md +1 -0
- phase_loop_runtime/skills_bundle/gemini-advisor-board/SKILL.md +38 -0
- phase_loop_runtime/skills_bundle/gemini-advisor-panel/README.md +1 -0
- phase_loop_runtime/skills_bundle/gemini-advisor-panel/SKILL.md +38 -0
- phase_loop_runtime/skills_bundle/gemini-execute-detailed/README.md +1 -0
- phase_loop_runtime/skills_bundle/gemini-execute-detailed/SKILL.md +144 -0
- phase_loop_runtime/skills_bundle/gemini-execute-phase/README.md +1 -0
- phase_loop_runtime/skills_bundle/gemini-execute-phase/SKILL.md +198 -0
- phase_loop_runtime/skills_bundle/gemini-execute-phase/scripts/allocate_worktree_name.sh +33 -0
- phase_loop_runtime/skills_bundle/gemini-execute-phase/scripts/audit_lane_file_touches.py +197 -0
- phase_loop_runtime/skills_bundle/gemini-execute-phase/scripts/cleanup_lane_worktrees.sh +103 -0
- phase_loop_runtime/skills_bundle/gemini-execute-phase/scripts/parent_tree_leakage_check.sh +125 -0
- phase_loop_runtime/skills_bundle/gemini-execute-phase/scripts/post_merge_import_smoke.sh +62 -0
- phase_loop_runtime/skills_bundle/gemini-execute-phase/scripts/pre_merge_destructiveness_check.sh +127 -0
- phase_loop_runtime/skills_bundle/gemini-execute-phase/scripts/resolve_branch_from_sha.sh +51 -0
- phase_loop_runtime/skills_bundle/gemini-execute-phase/scripts/state.py +274 -0
- phase_loop_runtime/skills_bundle/gemini-execute-phase/scripts/sweep_stale_worktrees.sh +62 -0
- phase_loop_runtime/skills_bundle/gemini-execute-phase/scripts/team_teardown.sh +32 -0
- phase_loop_runtime/skills_bundle/gemini-execute-phase/scripts/validate_plan_doc.py +642 -0
- phase_loop_runtime/skills_bundle/gemini-execute-phase/scripts/verify_harness.sh +96 -0
- phase_loop_runtime/skills_bundle/gemini-phase-loop/README.md +1 -0
- phase_loop_runtime/skills_bundle/gemini-phase-loop/SKILL.md +111 -0
- phase_loop_runtime/skills_bundle/gemini-phase-roadmap-builder/README.md +1 -0
- phase_loop_runtime/skills_bundle/gemini-phase-roadmap-builder/SKILL.md +147 -0
- phase_loop_runtime/skills_bundle/gemini-phase-roadmap-builder/assets/review_prompt.md +19 -0
- phase_loop_runtime/skills_bundle/gemini-phase-roadmap-builder/references/parallelization-heuristics.md +111 -0
- phase_loop_runtime/skills_bundle/gemini-phase-roadmap-builder/references/roadmap-template.md +193 -0
- phase_loop_runtime/skills_bundle/gemini-phase-roadmap-builder/scripts/validate_roadmap.py +32 -0
- phase_loop_runtime/skills_bundle/gemini-plan-detailed/README.md +1 -0
- phase_loop_runtime/skills_bundle/gemini-plan-detailed/SKILL.md +119 -0
- phase_loop_runtime/skills_bundle/gemini-plan-detailed/assets/review_prompt.md +25 -0
- phase_loop_runtime/skills_bundle/gemini-plan-phase/README.md +1 -0
- phase_loop_runtime/skills_bundle/gemini-plan-phase/SKILL.md +217 -0
- phase_loop_runtime/skills_bundle/gemini-plan-phase/assets/review_prompt.md +17 -0
- phase_loop_runtime/skills_bundle/gemini-plan-phase/scripts/validate_plan_doc.py +1092 -0
- phase_loop_runtime/skills_bundle/gemini-run-train/README.md +1 -0
- phase_loop_runtime/skills_bundle/gemini-run-train/SKILL.md +75 -0
- phase_loop_runtime/skills_bundle/gemini-skill-editor/README.md +1 -0
- phase_loop_runtime/skills_bundle/gemini-skill-editor/SKILL.md +87 -0
- phase_loop_runtime/skills_bundle/gemini-skill-editor/assets/editor_prompt.md +72 -0
- phase_loop_runtime/skills_bundle/gemini-skill-improvement-planner/README.md +1 -0
- phase_loop_runtime/skills_bundle/gemini-skill-improvement-planner/SKILL.md +109 -0
- phase_loop_runtime/skills_bundle/gemini-skill-improvement-planner/assets/aggregator_prompt.md +79 -0
- phase_loop_runtime/skills_bundle/gemini-task-contextualizer/README.md +1 -0
- phase_loop_runtime/skills_bundle/gemini-task-contextualizer/SKILL.md +98 -0
- phase_loop_runtime/skills_bundle/gemini-task-contextualizer/references/task-templates.md +103 -0
- phase_loop_runtime/skills_bundle/opencode-advisor-board/README.md +1 -0
- phase_loop_runtime/skills_bundle/opencode-advisor-board/SKILL.md +38 -0
- phase_loop_runtime/skills_bundle/opencode-advisor-panel/README.md +1 -0
- phase_loop_runtime/skills_bundle/opencode-advisor-panel/SKILL.md +38 -0
- phase_loop_runtime/skills_bundle/opencode-execute-detailed/README.md +1 -0
- phase_loop_runtime/skills_bundle/opencode-execute-detailed/SKILL.md +144 -0
- phase_loop_runtime/skills_bundle/opencode-execute-phase/README.md +1 -0
- phase_loop_runtime/skills_bundle/opencode-execute-phase/SKILL.md +196 -0
- phase_loop_runtime/skills_bundle/opencode-execute-phase/scripts/allocate_worktree_name.sh +33 -0
- phase_loop_runtime/skills_bundle/opencode-execute-phase/scripts/audit_lane_file_touches.py +197 -0
- phase_loop_runtime/skills_bundle/opencode-execute-phase/scripts/cleanup_lane_worktrees.sh +103 -0
- phase_loop_runtime/skills_bundle/opencode-execute-phase/scripts/parent_tree_leakage_check.sh +125 -0
- phase_loop_runtime/skills_bundle/opencode-execute-phase/scripts/post_merge_import_smoke.sh +62 -0
- phase_loop_runtime/skills_bundle/opencode-execute-phase/scripts/pre_merge_destructiveness_check.sh +127 -0
- phase_loop_runtime/skills_bundle/opencode-execute-phase/scripts/resolve_branch_from_sha.sh +51 -0
- phase_loop_runtime/skills_bundle/opencode-execute-phase/scripts/state.py +274 -0
- phase_loop_runtime/skills_bundle/opencode-execute-phase/scripts/sweep_stale_worktrees.sh +62 -0
- phase_loop_runtime/skills_bundle/opencode-execute-phase/scripts/team_teardown.sh +32 -0
- phase_loop_runtime/skills_bundle/opencode-execute-phase/scripts/validate_plan_doc.py +642 -0
- phase_loop_runtime/skills_bundle/opencode-execute-phase/scripts/verify_harness.sh +96 -0
- phase_loop_runtime/skills_bundle/opencode-phase-loop/README.md +1 -0
- phase_loop_runtime/skills_bundle/opencode-phase-loop/SKILL.md +113 -0
- phase_loop_runtime/skills_bundle/opencode-phase-roadmap-builder/README.md +1 -0
- phase_loop_runtime/skills_bundle/opencode-phase-roadmap-builder/SKILL.md +147 -0
- phase_loop_runtime/skills_bundle/opencode-phase-roadmap-builder/assets/review_prompt.md +19 -0
- phase_loop_runtime/skills_bundle/opencode-phase-roadmap-builder/references/parallelization-heuristics.md +111 -0
- phase_loop_runtime/skills_bundle/opencode-phase-roadmap-builder/references/roadmap-template.md +193 -0
- phase_loop_runtime/skills_bundle/opencode-phase-roadmap-builder/scripts/validate_roadmap.py +32 -0
- phase_loop_runtime/skills_bundle/opencode-plan-detailed/README.md +1 -0
- phase_loop_runtime/skills_bundle/opencode-plan-detailed/SKILL.md +119 -0
- phase_loop_runtime/skills_bundle/opencode-plan-detailed/assets/review_prompt.md +25 -0
- phase_loop_runtime/skills_bundle/opencode-plan-phase/README.md +1 -0
- phase_loop_runtime/skills_bundle/opencode-plan-phase/SKILL.md +211 -0
- phase_loop_runtime/skills_bundle/opencode-plan-phase/assets/review_prompt.md +17 -0
- phase_loop_runtime/skills_bundle/opencode-plan-phase/scripts/validate_plan_doc.py +1092 -0
- phase_loop_runtime/skills_bundle/opencode-run-train/README.md +1 -0
- phase_loop_runtime/skills_bundle/opencode-run-train/SKILL.md +75 -0
- phase_loop_runtime/skills_bundle/opencode-skill-editor/README.md +1 -0
- phase_loop_runtime/skills_bundle/opencode-skill-editor/SKILL.md +87 -0
- phase_loop_runtime/skills_bundle/opencode-skill-editor/assets/editor_prompt.md +72 -0
- phase_loop_runtime/skills_bundle/opencode-skill-improvement-planner/README.md +1 -0
- phase_loop_runtime/skills_bundle/opencode-skill-improvement-planner/SKILL.md +109 -0
- phase_loop_runtime/skills_bundle/opencode-skill-improvement-planner/assets/aggregator_prompt.md +79 -0
- phase_loop_runtime/skills_bundle/opencode-task-contextualizer/README.md +1 -0
- phase_loop_runtime/skills_bundle/opencode-task-contextualizer/SKILL.md +98 -0
- phase_loop_runtime/skills_bundle/opencode-task-contextualizer/references/task-templates.md +103 -0
- phase_loop_runtime/state.py +156 -0
- phase_loop_runtime/state_degradation.py +136 -0
- phase_loop_runtime/state_ops.py +676 -0
- phase_loop_runtime/train_ledger.py +215 -0
- phase_loop_runtime/train_roadmap.py +339 -0
- phase_loop_runtime/train_runner.py +1197 -0
- phase_loop_runtime/verification_evidence.py +650 -0
- phase_loop_runtime/verification_evidence_validator.py +75 -0
- phase_loop_runtime/visual_evidence_validator.py +36 -0
- phase_loop_runtime/worker_pool.py +123 -0
- phase_loop_runtime/worktree_index.py +270 -0
- phase_loop_runtime-0.2.0.data/data/share/phase-loop-runtime/protocol/protocol.md +2475 -0
- phase_loop_runtime-0.2.0.dist-info/METADATA +106 -0
- phase_loop_runtime-0.2.0.dist-info/RECORD +370 -0
- phase_loop_runtime-0.2.0.dist-info/WHEEL +5 -0
- phase_loop_runtime-0.2.0.dist-info/entry_points.txt +9 -0
- phase_loop_runtime-0.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# allocate_worktree_name.sh — emit a collision-impossible worktree name
|
|
3
|
+
# for a swim-lane teammate.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# allocate_worktree_name.sh <sl-id>
|
|
7
|
+
#
|
|
8
|
+
# <sl-id> Lane identifier, e.g. "sl-1" or "sl-2b".
|
|
9
|
+
#
|
|
10
|
+
# Emits exactly one line to stdout:
|
|
11
|
+
# lane-<sl-id>-<UTC-YYYYMMDDHHMMSS>-<4char-random>
|
|
12
|
+
#
|
|
13
|
+
# Rationale: the default `lane-<sl-id>` naming is not unique across rapid
|
|
14
|
+
# consecutive dispatch of in-process teammates — two teammates spawned in
|
|
15
|
+
# the same message can race on the same EnterWorktree slot. The 4-char
|
|
16
|
+
# random suffix + UTC timestamp eliminates the race by construction.
|
|
17
|
+
|
|
18
|
+
set -euo pipefail
|
|
19
|
+
|
|
20
|
+
if [[ $# -ne 1 ]]; then
|
|
21
|
+
echo "usage: allocate_worktree_name.sh <sl-id>" >&2
|
|
22
|
+
exit 2
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
sl_id="$1"
|
|
26
|
+
ts="$(date -u +%Y%m%dT%H%M%S)"
|
|
27
|
+
rand="$(tr -dc 'a-z0-9' </dev/urandom | head -c 4 || true)"
|
|
28
|
+
if [[ -z "$rand" ]]; then
|
|
29
|
+
# Extremely unlikely; fall back to $RANDOM-derived 4 chars.
|
|
30
|
+
rand="$(printf "%04x" "$((RANDOM & 0xFFFF))")"
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
echo "lane-${sl_id}-${ts}-${rand}"
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
audit_lane_file_touches.py — audit a lane's commit against the plan's
|
|
4
|
+
disjoint-owned-files contract.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
audit_lane_file_touches.py <lane-sha> <plan-doc-path> <this-lane-id>
|
|
8
|
+
|
|
9
|
+
Emits EXACTLY one token on stdout, exit 0 always (verdict is on stdout
|
|
10
|
+
for the orchestrator to act on):
|
|
11
|
+
|
|
12
|
+
CLEAN
|
|
13
|
+
- Every file touched by <lane-sha> (vs its first-parent ancestor)
|
|
14
|
+
falls within <this-lane-id>'s `Owned files` globs from the plan
|
|
15
|
+
doc.
|
|
16
|
+
|
|
17
|
+
PEER_INTRUSION
|
|
18
|
+
- One or more files touched match some OTHER lane's `Owned files`
|
|
19
|
+
globs. The lane wandered into a peer's territory. Orchestrator
|
|
20
|
+
surfaces to user for merge/no-merge decision — defensive cross-
|
|
21
|
+
lane test-mock edits happen and are usually benign, but should be
|
|
22
|
+
reviewed rather than surfacing as a later merge conflict.
|
|
23
|
+
|
|
24
|
+
ORPHAN_FILES
|
|
25
|
+
- One or more files touched fall OUTSIDE every lane's globs. The
|
|
26
|
+
teammate worked outside any declared lane scope — probable bug.
|
|
27
|
+
|
|
28
|
+
Any combination of intrusion + orphan is reported with intrusion winning.
|
|
29
|
+
Details (which peer, which files) are written to stderr.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
import re
|
|
35
|
+
import subprocess
|
|
36
|
+
import sys
|
|
37
|
+
from pathlib import Path
|
|
38
|
+
from typing import Dict, List, Optional, Set
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
_SL_SECTION_RE = re.compile(r"^###\s+(SL-\d+)\b.*$", re.MULTILINE)
|
|
42
|
+
_OWNED_BULLET_RE = re.compile(
|
|
43
|
+
r"^\s*-\s*\*\*Owned files\*\*\s*:\s*(.*?)\s*$",
|
|
44
|
+
re.IGNORECASE,
|
|
45
|
+
)
|
|
46
|
+
_CODE_TOKEN_RE = re.compile(r"`([^`]+)`")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _fail(msg: str) -> None:
|
|
50
|
+
print(f"audit_lane_file_touches: {msg}", file=sys.stderr)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _read(path: Path) -> str:
|
|
54
|
+
try:
|
|
55
|
+
return path.read_text(encoding="utf-8")
|
|
56
|
+
except Exception as exc:
|
|
57
|
+
_fail(f"cannot read {path}: {exc}")
|
|
58
|
+
sys.exit(2)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _extract_lanes_body(src: str) -> str:
|
|
62
|
+
"""Return the body between '## Lanes' and the next '## '."""
|
|
63
|
+
lines = src.splitlines()
|
|
64
|
+
out: List[str] = []
|
|
65
|
+
in_section = False
|
|
66
|
+
for line in lines:
|
|
67
|
+
if line.startswith("## ") and line.strip() == "## Lanes":
|
|
68
|
+
in_section = True
|
|
69
|
+
continue
|
|
70
|
+
if in_section and line.startswith("## "):
|
|
71
|
+
break
|
|
72
|
+
if in_section:
|
|
73
|
+
out.append(line)
|
|
74
|
+
return "\n".join(out)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _parse_owned_globs(lanes_body: str) -> Dict[str, List[str]]:
|
|
78
|
+
"""Map SL-N -> list of owned globs as declared in the plan."""
|
|
79
|
+
matches = list(_SL_SECTION_RE.finditer(lanes_body))
|
|
80
|
+
result: Dict[str, List[str]] = {}
|
|
81
|
+
for idx, m in enumerate(matches):
|
|
82
|
+
sl_id = m.group(1)
|
|
83
|
+
start = m.end()
|
|
84
|
+
end = matches[idx + 1].start() if idx + 1 < len(matches) else len(lanes_body)
|
|
85
|
+
body = lanes_body[start:end]
|
|
86
|
+
globs: List[str] = []
|
|
87
|
+
for line in body.splitlines():
|
|
88
|
+
mb = _OWNED_BULLET_RE.match(line)
|
|
89
|
+
if not mb:
|
|
90
|
+
continue
|
|
91
|
+
raw = mb.group(1)
|
|
92
|
+
tokens = _CODE_TOKEN_RE.findall(raw)
|
|
93
|
+
globs.extend(t.strip() for t in tokens if t.strip())
|
|
94
|
+
# Drop annotation-only items like "(NEW)" / "(DELETE)".
|
|
95
|
+
globs = [
|
|
96
|
+
g.split()[0].strip() for g in globs
|
|
97
|
+
if g and not g.startswith("(")
|
|
98
|
+
]
|
|
99
|
+
result[sl_id] = globs
|
|
100
|
+
return result
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _glob_to_regex(pattern: str) -> re.Pattern:
|
|
104
|
+
"""Minimal glob → regex. ** → any depth; * → any non-/; ? → one non-/."""
|
|
105
|
+
s = pattern.strip("`").strip()
|
|
106
|
+
esc = re.escape(s)
|
|
107
|
+
esc = esc.replace(r"\*\*", ".*").replace(r"\*", "[^/]*").replace(r"\?", "[^/]")
|
|
108
|
+
return re.compile("^" + esc + "$")
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _touched_files(sha: str) -> List[str]:
|
|
112
|
+
"""Files changed by <sha> relative to its first parent."""
|
|
113
|
+
try:
|
|
114
|
+
r = subprocess.run(
|
|
115
|
+
["git", "diff", "--name-only", f"{sha}^..{sha}"],
|
|
116
|
+
capture_output=True, text=True, check=True,
|
|
117
|
+
)
|
|
118
|
+
except subprocess.CalledProcessError:
|
|
119
|
+
# Commit has no parent (e.g., root) — fall back to diff against empty tree.
|
|
120
|
+
r = subprocess.run(
|
|
121
|
+
["git", "show", "--name-only", "--pretty=", sha],
|
|
122
|
+
capture_output=True, text=True, check=True,
|
|
123
|
+
)
|
|
124
|
+
return [line for line in r.stdout.splitlines() if line.strip()]
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def main(argv: List[str]) -> int:
|
|
128
|
+
if len(argv) != 4:
|
|
129
|
+
_fail("usage: audit_lane_file_touches.py <lane-sha> <plan-doc-path> <this-lane-id>")
|
|
130
|
+
return 2
|
|
131
|
+
|
|
132
|
+
lane_sha = argv[1]
|
|
133
|
+
plan_path = Path(argv[2])
|
|
134
|
+
this_lane = argv[3]
|
|
135
|
+
|
|
136
|
+
if not plan_path.exists():
|
|
137
|
+
_fail(f"plan doc not found: {plan_path}")
|
|
138
|
+
return 2
|
|
139
|
+
|
|
140
|
+
src = _read(plan_path)
|
|
141
|
+
lanes_body = _extract_lanes_body(src)
|
|
142
|
+
owned_map = _parse_owned_globs(lanes_body)
|
|
143
|
+
|
|
144
|
+
if this_lane not in owned_map:
|
|
145
|
+
_fail(f"lane {this_lane} not found in plan doc's `## Lanes` section")
|
|
146
|
+
return 2
|
|
147
|
+
|
|
148
|
+
# Compile regexes per lane.
|
|
149
|
+
compiled: Dict[str, List[re.Pattern]] = {
|
|
150
|
+
sl: [_glob_to_regex(g) for g in globs]
|
|
151
|
+
for sl, globs in owned_map.items()
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
touched = _touched_files(lane_sha)
|
|
155
|
+
|
|
156
|
+
def match_any(path: str, pats: List[re.Pattern]) -> bool:
|
|
157
|
+
return any(p.match(path) for p in pats)
|
|
158
|
+
|
|
159
|
+
intrusions: Dict[str, List[str]] = {}
|
|
160
|
+
orphans: List[str] = []
|
|
161
|
+
clean: List[str] = []
|
|
162
|
+
for path in touched:
|
|
163
|
+
if match_any(path, compiled[this_lane]):
|
|
164
|
+
clean.append(path)
|
|
165
|
+
continue
|
|
166
|
+
peer_hit: Optional[str] = None
|
|
167
|
+
for sl, pats in compiled.items():
|
|
168
|
+
if sl == this_lane:
|
|
169
|
+
continue
|
|
170
|
+
if match_any(path, pats):
|
|
171
|
+
peer_hit = sl
|
|
172
|
+
break
|
|
173
|
+
if peer_hit is not None:
|
|
174
|
+
intrusions.setdefault(peer_hit, []).append(path)
|
|
175
|
+
else:
|
|
176
|
+
orphans.append(path)
|
|
177
|
+
|
|
178
|
+
# Emit verdict. Intrusion takes precedence over orphan (intrusion is more actionable).
|
|
179
|
+
if intrusions:
|
|
180
|
+
for peer, paths in sorted(intrusions.items()):
|
|
181
|
+
_fail(f"{this_lane} touched files owned by {peer}: {paths}")
|
|
182
|
+
if orphans:
|
|
183
|
+
_fail(f"{this_lane} also touched orphan files (no lane owns): {orphans}")
|
|
184
|
+
print("PEER_INTRUSION")
|
|
185
|
+
return 0
|
|
186
|
+
|
|
187
|
+
if orphans:
|
|
188
|
+
_fail(f"{this_lane} touched files outside any lane's Owned files: {orphans}")
|
|
189
|
+
print("ORPHAN_FILES")
|
|
190
|
+
return 0
|
|
191
|
+
|
|
192
|
+
print("CLEAN")
|
|
193
|
+
return 0
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
if __name__ == "__main__":
|
|
197
|
+
sys.exit(main(sys.argv))
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# cleanup_lane_worktrees.sh — remove lane worktrees and their auto-named
|
|
3
|
+
# branches after a phase merges.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# cleanup_lane_worktrees.sh <branch-pattern>
|
|
7
|
+
#
|
|
8
|
+
# <branch-pattern> Glob applied to each worktree's branch name (the
|
|
9
|
+
# short name, not refs/heads/…). Defaults to
|
|
10
|
+
# 'worktree-*' so the common case works with no arg.
|
|
11
|
+
#
|
|
12
|
+
# Behavior:
|
|
13
|
+
# - Enumerates every worktree via `git worktree list --porcelain`.
|
|
14
|
+
# - Skips the orchestrator's own worktree (identified by matching the
|
|
15
|
+
# `git rev-parse --show-toplevel` of the current cwd).
|
|
16
|
+
# - For each remaining worktree whose branch matches <branch-pattern>:
|
|
17
|
+
# * `git worktree remove --force <path>`
|
|
18
|
+
# * If the branch also matches 'worktree-*' or 'phase/*/sl-*',
|
|
19
|
+
# `git branch -D <branch>` (salvage footgun: -D, not -d).
|
|
20
|
+
# - Never blocks the phase: exit 0 even on individual cleanup failures;
|
|
21
|
+
# each failure is logged to stderr.
|
|
22
|
+
#
|
|
23
|
+
# Rationale: Step 7 post-merge cleanup. Keeps human-named branches intact
|
|
24
|
+
# (skills/*, feature/*, fix/*) even when accidentally matched by glob.
|
|
25
|
+
|
|
26
|
+
set -uo pipefail
|
|
27
|
+
|
|
28
|
+
pattern="${1:-worktree-*}"
|
|
29
|
+
|
|
30
|
+
# Resolve orchestrator's anchored worktree so we don't try to delete it.
|
|
31
|
+
orch_root=""
|
|
32
|
+
if orch_root="$(git rev-parse --show-toplevel 2>/dev/null)"; then
|
|
33
|
+
:
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
removed=0
|
|
37
|
+
skipped=0
|
|
38
|
+
|
|
39
|
+
# Parse `git worktree list --porcelain`. Each record is separated by a blank line:
|
|
40
|
+
# worktree <path>
|
|
41
|
+
# HEAD <sha>
|
|
42
|
+
# branch refs/heads/<name>
|
|
43
|
+
while IFS= read -r block; do
|
|
44
|
+
# `git worktree list --porcelain` actually yields one line per key; we
|
|
45
|
+
# collapse them back into records here.
|
|
46
|
+
[[ -z "$block" ]] && continue
|
|
47
|
+
key="${block%% *}"
|
|
48
|
+
value="${block#* }"
|
|
49
|
+
case "$key" in
|
|
50
|
+
worktree)
|
|
51
|
+
wt_path="$value"
|
|
52
|
+
wt_branch=""
|
|
53
|
+
;;
|
|
54
|
+
branch)
|
|
55
|
+
# value looks like 'refs/heads/worktree-sl-1'
|
|
56
|
+
wt_branch="${value#refs/heads/}"
|
|
57
|
+
;;
|
|
58
|
+
HEAD) ;; # ignore
|
|
59
|
+
detached) wt_branch="" ;;
|
|
60
|
+
esac
|
|
61
|
+
# When we hit a new `worktree` line, the previous record is complete —
|
|
62
|
+
# but the block-mode loop above feeds us line-by-line. We process each
|
|
63
|
+
# line and finalize when we hit a record boundary below.
|
|
64
|
+
done < <(git worktree list --porcelain)
|
|
65
|
+
|
|
66
|
+
# Process each worktree block (re-read cleanly; the above was an artifact).
|
|
67
|
+
while IFS= read -r path; do
|
|
68
|
+
[[ -z "$path" ]] && continue
|
|
69
|
+
# Skip orchestrator's anchor.
|
|
70
|
+
if [[ "$path" == "$orch_root" ]]; then
|
|
71
|
+
skipped=$((skipped + 1))
|
|
72
|
+
continue
|
|
73
|
+
fi
|
|
74
|
+
# Resolve this worktree's branch.
|
|
75
|
+
branch="$(git -C "$path" rev-parse --abbrev-ref HEAD 2>/dev/null || echo '')"
|
|
76
|
+
if [[ -z "$branch" || "$branch" == "HEAD" ]]; then
|
|
77
|
+
# Detached HEAD worktree — skip.
|
|
78
|
+
skipped=$((skipped + 1))
|
|
79
|
+
continue
|
|
80
|
+
fi
|
|
81
|
+
# Apply the branch pattern.
|
|
82
|
+
# shellcheck disable=SC2053
|
|
83
|
+
if [[ "$branch" != $pattern ]]; then
|
|
84
|
+
skipped=$((skipped + 1))
|
|
85
|
+
continue
|
|
86
|
+
fi
|
|
87
|
+
# Remove the worktree.
|
|
88
|
+
if git worktree remove --force "$path" 2>/dev/null; then
|
|
89
|
+
removed=$((removed + 1))
|
|
90
|
+
else
|
|
91
|
+
echo "cleanup_lane_worktrees: failed to remove worktree $path (branch=$branch)" >&2
|
|
92
|
+
continue
|
|
93
|
+
fi
|
|
94
|
+
# Delete the branch only if it's an auto-named pattern.
|
|
95
|
+
if [[ "$branch" == worktree-* || "$branch" == phase/*/sl-* ]]; then
|
|
96
|
+
if ! git branch -D "$branch" 2>/dev/null; then
|
|
97
|
+
echo "cleanup_lane_worktrees: failed to delete branch $branch" >&2
|
|
98
|
+
fi
|
|
99
|
+
fi
|
|
100
|
+
done < <(git worktree list --porcelain | awk '$1 == "worktree" { print $2 }')
|
|
101
|
+
|
|
102
|
+
echo "cleanup_lane_worktrees: removed $removed, skipped $skipped"
|
|
103
|
+
exit 0
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# parent_tree_leakage_check.sh — detect when a teammate's filesystem edits
|
|
3
|
+
# escaped its worktree into the parent checkout, or when EnterWorktree
|
|
4
|
+
# silently fell back to in-place branch creation in the parent.
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# parent_tree_leakage_check.sh <lane-id> <owned-globs-file> [<merge-target>]
|
|
8
|
+
#
|
|
9
|
+
# <lane-id> Informational only; echoed into stdout for
|
|
10
|
+
# orchestrator logging.
|
|
11
|
+
# <owned-globs-file> File with one glob pattern per line; these are
|
|
12
|
+
# the lane's `Owned files` from the plan doc.
|
|
13
|
+
# Passing /dev/null is valid (treat empty globs
|
|
14
|
+
# as "nothing is owned" → any dirty file counts
|
|
15
|
+
# as unrelated).
|
|
16
|
+
# <merge-target> Optional. Branch the phase merges into (default
|
|
17
|
+
# "main"). Used by the new PARENT_ON_WRONG_BRANCH
|
|
18
|
+
# probe.
|
|
19
|
+
#
|
|
20
|
+
# Behavior: emits EXACTLY one token on stdout, exit 0 always.
|
|
21
|
+
#
|
|
22
|
+
# CLEAN
|
|
23
|
+
# - Working tree has no uncommitted changes AND the parent is on the
|
|
24
|
+
# merge-target branch. No leakage.
|
|
25
|
+
#
|
|
26
|
+
# LEAKAGE_DETECTED
|
|
27
|
+
# - Working tree has dirty files AND at least one matches the lane's
|
|
28
|
+
# owned globs. The teammate wrote into the parent checkout rather
|
|
29
|
+
# than the worktree; orchestrator should stash or abort before merge.
|
|
30
|
+
#
|
|
31
|
+
# UNRELATED_DIRTY_TREE
|
|
32
|
+
# - Working tree has dirty files but NONE match the lane's owned
|
|
33
|
+
# globs. Probably other orchestrator-level changes; caller decides.
|
|
34
|
+
#
|
|
35
|
+
# PARENT_ON_WRONG_BRANCH
|
|
36
|
+
# - Working tree is CLEAN but the parent checkout is on a branch
|
|
37
|
+
# OTHER than <merge-target>. Symptom of EnterWorktree silently
|
|
38
|
+
# falling back to in-place branch creation (a name collision is
|
|
39
|
+
# the typical cause). The lane's commit is usually fine — merge
|
|
40
|
+
# by SHA, then `git checkout <merge-target>` in the parent before
|
|
41
|
+
# post-merge worktree cleanup.
|
|
42
|
+
#
|
|
43
|
+
# Implementation notes:
|
|
44
|
+
# - Runs from the parent checkout (the cwd of the orchestrator's git
|
|
45
|
+
# context, not the lane's worktree).
|
|
46
|
+
# - `git status --porcelain` output: `XY <path>` where X/Y are status
|
|
47
|
+
# codes; we parse the path by stripping the first 3 chars.
|
|
48
|
+
|
|
49
|
+
set -uo pipefail
|
|
50
|
+
|
|
51
|
+
if [[ $# -lt 2 || $# -gt 3 ]]; then
|
|
52
|
+
echo "usage: parent_tree_leakage_check.sh <lane-id> <owned-globs-file> [<merge-target>]" >&2
|
|
53
|
+
exit 2
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
lane_id="$1"
|
|
57
|
+
globs_path="$2"
|
|
58
|
+
merge_target="${3:-main}"
|
|
59
|
+
|
|
60
|
+
# Load owned globs.
|
|
61
|
+
globs=()
|
|
62
|
+
if [[ -r "$globs_path" && "$globs_path" != "/dev/null" ]]; then
|
|
63
|
+
while IFS= read -r line; do
|
|
64
|
+
line="${line%%#*}"
|
|
65
|
+
line="$(echo -n "$line" | xargs || true)"
|
|
66
|
+
[[ -z "$line" ]] && continue
|
|
67
|
+
globs+=("$line")
|
|
68
|
+
done < "$globs_path"
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
# Enumerate dirty paths from the parent checkout.
|
|
72
|
+
dirty_paths=()
|
|
73
|
+
while IFS= read -r line; do
|
|
74
|
+
[[ -z "$line" ]] && continue
|
|
75
|
+
# Status code (first 2 chars) + a space, then the path. Renames use
|
|
76
|
+
# "R old -> new"; we take the NEW path.
|
|
77
|
+
path="${line:3}"
|
|
78
|
+
if [[ "$path" == *" -> "* ]]; then
|
|
79
|
+
path="${path#* -> }"
|
|
80
|
+
fi
|
|
81
|
+
# Strip surrounding quotes git adds for paths with spaces.
|
|
82
|
+
path="${path#\"}"
|
|
83
|
+
path="${path%\"}"
|
|
84
|
+
dirty_paths+=("$path")
|
|
85
|
+
done < <(git status --porcelain 2>/dev/null)
|
|
86
|
+
|
|
87
|
+
if [[ ${#dirty_paths[@]} -eq 0 ]]; then
|
|
88
|
+
# Parent is clean — but is it on the right branch?
|
|
89
|
+
current_branch="$(git branch --show-current 2>/dev/null || true)"
|
|
90
|
+
if [[ -n "$current_branch" && "$current_branch" != "$merge_target" ]]; then
|
|
91
|
+
echo "parent_tree_leakage_check: $lane_id — parent checkout is on branch '$current_branch' (expected '$merge_target')" >&2
|
|
92
|
+
echo "PARENT_ON_WRONG_BRANCH"
|
|
93
|
+
exit 0
|
|
94
|
+
fi
|
|
95
|
+
echo "CLEAN"
|
|
96
|
+
exit 0
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
# Test each dirty path against the lane's globs.
|
|
100
|
+
is_owned() {
|
|
101
|
+
local path="$1"
|
|
102
|
+
local pat
|
|
103
|
+
for pat in "${globs[@]+"${globs[@]}"}"; do
|
|
104
|
+
# shellcheck disable=SC2053
|
|
105
|
+
if [[ "$path" == $pat ]]; then
|
|
106
|
+
return 0
|
|
107
|
+
fi
|
|
108
|
+
done
|
|
109
|
+
return 1
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
leakage=false
|
|
113
|
+
for p in "${dirty_paths[@]}"; do
|
|
114
|
+
if is_owned "$p"; then
|
|
115
|
+
leakage=true
|
|
116
|
+
echo "parent_tree_leakage_check: $lane_id — dirty path $p matches owned globs" >&2
|
|
117
|
+
fi
|
|
118
|
+
done
|
|
119
|
+
|
|
120
|
+
if [[ "$leakage" == "true" ]]; then
|
|
121
|
+
echo "LEAKAGE_DETECTED"
|
|
122
|
+
exit 0
|
|
123
|
+
fi
|
|
124
|
+
echo "UNRELATED_DIRTY_TREE"
|
|
125
|
+
exit 0
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# post_merge_import_smoke.sh — verify post-merge Python-package imports.
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# post_merge_import_smoke.sh <pkg.dotted.path> [<pkg.another> ...]
|
|
6
|
+
#
|
|
7
|
+
# For each package argument, runs `python -c "import <pkg>"` using the
|
|
8
|
+
# repo-local .venv (falls back to plain `python` if .venv is missing).
|
|
9
|
+
# Emits one line per package:
|
|
10
|
+
#
|
|
11
|
+
# IMPORT_OK: <pkg>
|
|
12
|
+
# IMPORT_FAIL: <pkg> — <first-line-of-error>
|
|
13
|
+
#
|
|
14
|
+
# Exit code:
|
|
15
|
+
# 0 — every package imports cleanly
|
|
16
|
+
# 1 — at least one package failed to import
|
|
17
|
+
# 2 — usage error
|
|
18
|
+
#
|
|
19
|
+
# Rationale: a lane that drops or renames a symbol re-exported by an
|
|
20
|
+
# `__init__.py` breaks package load silently — the ImportError only
|
|
21
|
+
# surfaces when some downstream code happens to trigger the import. A
|
|
22
|
+
# post-merge import smoke on every `__init__.py` the lane touched catches
|
|
23
|
+
# this in seconds, before the next wave builds on a broken base.
|
|
24
|
+
#
|
|
25
|
+
# Invocation pattern for the orchestrator (Step 7):
|
|
26
|
+
# packages="$(git diff --name-only HEAD~..HEAD \
|
|
27
|
+
# | grep '__init__\.py$' \
|
|
28
|
+
# | sed 's|/__init__\.py$||; s|/|.|g' \
|
|
29
|
+
# | sort -u)"
|
|
30
|
+
# [[ -n "$packages" ]] && bash <script> $packages
|
|
31
|
+
|
|
32
|
+
set -uo pipefail
|
|
33
|
+
|
|
34
|
+
if [[ $# -lt 1 ]]; then
|
|
35
|
+
echo "usage: post_merge_import_smoke.sh <pkg.dotted.path> [<pkg.another> ...]" >&2
|
|
36
|
+
exit 2
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
# Prefer repo-local venv if present.
|
|
40
|
+
python_bin="python"
|
|
41
|
+
if [[ -x ".venv/bin/python" ]]; then
|
|
42
|
+
python_bin=".venv/bin/python"
|
|
43
|
+
elif [[ -x "venv/bin/python" ]]; then
|
|
44
|
+
python_bin="venv/bin/python"
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
any_fail=0
|
|
48
|
+
for pkg in "$@"; do
|
|
49
|
+
# Run the import in a subshell; capture stderr.
|
|
50
|
+
err="$("$python_bin" -c "import ${pkg}" 2>&1 >/dev/null)"
|
|
51
|
+
rc=$?
|
|
52
|
+
if [[ $rc -eq 0 ]]; then
|
|
53
|
+
echo "IMPORT_OK: ${pkg}"
|
|
54
|
+
else
|
|
55
|
+
# First line of the error only.
|
|
56
|
+
first_line="$(echo "$err" | tail -n 1)"
|
|
57
|
+
echo "IMPORT_FAIL: ${pkg} — ${first_line}"
|
|
58
|
+
any_fail=1
|
|
59
|
+
fi
|
|
60
|
+
done
|
|
61
|
+
|
|
62
|
+
exit $any_fail
|
phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/pre_merge_destructiveness_check.sh
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# pre_merge_destructiveness_check.sh — classify a lane's merge before
|
|
3
|
+
# performing it, to prevent stale-base destruction of peer-lane work.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# pre_merge_destructiveness_check.sh <lane-sha> <merge-target> <whitelist-path>
|
|
7
|
+
#
|
|
8
|
+
# <lane-sha> Commit SHA produced by the lane.
|
|
9
|
+
# <merge-target> Branch the lane will be merged into (typically main).
|
|
10
|
+
# <whitelist-path> File with one path per line listing destructive
|
|
11
|
+
# changes the plan EXPECTS for this lane. Supports
|
|
12
|
+
# shell-glob patterns. Use /dev/null if the lane
|
|
13
|
+
# is purely additive.
|
|
14
|
+
#
|
|
15
|
+
# Behavior: emits EXACTLY one token on stdout, exit 0 always (verdict is
|
|
16
|
+
# on stdout for the orchestrator to act on).
|
|
17
|
+
#
|
|
18
|
+
# SAFE
|
|
19
|
+
# - The ancestor-diff deletion list is empty OR every deletion is
|
|
20
|
+
# explicitly whitelisted. Proceed with `git merge --no-ff`.
|
|
21
|
+
#
|
|
22
|
+
# STALE_BASE_DETECTED
|
|
23
|
+
# - The lane's diff-against-target shows deletions of files that
|
|
24
|
+
# WEREN'T in the lane's ancestor; i.e. peer lanes merged additions
|
|
25
|
+
# between the lane's base and target, and `git merge --no-ff` would
|
|
26
|
+
# revert them. Orchestrator should salvage (cherry-pick the lane's
|
|
27
|
+
# owned paths) rather than retry.
|
|
28
|
+
#
|
|
29
|
+
# CONFLICT
|
|
30
|
+
# - Some other destructive signature that doesn't match either of the
|
|
31
|
+
# above. Orchestrator should surface to the teammate for manual
|
|
32
|
+
# resolution.
|
|
33
|
+
#
|
|
34
|
+
# Rationale: Step 7's MANDATORY pre-merge check. A lane that committed
|
|
35
|
+
# against a stale base can wipe peer-lane work on `--no-ff` merge; the
|
|
36
|
+
# naive `git diff main..lane` can't distinguish that from a parallel-
|
|
37
|
+
# branch false positive. Extracting the 3-part diff (naive + ancestor +
|
|
38
|
+
# whitelist) into a script makes the verdict deterministic.
|
|
39
|
+
|
|
40
|
+
set -uo pipefail
|
|
41
|
+
|
|
42
|
+
if [[ $# -ne 3 ]]; then
|
|
43
|
+
echo "usage: pre_merge_destructiveness_check.sh <lane-sha> <merge-target> <whitelist-path>" >&2
|
|
44
|
+
exit 2
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
sha="$1"
|
|
48
|
+
target="$2"
|
|
49
|
+
whitelist_path="$3"
|
|
50
|
+
|
|
51
|
+
# Load whitelist patterns (one per line; '#' comments OK; blank lines skipped).
|
|
52
|
+
whitelist=()
|
|
53
|
+
if [[ -r "$whitelist_path" && "$whitelist_path" != "/dev/null" ]]; then
|
|
54
|
+
while IFS= read -r line; do
|
|
55
|
+
line="${line%%#*}"
|
|
56
|
+
line="${line//[[:space:]]/}"
|
|
57
|
+
[[ -z "$line" ]] && continue
|
|
58
|
+
whitelist+=("$line")
|
|
59
|
+
done < "$whitelist_path"
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# Primary: deletions in target..lane-sha (naïve diff).
|
|
63
|
+
mapfile -t naive_deletions < <(
|
|
64
|
+
git diff --diff-filter=D --name-only "$target..$sha" 2>/dev/null
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# Disambiguator: deletions in ancestor..lane-sha (what the lane actually
|
|
68
|
+
# did, ignoring what target gained since).
|
|
69
|
+
ancestor="$(git merge-base "$target" "$sha" 2>/dev/null)"
|
|
70
|
+
mapfile -t ancestor_deletions < <(
|
|
71
|
+
[[ -n "$ancestor" ]] \
|
|
72
|
+
&& git diff --diff-filter=D --name-only "$ancestor..$sha" 2>/dev/null \
|
|
73
|
+
|| true
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
# Helper: test whether a path matches any whitelist glob.
|
|
77
|
+
is_whitelisted() {
|
|
78
|
+
local path="$1"
|
|
79
|
+
local pat
|
|
80
|
+
for pat in "${whitelist[@]+"${whitelist[@]}"}"; do
|
|
81
|
+
# shellcheck disable=SC2053
|
|
82
|
+
if [[ "$path" == $pat ]]; then
|
|
83
|
+
return 0
|
|
84
|
+
fi
|
|
85
|
+
done
|
|
86
|
+
return 1
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# Case 1: the lane itself did zero deletions (ancestor..lane is additive-only
|
|
90
|
+
# OR all lane-side deletions are whitelisted). The naive deletion list may
|
|
91
|
+
# still show peer-lane additions — which is the stale-base signature.
|
|
92
|
+
lane_did_unwhitelisted_delete=false
|
|
93
|
+
for d in "${ancestor_deletions[@]+"${ancestor_deletions[@]}"}"; do
|
|
94
|
+
[[ -z "$d" ]] && continue
|
|
95
|
+
if ! is_whitelisted "$d"; then
|
|
96
|
+
lane_did_unwhitelisted_delete=true
|
|
97
|
+
break
|
|
98
|
+
fi
|
|
99
|
+
done
|
|
100
|
+
|
|
101
|
+
# Compute naive-but-not-ancestor deletions (files target has that lane
|
|
102
|
+
# never had -> peer lanes added them after lane branched off).
|
|
103
|
+
declare -A ancestor_set=()
|
|
104
|
+
for d in "${ancestor_deletions[@]+"${ancestor_deletions[@]}"}"; do
|
|
105
|
+
[[ -z "$d" ]] && continue
|
|
106
|
+
ancestor_set["$d"]=1
|
|
107
|
+
done
|
|
108
|
+
stale_base_deletions=()
|
|
109
|
+
for d in "${naive_deletions[@]+"${naive_deletions[@]}"}"; do
|
|
110
|
+
[[ -z "$d" ]] && continue
|
|
111
|
+
if [[ -z "${ancestor_set[$d]+set}" ]]; then
|
|
112
|
+
stale_base_deletions+=("$d")
|
|
113
|
+
fi
|
|
114
|
+
done
|
|
115
|
+
|
|
116
|
+
if [[ "$lane_did_unwhitelisted_delete" == "false" && ${#stale_base_deletions[@]} -eq 0 ]]; then
|
|
117
|
+
echo "SAFE"
|
|
118
|
+
exit 0
|
|
119
|
+
fi
|
|
120
|
+
if [[ "$lane_did_unwhitelisted_delete" == "false" && ${#stale_base_deletions[@]} -gt 0 ]]; then
|
|
121
|
+
# Lane is additive but diff-against-target shows deletions from peer-lane
|
|
122
|
+
# additions — classic stale base.
|
|
123
|
+
echo "STALE_BASE_DETECTED"
|
|
124
|
+
exit 0
|
|
125
|
+
fi
|
|
126
|
+
echo "CONFLICT"
|
|
127
|
+
exit 0
|