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,399 @@
|
|
|
1
|
+
"""CS-0.11 -- brownfield ingestion: shape-to-conform, then verify.
|
|
2
|
+
|
|
3
|
+
`phase-loop consiliency-ingest --repo <path>` looks at whether the repo
|
|
4
|
+
already has a `.consiliency/manifest.json` -- the single detection/consent
|
|
5
|
+
point the whole `.consiliency` stack shares (see
|
|
6
|
+
:func:`consiliency_layout.find_consiliency_manifest`) -- and picks one of two
|
|
7
|
+
disjoint branches:
|
|
8
|
+
|
|
9
|
+
* **SHAPE** (manifest absent): a brownfield repo hasn't been touched yet.
|
|
10
|
+
This is CONSENT-GATED on an explicit ``--adopt``/``adopt=True`` flag -- an
|
|
11
|
+
unflagged repo is a pure no-op, nothing is read beyond the one existence
|
|
12
|
+
check and nothing is written. When adopted, this module delegates the base
|
|
13
|
+
layout entirely to the CS-0.5 scaffolder (:func:`consiliency_scaffold.scaffold`)
|
|
14
|
+
-- it never reimplements doc placement -- and then layers a CS-0.12
|
|
15
|
+
(contract 0.2.0) adoption profile and a PROPOSED governed-set allowlist
|
|
16
|
+
onto the manifest scaffold() just wrote, in the same first-writer pass.
|
|
17
|
+
The proposal is conservative: only the paths the required-documents
|
|
18
|
+
registry composed for the declared archetype(s) -- i.e. exactly the rows
|
|
19
|
+
scaffold() itself declared in ``documents`` -- are proposed. Nothing
|
|
20
|
+
ambiguous is auto-claimed, and the default ignore-set (scratchpads,
|
|
21
|
+
other-harness namespaces such as `.phase-loop/`, `.claude/`, `.codex/`,
|
|
22
|
+
...) is never a candidate, defensively re-checked here even though the
|
|
23
|
+
required-documents registry can never itself emit an ignored path.
|
|
24
|
+
* **VERIFY** (manifest present): every subsequent pass, including a pass
|
|
25
|
+
over a hand-corrupted `.consiliency/`. This module NEVER rewrites; it runs
|
|
26
|
+
the CS-0.6 L0 gates (:func:`consiliency_gates.scan_consiliency_gates`)
|
|
27
|
+
as-is and additionally labels each declared document against the CS-0.12
|
|
28
|
+
governance-scope decision (governed / foreign / present-nonconforming),
|
|
29
|
+
again read-only. Detection is manifest-FILE-presence, not
|
|
30
|
+
manifest-schema-validity, so a corrupted manifest is flagged (via the
|
|
31
|
+
existing layout-validity gate) and never mistaken for "absent" -- it can
|
|
32
|
+
never accidentally re-trigger the shape branch and overwrite a human's
|
|
33
|
+
repair.
|
|
34
|
+
|
|
35
|
+
Governance-scope decision (CS-0.12 / contract 0.2.0): :func:`evaluate_governance_scope`
|
|
36
|
+
is a pure function over (adoption profile, governed_set, ignore_set, facet,
|
|
37
|
+
subject) implementing the ``governance_scope_scenario`` conformance surface
|
|
38
|
+
the vendored contract ships (``consiliency_contract``'s
|
|
39
|
+
``conformance/vectors/{adoption,governed-set,ignore-set,doc-label}-*.json``).
|
|
40
|
+
Branch order, kept in sync with those vectors:
|
|
41
|
+
|
|
42
|
+
1. no adoption profile -> ungoverned (``not-adopted``)
|
|
43
|
+
2. adoption profile present but ``adopted: false`` -> ungoverned (``adoption-declined``)
|
|
44
|
+
3. requested facet not in ``adopted_scope`` -> ungoverned (``out-of-scope-facet``)
|
|
45
|
+
4. path matches the ignore-set (default + repo-declared) -> ungoverned
|
|
46
|
+
(``ignored``) -- this overrides the governed-set allowlist; it is the
|
|
47
|
+
safety floor scratchpads and other-harness docs sit behind.
|
|
48
|
+
5. path matches no governed_set selector -> ungoverned (``undeclared-ungoverned``);
|
|
49
|
+
a present-but-undeclared subject is additionally labeled ``foreign``.
|
|
50
|
+
6. otherwise -> governed (``declared``); an ``observed_label`` of
|
|
51
|
+
``present-nonconforming`` on the subject additionally warns without
|
|
52
|
+
changing the governed verdict.
|
|
53
|
+
"""
|
|
54
|
+
from __future__ import annotations
|
|
55
|
+
|
|
56
|
+
import fnmatch
|
|
57
|
+
import json
|
|
58
|
+
from dataclasses import dataclass
|
|
59
|
+
from pathlib import Path, PurePosixPath
|
|
60
|
+
from typing import Any, Mapping, Sequence
|
|
61
|
+
|
|
62
|
+
from jsonschema import Draft202012Validator
|
|
63
|
+
|
|
64
|
+
from consiliency_contract import load_registry
|
|
65
|
+
|
|
66
|
+
from .consiliency_gates import scan_consiliency_gates
|
|
67
|
+
from .consiliency_layout import (
|
|
68
|
+
ARCHETYPE_IDS,
|
|
69
|
+
contract_version_status_schema,
|
|
70
|
+
find_consiliency_manifest,
|
|
71
|
+
installed_contract_version,
|
|
72
|
+
interface_declaration_schema,
|
|
73
|
+
load_consiliency_manifest,
|
|
74
|
+
manifest_path,
|
|
75
|
+
manifest_schema,
|
|
76
|
+
)
|
|
77
|
+
from .consiliency_scaffold import ScaffoldResult, scaffold
|
|
78
|
+
|
|
79
|
+
#: The `adopted_scope` facets CS-0.6 actually gates today (presence,
|
|
80
|
+
#: local-integrity, layout-validity, version-skew all live under the
|
|
81
|
+
#: `.consiliency/` LAYOUT and are enforced by the L0 GATES). The contract's
|
|
82
|
+
#: adoptionProfile also allows `projections`/`cert`, but nothing in
|
|
83
|
+
#: agent-harness enforces those facets yet -- claiming them here would be
|
|
84
|
+
#: consent theater, so this module only ever declares scope it backs.
|
|
85
|
+
_ADOPTED_SCOPE_ENFORCED: tuple[str, ...] = ("layout", "gates")
|
|
86
|
+
|
|
87
|
+
#: Manifest document ids whose target artifact is machine-generated JSON with
|
|
88
|
+
#: a real vendored schema -- the only L0 surface honest enough to support a
|
|
89
|
+
#: content-conformance label. Prose docs are presence-only by design (see
|
|
90
|
+
#: consiliency_scaffold's module docstring): this module never judges
|
|
91
|
+
#: hand-authored markdown, so it never labels a prose doc nonconforming.
|
|
92
|
+
_SCHEMA_CHECKED_DOC_IDS: dict[str, Any] = {
|
|
93
|
+
"contract-version-status": contract_version_status_schema,
|
|
94
|
+
"interface-declaration": interface_declaration_schema,
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
_MESSAGES: dict[str, str] = {
|
|
98
|
+
"governance.not_adopted": "Repo has no adoption profile; the document is ungoverned.",
|
|
99
|
+
"governance.adoption_declined": "Adoption is explicitly declined (adopted:false); the document is ungoverned.",
|
|
100
|
+
"governance.out_of_scope_facet": "The requested facet is not in adopted_scope; the document is ungoverned for this facet.",
|
|
101
|
+
"governance.ignored": "Path matches the ignore-set; it is ungoverned and never ingested, overriding the governed_set match.",
|
|
102
|
+
"governance.undeclared": "No governed_set selector matches the document; it is ungoverned.",
|
|
103
|
+
"governance.foreign": "Present artifact is not in the governed set; labeled foreign (governed:false).",
|
|
104
|
+
"governance.governed": "Document is declared in the governed set and within an adopted scope facet.",
|
|
105
|
+
"governance.present_nonconforming": "Governed document is present but does not conform to its declared class.",
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _default_ignore_set() -> tuple[str, ...]:
|
|
110
|
+
return tuple(load_registry("default_ignore_set").get("namespaces", ()))
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _path_ignored(path: str, ignore_set: Sequence[str]) -> bool:
|
|
114
|
+
"""Default-ignore-set matching rule (`consiliency_contract`'s registry):
|
|
115
|
+
a metachar-free entry ending in `/` is a bare directory name and matches
|
|
116
|
+
at ANY depth; anything containing a glob metacharacter is a glob
|
|
117
|
+
evaluated against the whole repo-relative path."""
|
|
118
|
+
parts = PurePosixPath(path).parts
|
|
119
|
+
for entry in ignore_set:
|
|
120
|
+
has_metachar = any(ch in entry for ch in "*?[")
|
|
121
|
+
if not has_metachar and entry.endswith("/"):
|
|
122
|
+
if entry.rstrip("/") in parts[:-1]:
|
|
123
|
+
return True
|
|
124
|
+
elif fnmatch.fnmatch(path, entry):
|
|
125
|
+
return True
|
|
126
|
+
return False
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _selector_matches(selector: Mapping[str, Any], subject: Mapping[str, Any]) -> bool:
|
|
130
|
+
by = selector.get("by")
|
|
131
|
+
value = str(selector.get("value") or "")
|
|
132
|
+
if by == "path":
|
|
133
|
+
return str(subject.get("path") or "") == value
|
|
134
|
+
if by == "glob":
|
|
135
|
+
return fnmatch.fnmatch(str(subject.get("path") or ""), value)
|
|
136
|
+
if by == "class":
|
|
137
|
+
return str(subject.get("class") or "") == value
|
|
138
|
+
return False
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def evaluate_governance_scope(
|
|
142
|
+
*,
|
|
143
|
+
adoption: Mapping[str, Any] | None,
|
|
144
|
+
governed_set: Sequence[Mapping[str, Any]] = (),
|
|
145
|
+
ignore_set: Sequence[str] = (),
|
|
146
|
+
facet: str | None = None,
|
|
147
|
+
subject: Mapping[str, Any],
|
|
148
|
+
) -> dict[str, Any]:
|
|
149
|
+
"""Pure CS-0.12 governance-scope decision. See module docstring for the
|
|
150
|
+
branch order this implements against the vendored contract's
|
|
151
|
+
`governance_scope_scenario` conformance vectors."""
|
|
152
|
+
|
|
153
|
+
def _decision(*, governed: bool, reason: str, code: str, status: str = "accepted", labels: tuple[str, ...] = ()) -> dict[str, Any]:
|
|
154
|
+
result: dict[str, Any] = {
|
|
155
|
+
"schema": "consiliency.conformance_decision.v1",
|
|
156
|
+
"status": status,
|
|
157
|
+
"maturity": "presence-only",
|
|
158
|
+
"findings": [{"code": code, "severity": "warn" if status == "warn" else "info", "message": _MESSAGES[code]}],
|
|
159
|
+
"governed": governed,
|
|
160
|
+
"reason": reason,
|
|
161
|
+
}
|
|
162
|
+
if labels:
|
|
163
|
+
result["labels"] = list(labels)
|
|
164
|
+
return result
|
|
165
|
+
|
|
166
|
+
if adoption is not None and adoption.get("adopted") is False:
|
|
167
|
+
return _decision(governed=False, reason="adoption-declined", code="governance.adoption_declined")
|
|
168
|
+
if not adoption or not adoption.get("adopted"):
|
|
169
|
+
return _decision(governed=False, reason="not-adopted", code="governance.not_adopted")
|
|
170
|
+
|
|
171
|
+
adopted_scope = tuple(adoption.get("adopted_scope") or ())
|
|
172
|
+
if facet is not None and facet not in adopted_scope:
|
|
173
|
+
return _decision(governed=False, reason="out-of-scope-facet", code="governance.out_of_scope_facet")
|
|
174
|
+
|
|
175
|
+
if _path_ignored(str(subject.get("path") or ""), ignore_set):
|
|
176
|
+
return _decision(governed=False, reason="ignored", code="governance.ignored")
|
|
177
|
+
|
|
178
|
+
if not any(_selector_matches(selector, subject) for selector in governed_set):
|
|
179
|
+
if subject.get("observed_label") == "foreign":
|
|
180
|
+
return _decision(governed=False, reason="undeclared-ungoverned", code="governance.foreign", labels=("foreign",))
|
|
181
|
+
return _decision(governed=False, reason="undeclared-ungoverned", code="governance.undeclared")
|
|
182
|
+
|
|
183
|
+
if subject.get("observed_label") == "present-nonconforming":
|
|
184
|
+
return _decision(
|
|
185
|
+
governed=True, reason="declared", code="governance.present_nonconforming",
|
|
186
|
+
status="warn", labels=("present-nonconforming",),
|
|
187
|
+
)
|
|
188
|
+
return _decision(governed=True, reason="declared", code="governance.governed")
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _primary_archetype(mode: str, archetypes: tuple[str, ...]) -> str:
|
|
192
|
+
"""The contract's `adoptionProfile.archetype` is singular (one enum
|
|
193
|
+
value, including `baseline-only`), while `declaration.archetypes` is a
|
|
194
|
+
set. When more than one archetype is declared, this picks the first in
|
|
195
|
+
registry order -- the same precedence `compose_required_documents`
|
|
196
|
+
already uses to resolve composition order -- as the profile's headline
|
|
197
|
+
archetype. This is a judgment call: the manifest's own `declaration`
|
|
198
|
+
remains the source of truth for the full set; `adoption.archetype` is
|
|
199
|
+
only ever a single-value summary of it."""
|
|
200
|
+
if mode == "baseline-only" or not archetypes:
|
|
201
|
+
return "baseline-only"
|
|
202
|
+
for candidate in ARCHETYPE_IDS:
|
|
203
|
+
if candidate in archetypes:
|
|
204
|
+
return candidate
|
|
205
|
+
return archetypes[0]
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def _propose_governed_set(manifest: Mapping[str, Any]) -> list[dict[str, Any]]:
|
|
209
|
+
ignore_set = _default_ignore_set()
|
|
210
|
+
selectors: list[dict[str, Any]] = []
|
|
211
|
+
seen: set[str] = set()
|
|
212
|
+
for entry in manifest.get("documents", []):
|
|
213
|
+
path = entry.get("path")
|
|
214
|
+
if not path or path in seen:
|
|
215
|
+
continue
|
|
216
|
+
# Defensive: the required-documents registry can never itself emit
|
|
217
|
+
# an ignored path, but a governed-set proposal must never claim one
|
|
218
|
+
# even if that invariant ever drifts.
|
|
219
|
+
if _path_ignored(str(path), ignore_set):
|
|
220
|
+
continue
|
|
221
|
+
seen.add(path)
|
|
222
|
+
selectors.append({"by": "path", "value": path})
|
|
223
|
+
return selectors
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def _observe_document_label(repo: Path, entry: Mapping[str, Any]) -> str | None:
|
|
227
|
+
"""The only L0-honest content signal this module computes: whether a
|
|
228
|
+
machine-generated JSON artifact (status.json / interfaces.json)
|
|
229
|
+
validates against its own vendored schema. Prose docs are never judged
|
|
230
|
+
-- this module doesn't invent a class-conformance detector for
|
|
231
|
+
hand-authored markdown."""
|
|
232
|
+
path = entry.get("path")
|
|
233
|
+
if not path:
|
|
234
|
+
return None
|
|
235
|
+
file_path = repo / str(path)
|
|
236
|
+
if not file_path.is_file():
|
|
237
|
+
return None # absence is the CS-0.6 presence gate's concern, not a conformance label.
|
|
238
|
+
schema_loader = _SCHEMA_CHECKED_DOC_IDS.get(str(entry.get("id")))
|
|
239
|
+
if schema_loader is None:
|
|
240
|
+
return None
|
|
241
|
+
try:
|
|
242
|
+
payload = json.loads(file_path.read_text(encoding="utf-8"))
|
|
243
|
+
except (OSError, ValueError):
|
|
244
|
+
return "present-nonconforming"
|
|
245
|
+
errors = list(Draft202012Validator(schema_loader()).iter_errors(payload))
|
|
246
|
+
return "present-nonconforming" if errors else None
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
@dataclass(frozen=True)
|
|
250
|
+
class IngestResult:
|
|
251
|
+
repo: Path
|
|
252
|
+
mode: str # "shape" | "verify" | "skipped"
|
|
253
|
+
dry_run: bool
|
|
254
|
+
adopted: bool
|
|
255
|
+
manifest_path: Path
|
|
256
|
+
scaffold: dict[str, Any] | None
|
|
257
|
+
gate_scan: dict[str, Any] | None
|
|
258
|
+
governed_set: tuple[dict[str, Any], ...]
|
|
259
|
+
document_labels: tuple[dict[str, Any], ...]
|
|
260
|
+
findings: tuple[dict[str, Any], ...]
|
|
261
|
+
|
|
262
|
+
def to_json(self) -> dict[str, Any]:
|
|
263
|
+
return {
|
|
264
|
+
"repo": str(self.repo),
|
|
265
|
+
"mode": self.mode,
|
|
266
|
+
"dry_run": self.dry_run,
|
|
267
|
+
"adopted": self.adopted,
|
|
268
|
+
"manifest_path": str(self.manifest_path),
|
|
269
|
+
"scaffold": self.scaffold,
|
|
270
|
+
"gate_scan": self.gate_scan,
|
|
271
|
+
"governed_set": list(self.governed_set),
|
|
272
|
+
"document_labels": list(self.document_labels),
|
|
273
|
+
"findings": list(self.findings),
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def ingest(
|
|
278
|
+
repo: str | Path,
|
|
279
|
+
*,
|
|
280
|
+
adopt: bool = False,
|
|
281
|
+
mode: str = "baseline-only",
|
|
282
|
+
archetypes: tuple[str, ...] = (),
|
|
283
|
+
modifiers: tuple[str, ...] = (),
|
|
284
|
+
repo_id: str | None = None,
|
|
285
|
+
display_name: str | None = None,
|
|
286
|
+
dry_run: bool = False,
|
|
287
|
+
) -> IngestResult:
|
|
288
|
+
repo = Path(repo)
|
|
289
|
+
existing = find_consiliency_manifest(repo)
|
|
290
|
+
if existing is not None:
|
|
291
|
+
return _verify(repo, existing_manifest_path=existing, dry_run=dry_run)
|
|
292
|
+
|
|
293
|
+
target_manifest_path = manifest_path(repo)
|
|
294
|
+
if not adopt:
|
|
295
|
+
return IngestResult(
|
|
296
|
+
repo=repo, mode="skipped", dry_run=dry_run, adopted=False,
|
|
297
|
+
manifest_path=target_manifest_path, scaffold=None, gate_scan=None,
|
|
298
|
+
governed_set=(), document_labels=(),
|
|
299
|
+
findings=(
|
|
300
|
+
{
|
|
301
|
+
"code": "adoption.not_requested",
|
|
302
|
+
"severity": "info",
|
|
303
|
+
"message": "No .consiliency/manifest present and --adopt was not passed; repo left untouched.",
|
|
304
|
+
},
|
|
305
|
+
),
|
|
306
|
+
)
|
|
307
|
+
return _shape(
|
|
308
|
+
repo, mode=mode, archetypes=archetypes, modifiers=modifiers,
|
|
309
|
+
repo_id=repo_id, display_name=display_name, dry_run=dry_run,
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def _shape(
|
|
314
|
+
repo: Path,
|
|
315
|
+
*,
|
|
316
|
+
mode: str,
|
|
317
|
+
archetypes: tuple[str, ...],
|
|
318
|
+
modifiers: tuple[str, ...],
|
|
319
|
+
repo_id: str | None,
|
|
320
|
+
display_name: str | None,
|
|
321
|
+
dry_run: bool,
|
|
322
|
+
) -> IngestResult:
|
|
323
|
+
scaffold_result: ScaffoldResult = scaffold(
|
|
324
|
+
repo, mode=mode, archetypes=archetypes, modifiers=modifiers,
|
|
325
|
+
repo_id=repo_id, display_name=display_name, dry_run=dry_run,
|
|
326
|
+
)
|
|
327
|
+
target_manifest_path = scaffold_result.manifest_path
|
|
328
|
+
|
|
329
|
+
if dry_run:
|
|
330
|
+
# Mirror scaffold()'s own dry-run contract: nothing on disk, report
|
|
331
|
+
# what WOULD happen using the same rows the (unwritten) manifest
|
|
332
|
+
# would have declared.
|
|
333
|
+
placeholder_docs = [{"path": p} for p in (*scaffold_result.created_paths, *scaffold_result.referenced_paths)]
|
|
334
|
+
proposed = _propose_governed_set({"documents": placeholder_docs})
|
|
335
|
+
return IngestResult(
|
|
336
|
+
repo=repo, mode="shape", dry_run=True, adopted=True,
|
|
337
|
+
manifest_path=target_manifest_path, scaffold=scaffold_result.to_json(),
|
|
338
|
+
gate_scan=None, governed_set=tuple(proposed), document_labels=(), findings=(),
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
manifest = json.loads(target_manifest_path.read_text(encoding="utf-8"))
|
|
342
|
+
proposed = _propose_governed_set(manifest)
|
|
343
|
+
manifest["adoption"] = {
|
|
344
|
+
"adopted": True,
|
|
345
|
+
"contract_version": installed_contract_version(),
|
|
346
|
+
"archetype": _primary_archetype(mode, archetypes),
|
|
347
|
+
"adopted_scope": list(_ADOPTED_SCOPE_ENFORCED),
|
|
348
|
+
}
|
|
349
|
+
manifest["governed_set"] = proposed
|
|
350
|
+
Draft202012Validator(manifest_schema()).validate(manifest)
|
|
351
|
+
target_manifest_path.write_text(json.dumps(manifest, indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
|
352
|
+
|
|
353
|
+
gate_scan = scan_consiliency_gates(repo)
|
|
354
|
+
return IngestResult(
|
|
355
|
+
repo=repo, mode="shape", dry_run=False, adopted=True,
|
|
356
|
+
manifest_path=target_manifest_path, scaffold=scaffold_result.to_json(),
|
|
357
|
+
gate_scan=gate_scan, governed_set=tuple(proposed), document_labels=(), findings=(),
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def _verify(repo: Path, *, existing_manifest_path: Path, dry_run: bool) -> IngestResult:
|
|
362
|
+
gate_scan = scan_consiliency_gates(repo)
|
|
363
|
+
manifest = load_consiliency_manifest(repo)
|
|
364
|
+
document_labels: list[dict[str, Any]] = []
|
|
365
|
+
findings: list[dict[str, Any]] = []
|
|
366
|
+
governed_set: tuple[dict[str, Any], ...] = ()
|
|
367
|
+
adopted = False
|
|
368
|
+
|
|
369
|
+
if manifest is not None:
|
|
370
|
+
governed_set = tuple(manifest.get("governed_set") or ())
|
|
371
|
+
adoption = manifest.get("adoption")
|
|
372
|
+
adopted = bool(adoption and adoption.get("adopted"))
|
|
373
|
+
ignore_set = _default_ignore_set()
|
|
374
|
+
for entry in manifest.get("documents", []):
|
|
375
|
+
path = entry.get("path")
|
|
376
|
+
if not path:
|
|
377
|
+
continue
|
|
378
|
+
observed_label = _observe_document_label(repo, entry)
|
|
379
|
+
subject = {"kind": "doc", "path": path, "class": entry.get("class"), "observed_label": observed_label}
|
|
380
|
+
decision = evaluate_governance_scope(
|
|
381
|
+
adoption=adoption, governed_set=list(governed_set),
|
|
382
|
+
ignore_set=ignore_set, facet="layout", subject=subject,
|
|
383
|
+
)
|
|
384
|
+
document_labels.append({"doc_id": entry.get("id"), "path": path, **decision})
|
|
385
|
+
if decision["status"] == "warn":
|
|
386
|
+
findings.append(
|
|
387
|
+
{
|
|
388
|
+
"doc_id": entry.get("id"),
|
|
389
|
+
"path": path,
|
|
390
|
+
"code": decision["findings"][0]["code"],
|
|
391
|
+
"message": decision["findings"][0]["message"],
|
|
392
|
+
}
|
|
393
|
+
)
|
|
394
|
+
|
|
395
|
+
return IngestResult(
|
|
396
|
+
repo=repo, mode="verify", dry_run=dry_run, adopted=adopted,
|
|
397
|
+
manifest_path=existing_manifest_path, scaffold=None, gate_scan=gate_scan,
|
|
398
|
+
governed_set=governed_set, document_labels=tuple(document_labels), findings=tuple(findings),
|
|
399
|
+
)
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"""Shared `.consiliency/` layout constants and lookup helpers (CS-0.5/CS-0.6).
|
|
2
|
+
|
|
3
|
+
Single source of truth for where the `.consiliency/` artifacts live and how a
|
|
4
|
+
manifest is composed against the vendored `consiliency_contract` package data.
|
|
5
|
+
The scaffolder (``consiliency_scaffold``), the L0 gates
|
|
6
|
+
(``consiliency_gates``), and the runner's consent check must all agree on
|
|
7
|
+
this path -- drift here would be a silent bug (an operator could scaffold a
|
|
8
|
+
manifest the gates never find).
|
|
9
|
+
|
|
10
|
+
Version-gated DUAL-READ (CS-0.5 scope): this module is purely additive. It
|
|
11
|
+
never reads or writes ``.phase-loop/`` or ``.pipeline/``, and nothing in the
|
|
12
|
+
existing runtime is rewired to prefer `.consiliency/` yet -- that fallback
|
|
13
|
+
seam is for CS-0.12 once the adoption-profile consent check lands. Today,
|
|
14
|
+
`.consiliency/` and legacy layouts simply coexist.
|
|
15
|
+
"""
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import json
|
|
19
|
+
from dataclasses import dataclass
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from typing import Any, Mapping
|
|
22
|
+
|
|
23
|
+
from consiliency_contract import CONTRACT_VERSION, load_registry, load_schema
|
|
24
|
+
|
|
25
|
+
#: Repo-relative root for all Consiliency-standard artifacts.
|
|
26
|
+
CONSILIENCY_DIR = ".consiliency"
|
|
27
|
+
#: Filenames within CONSILIENCY_DIR, pinned to the shapes used by the
|
|
28
|
+
#: contract's own conformance vectors (manifest-valid-product.json uses
|
|
29
|
+
#: ".consiliency/status.json" and ".consiliency/interfaces.json").
|
|
30
|
+
MANIFEST_FILENAME = "manifest.json"
|
|
31
|
+
STATUS_FILENAME = "status.json"
|
|
32
|
+
INTERFACES_FILENAME = "interfaces.json"
|
|
33
|
+
#: Stub documents the scaffolder is allowed to author live under this
|
|
34
|
+
#: sub-namespace so they can never collide with a repo's own doc layout.
|
|
35
|
+
STUB_DOCS_SUBDIR = "docs"
|
|
36
|
+
|
|
37
|
+
ARCHETYPE_IDS: tuple[str, ...] = ("product", "service", "library", "infra", "tooling-meta", "experiment", "document")
|
|
38
|
+
MODIFIER_IDS: tuple[str, ...] = ("data-bearing", "public", "regulated", "user-facing")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def consiliency_root(repo: Path) -> Path:
|
|
42
|
+
return Path(repo) / CONSILIENCY_DIR
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def manifest_path(repo: Path) -> Path:
|
|
46
|
+
return consiliency_root(repo) / MANIFEST_FILENAME
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def status_path(repo: Path) -> Path:
|
|
50
|
+
return consiliency_root(repo) / STATUS_FILENAME
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def interfaces_path(repo: Path) -> Path:
|
|
54
|
+
return consiliency_root(repo) / INTERFACES_FILENAME
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def find_consiliency_manifest(repo: str | Path) -> Path | None:
|
|
58
|
+
"""The one place that decides whether a repo has opted into Consiliency.
|
|
59
|
+
|
|
60
|
+
Every consumer (scaffolder overwrite checks, all four L0 gates, and the
|
|
61
|
+
runner's top-of-loop/closeout hooks) MUST call this rather than
|
|
62
|
+
re-deriving the path, so the CS-0.6 consent gate ("act only on repos that
|
|
63
|
+
HAVE a `.consiliency/manifest`") is enforced identically everywhere.
|
|
64
|
+
"""
|
|
65
|
+
path = manifest_path(Path(repo))
|
|
66
|
+
return path if path.is_file() else None
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def load_consiliency_manifest(repo: str | Path) -> dict[str, Any] | None:
|
|
70
|
+
"""Parsed manifest, or ``None`` when absent OR unparsable.
|
|
71
|
+
|
|
72
|
+
Unparsable is folded into "no consent" rather than raised -- a corrupt
|
|
73
|
+
manifest must never crash the loop; the layout-validity gate is what
|
|
74
|
+
reports that condition as a finding.
|
|
75
|
+
"""
|
|
76
|
+
path = find_consiliency_manifest(repo)
|
|
77
|
+
if path is None:
|
|
78
|
+
return None
|
|
79
|
+
try:
|
|
80
|
+
return json.loads(path.read_text(encoding="utf-8"))
|
|
81
|
+
except (OSError, ValueError):
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@dataclass(frozen=True)
|
|
86
|
+
class RequiredDocRow:
|
|
87
|
+
id: str
|
|
88
|
+
doc_class: str
|
|
89
|
+
required: bool
|
|
90
|
+
maturity_floor: str
|
|
91
|
+
l0_stub_allowed: bool
|
|
92
|
+
l0_note: str | None = None
|
|
93
|
+
source: str = "baseline" # baseline | archetype:<id> | modifier:<id>
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class RequiredDocumentConflict(ValueError):
|
|
97
|
+
"""Two composed rows share an id but are not byte-identical."""
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def compose_required_documents(
|
|
101
|
+
*,
|
|
102
|
+
mode: str,
|
|
103
|
+
archetypes: tuple[str, ...] = (),
|
|
104
|
+
modifiers: tuple[str, ...] = (),
|
|
105
|
+
) -> tuple[RequiredDocRow, ...]:
|
|
106
|
+
"""Compose the required-document set per the registry's own composition
|
|
107
|
+
order: baseline first, then archetypes in REGISTRY order (not input
|
|
108
|
+
order), then modifiers in registry order. Byte-identical duplicate ids are
|
|
109
|
+
de-duplicated; conflicting duplicate ids fail (registry policy)."""
|
|
110
|
+
if mode not in ("baseline-only", "archetyped"):
|
|
111
|
+
raise ValueError(f"invalid declaration mode: {mode!r}")
|
|
112
|
+
registry = load_registry("required_documents")
|
|
113
|
+
archetype_registry = load_registry("archetypes")
|
|
114
|
+
registry_archetype_order = [entry["id"] for entry in archetype_registry["archetypes"]]
|
|
115
|
+
registry_modifier_order = [entry["id"] for entry in archetype_registry["modifiers"]]
|
|
116
|
+
|
|
117
|
+
rows_by_id: dict[str, RequiredDocRow] = {}
|
|
118
|
+
raw_by_id: dict[str, dict[str, Any]] = {}
|
|
119
|
+
|
|
120
|
+
def _add(raw: Mapping[str, Any], source: str) -> None:
|
|
121
|
+
doc_id = raw["id"]
|
|
122
|
+
if doc_id in raw_by_id and raw_by_id[doc_id] != dict(raw):
|
|
123
|
+
raise RequiredDocumentConflict(
|
|
124
|
+
f"required-document id {doc_id!r} conflicts between {rows_by_id[doc_id].source!r} and {source!r}"
|
|
125
|
+
)
|
|
126
|
+
if doc_id in raw_by_id:
|
|
127
|
+
return # byte-identical duplicate -- de-dupe silently.
|
|
128
|
+
raw_by_id[doc_id] = dict(raw)
|
|
129
|
+
rows_by_id[doc_id] = RequiredDocRow(
|
|
130
|
+
id=doc_id,
|
|
131
|
+
doc_class=raw["class"],
|
|
132
|
+
required=bool(raw.get("required", True)),
|
|
133
|
+
maturity_floor=raw["maturity_floor"],
|
|
134
|
+
l0_stub_allowed=bool(raw.get("l0_stub_allowed", False)),
|
|
135
|
+
l0_note=raw.get("l0_note"),
|
|
136
|
+
source=source,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
for raw in registry["baseline"]:
|
|
140
|
+
_add(raw, "baseline")
|
|
141
|
+
if mode == "archetyped":
|
|
142
|
+
for archetype_id in registry_archetype_order:
|
|
143
|
+
if archetype_id not in archetypes:
|
|
144
|
+
continue
|
|
145
|
+
for raw in registry.get("archetypes", {}).get(archetype_id, ()):
|
|
146
|
+
_add(raw, f"archetype:{archetype_id}")
|
|
147
|
+
for modifier_id in registry_modifier_order:
|
|
148
|
+
if modifier_id not in modifiers:
|
|
149
|
+
continue
|
|
150
|
+
for raw in registry.get("modifiers", {}).get(modifier_id, ()):
|
|
151
|
+
_add(raw, f"modifier:{modifier_id}")
|
|
152
|
+
return tuple(rows_by_id[doc_id] for doc_id in raw_by_id)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def installed_contract_version() -> str:
|
|
156
|
+
return CONTRACT_VERSION
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def manifest_schema() -> dict[str, Any]:
|
|
160
|
+
return load_schema("manifest")
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def contract_version_status_schema() -> dict[str, Any]:
|
|
164
|
+
return load_schema("contract_version_status")
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def interface_declaration_schema() -> dict[str, Any]:
|
|
168
|
+
return load_schema("interface_declaration")
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def version_skew_protocol() -> dict[str, Any]:
|
|
172
|
+
return load_schema("version_skew_protocol")
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def loop_gate_protocol() -> dict[str, Any]:
|
|
176
|
+
return load_schema("loop_gate_protocol")
|