agentic-project-kit 1.0.1__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.
- agentic_project_kit/__init__.py +1 -0
- agentic_project_kit/absolute_path_portability_audit.py +241 -0
- agentic_project_kit/access_level_policy.py +14 -0
- agentic_project_kit/access_levels.py +22 -0
- agentic_project_kit/action_registry.py +195 -0
- agentic_project_kit/action_specs.py +286 -0
- agentic_project_kit/agent_command_runner.py +516 -0
- agentic_project_kit/audit_test_matrix.py +36 -0
- agentic_project_kit/audit_test_matrix_cli.py +43 -0
- agentic_project_kit/chat_bootloader.py +257 -0
- agentic_project_kit/chat_entrypoint_contract.py +297 -0
- agentic_project_kit/checks.py +511 -0
- agentic_project_kit/ci_readiness.py +211 -0
- agentic_project_kit/cli.py +147 -0
- agentic_project_kit/cli_commands/__init__.py +1 -0
- agentic_project_kit/cli_commands/absolute_path_audit.py +25 -0
- agentic_project_kit/cli_commands/actions.py +21 -0
- agentic_project_kit/cli_commands/artifact_gc.py +240 -0
- agentic_project_kit/cli_commands/boot.py +55 -0
- agentic_project_kit/cli_commands/chat.py +34 -0
- agentic_project_kit/cli_commands/checks.py +305 -0
- agentic_project_kit/cli_commands/cockpit.py +103 -0
- agentic_project_kit/cli_commands/command_taxonomy.py +25 -0
- agentic_project_kit/cli_commands/commands.py +129 -0
- agentic_project_kit/cli_commands/dev.py +23 -0
- agentic_project_kit/cli_commands/direction.py +92 -0
- agentic_project_kit/cli_commands/doc_currency_audit.py +25 -0
- agentic_project_kit/cli_commands/doc_registry.py +126 -0
- agentic_project_kit/cli_commands/docs.py +223 -0
- agentic_project_kit/cli_commands/dpa.py +1338 -0
- agentic_project_kit/cli_commands/evidence.py +251 -0
- agentic_project_kit/cli_commands/github.py +34 -0
- agentic_project_kit/cli_commands/governance.py +14 -0
- agentic_project_kit/cli_commands/gui.py +23 -0
- agentic_project_kit/cli_commands/gui_readiness_gate.py +27 -0
- agentic_project_kit/cli_commands/handoff.py +183 -0
- agentic_project_kit/cli_commands/human_workflows.py +430 -0
- agentic_project_kit/cli_commands/init.py +132 -0
- agentic_project_kit/cli_commands/instruction.py +75 -0
- agentic_project_kit/cli_commands/mutation_lock_audit.py +24 -0
- agentic_project_kit/cli_commands/ns_legacy_audit.py +25 -0
- agentic_project_kit/cli_commands/pass_already_done.py +66 -0
- agentic_project_kit/cli_commands/patch_failure_discipline_audit.py +26 -0
- agentic_project_kit/cli_commands/patch_preflight.py +37 -0
- agentic_project_kit/cli_commands/path_literal_audit.py +39 -0
- agentic_project_kit/cli_commands/patterns.py +40 -0
- agentic_project_kit/cli_commands/planning_docs_audit.py +25 -0
- agentic_project_kit/cli_commands/pr.py +133 -0
- agentic_project_kit/cli_commands/pr_hygiene.py +27 -0
- agentic_project_kit/cli_commands/profiles.py +26 -0
- agentic_project_kit/cli_commands/program_redundancy_audit.py +25 -0
- agentic_project_kit/cli_commands/project_direction.py +25 -0
- agentic_project_kit/cli_commands/release.py +392 -0
- agentic_project_kit/cli_commands/release_publish_orchestration.py +36 -0
- agentic_project_kit/cli_commands/remote_branch_hygiene.py +152 -0
- agentic_project_kit/cli_commands/remote_next.py +57 -0
- agentic_project_kit/cli_commands/removed_ns_commands.py +65 -0
- agentic_project_kit/cli_commands/rule_registry.py +129 -0
- agentic_project_kit/cli_commands/rules.py +222 -0
- agentic_project_kit/cli_commands/scaffold.py +46 -0
- agentic_project_kit/cli_commands/slice.py +21 -0
- agentic_project_kit/cli_commands/standard_gates_audit_suite.py +27 -0
- agentic_project_kit/cli_commands/state.py +51 -0
- agentic_project_kit/cli_commands/status_current_state_audit.py +30 -0
- agentic_project_kit/cli_commands/todo.py +53 -0
- agentic_project_kit/cli_commands/transfer.py +19 -0
- agentic_project_kit/cli_commands/transfer_context_flow.py +398 -0
- agentic_project_kit/cli_commands/transfer_context_helpers.py +398 -0
- agentic_project_kit/cli_commands/transfer_diagnostics.py +767 -0
- agentic_project_kit/cli_commands/transfer_evidence_flow.py +368 -0
- agentic_project_kit/cli_commands/transfer_handoff_flow.py +594 -0
- agentic_project_kit/cli_commands/transfer_order_contract.py +74 -0
- agentic_project_kit/cli_commands/transfer_post_merge_complete.py +442 -0
- agentic_project_kit/cli_commands/transfer_post_merge_settle.py +171 -0
- agentic_project_kit/cli_commands/transfer_pr_closeout_complete.py +124 -0
- agentic_project_kit/cli_commands/transfer_pr_create_flow.py +743 -0
- agentic_project_kit/cli_commands/transfer_pr_merge_flow.py +547 -0
- agentic_project_kit/cli_commands/transfer_repo_after_pr.py +160 -0
- agentic_project_kit/cli_commands/transfer_repo_pre_pr.py +664 -0
- agentic_project_kit/cli_commands/transfer_runner_flow.py +131 -0
- agentic_project_kit/cli_commands/transfer_runtime_initial.py +194 -0
- agentic_project_kit/cli_commands/transfer_shared.py +274 -0
- agentic_project_kit/cli_commands/validation.py +200 -0
- agentic_project_kit/cli_commands/version.py +27 -0
- agentic_project_kit/cli_commands/work_orders.py +219 -0
- agentic_project_kit/cli_commands/workflow.py +471 -0
- agentic_project_kit/cli_commands/workflow_guard.py +26 -0
- agentic_project_kit/cli_commands/workspace.py +252 -0
- agentic_project_kit/cockpit.py +608 -0
- agentic_project_kit/cockpit_readiness.py +67 -0
- agentic_project_kit/command_authority_audit.py +192 -0
- agentic_project_kit/command_inbox_check.py +103 -0
- agentic_project_kit/command_manifest.py +591 -0
- agentic_project_kit/command_queue_contract.py +161 -0
- agentic_project_kit/command_selector.py +245 -0
- agentic_project_kit/command_taxonomy.py +264 -0
- agentic_project_kit/commit_guard.py +67 -0
- agentic_project_kit/communication_artifact_gc.py +495 -0
- agentic_project_kit/communication_rule_context.py +437 -0
- agentic_project_kit/communication_state.py +115 -0
- agentic_project_kit/composed_wrapper_invariants.py +97 -0
- agentic_project_kit/composite_short_circuit.py +140 -0
- agentic_project_kit/contract.py +251 -0
- agentic_project_kit/control_state.py +83 -0
- agentic_project_kit/doc_currency_audit.py +536 -0
- agentic_project_kit/doc_lifecycle.py +1179 -0
- agentic_project_kit/doc_lifecycle_signals.py +446 -0
- agentic_project_kit/doc_lifecycle_sweep.py +639 -0
- agentic_project_kit/doc_mesh.py +491 -0
- agentic_project_kit/doctor.py +379 -0
- agentic_project_kit/documentation_registry.py +1122 -0
- agentic_project_kit/documentation_system_audit.py +310 -0
- agentic_project_kit/dpa_current_handoff_lifecycle.py +549 -0
- agentic_project_kit/dpa_dp2_decision_readiness.py +362 -0
- agentic_project_kit/dpa_dp3_dp4_adjudication.py +604 -0
- agentic_project_kit/dpa_dp5_block_new_gate.py +294 -0
- agentic_project_kit/dpa_dp5_stage_adoption.py +615 -0
- agentic_project_kit/dpa_dp5_strict_gate.py +187 -0
- agentic_project_kit/dpa_final_closeout.py +627 -0
- agentic_project_kit/dpa_fixture_evidence.py +680 -0
- agentic_project_kit/dpa_maintainer_record_check.py +711 -0
- agentic_project_kit/dpa_post_dp2_scope_assessment.py +734 -0
- agentic_project_kit/dpa_probe_002_readiness.py +509 -0
- agentic_project_kit/dpa_probe_003_readiness.py +417 -0
- agentic_project_kit/dpa_probe_004_readiness.py +437 -0
- agentic_project_kit/dpa_readiness.py +505 -0
- agentic_project_kit/dpa_readonly_probe_execution.py +500 -0
- agentic_project_kit/dpa_registry_contracts.py +312 -0
- agentic_project_kit/dpa_renderer_readiness.py +407 -0
- agentic_project_kit/dpa_repo_adoption_assessment.py +574 -0
- agentic_project_kit/dpa_stable_readiness.py +743 -0
- agentic_project_kit/dpa_successor_projection.py +168 -0
- agentic_project_kit/dpa_workspace_init_projection.py +93 -0
- agentic_project_kit/dpa_wrt_ch001_evidence.py +327 -0
- agentic_project_kit/entrypoint_slice_runner.py +153 -0
- agentic_project_kit/evidence_clean.py +152 -0
- agentic_project_kit/evidence_commit_paths.py +214 -0
- agentic_project_kit/evidence_finalize_log.py +204 -0
- agentic_project_kit/evidence_guard.py +114 -0
- agentic_project_kit/evidence_inspector.py +507 -0
- agentic_project_kit/evidence_state_contract.py +99 -0
- agentic_project_kit/execution_mode_state.py +148 -0
- agentic_project_kit/final_summary_contract.py +85 -0
- agentic_project_kit/finalize_guard.py +139 -0
- agentic_project_kit/gatekeeper_core.py +232 -0
- agentic_project_kit/github.py +25 -0
- agentic_project_kit/governance.py +59 -0
- agentic_project_kit/gui_action_execution.py +105 -0
- agentic_project_kit/gui_action_renderer.py +81 -0
- agentic_project_kit/gui_action_run_intent.py +98 -0
- agentic_project_kit/gui_action_views.py +195 -0
- agentic_project_kit/gui_activity_log.py +76 -0
- agentic_project_kit/gui_button_catalog.py +605 -0
- agentic_project_kit/gui_cockpit.py +365 -0
- agentic_project_kit/gui_cockpit_actions.py +695 -0
- agentic_project_kit/gui_cockpit_common.py +172 -0
- agentic_project_kit/gui_cockpit_header.py +501 -0
- agentic_project_kit/gui_cockpit_sidebar.py +387 -0
- agentic_project_kit/gui_cockpit_task.py +748 -0
- agentic_project_kit/gui_command_projection.py +355 -0
- agentic_project_kit/gui_communication_modes.py +130 -0
- agentic_project_kit/gui_dry_run.py +219 -0
- agentic_project_kit/gui_gatekeeper_status.py +259 -0
- agentic_project_kit/gui_layout_plan.py +148 -0
- agentic_project_kit/gui_open_folder.py +18 -0
- agentic_project_kit/gui_output_status_panel.py +61 -0
- agentic_project_kit/gui_panel_state.py +47 -0
- agentic_project_kit/gui_presenter.py +62 -0
- agentic_project_kit/gui_readiness_gate.py +206 -0
- agentic_project_kit/gui_release_flow.py +59 -0
- agentic_project_kit/gui_task_editor.py +1077 -0
- agentic_project_kit/gui_tk_widgets.py +177 -0
- agentic_project_kit/gui_tkinter_renderer.py +87 -0
- agentic_project_kit/gui_tkinter_shell.py +1176 -0
- agentic_project_kit/gui_transfer_contract.py +28 -0
- agentic_project_kit/gui_viewmodel.py +698 -0
- agentic_project_kit/gui_window_guard.py +46 -0
- agentic_project_kit/handoff_freshness.py +390 -0
- agentic_project_kit/handoff_prompt.py +180 -0
- agentic_project_kit/handoff_state.py +254 -0
- agentic_project_kit/instruction_lint.py +455 -0
- agentic_project_kit/llm_context_carriers.py +66 -0
- agentic_project_kit/llm_execution_context.py +285 -0
- agentic_project_kit/local_command_stack.py +133 -0
- agentic_project_kit/local_feature_gate.py +82 -0
- agentic_project_kit/local_garbage_collector.py +269 -0
- agentic_project_kit/models.py +18 -0
- agentic_project_kit/mutation_lock_audit.py +421 -0
- agentic_project_kit/next_turn_evidence.py +253 -0
- agentic_project_kit/next_turn_merge_if_green.py +459 -0
- agentic_project_kit/next_turn_pr_status.py +255 -0
- agentic_project_kit/next_turn_result.py +183 -0
- agentic_project_kit/next_turn_runner.py +159 -0
- agentic_project_kit/next_turn_slot.py +107 -0
- agentic_project_kit/next_turn_status.py +274 -0
- agentic_project_kit/ns_legacy_reference_audit.py +258 -0
- agentic_project_kit/ns_slice_runner.py +16 -0
- agentic_project_kit/operational_handoff_projection.py +124 -0
- agentic_project_kit/output_contract.py +80 -0
- agentic_project_kit/output_repair.py +61 -0
- agentic_project_kit/pass_already_done.py +216 -0
- agentic_project_kit/patch_artifact_preflight.py +147 -0
- agentic_project_kit/patch_cycle_workflow.py +440 -0
- agentic_project_kit/patch_failure_discipline_audit.py +223 -0
- agentic_project_kit/patch_preflight.py +215 -0
- agentic_project_kit/path_literal_audit.py +612 -0
- agentic_project_kit/patterns.py +99 -0
- agentic_project_kit/planning_docs_consolidation_audit.py +313 -0
- agentic_project_kit/portability_shell_gate.py +40 -0
- agentic_project_kit/post_merge_handoff_refresh.py +56 -0
- agentic_project_kit/post_release.py +252 -0
- agentic_project_kit/post_release_closeout.py +616 -0
- agentic_project_kit/pr_cleanup.py +172 -0
- agentic_project_kit/pr_closeout.py +50 -0
- agentic_project_kit/pr_closeout_complete.py +344 -0
- agentic_project_kit/pr_create_or_skip.py +71 -0
- agentic_project_kit/pr_hygiene.py +210 -0
- agentic_project_kit/program_redundancy_audit.py +251 -0
- agentic_project_kit/project_direction.py +840 -0
- agentic_project_kit/protected_change_planner.py +194 -0
- agentic_project_kit/release.py +401 -0
- agentic_project_kit/release_doi_safety.py +24 -0
- agentic_project_kit/release_gate_core.py +174 -0
- agentic_project_kit/release_metadata_authority_gate.py +328 -0
- agentic_project_kit/release_metadata_prep.py +43 -0
- agentic_project_kit/release_notes.py +823 -0
- agentic_project_kit/release_prep_core.py +204 -0
- agentic_project_kit/release_prepare.py +369 -0
- agentic_project_kit/release_process_guardrails.py +247 -0
- agentic_project_kit/release_publish_core.py +114 -0
- agentic_project_kit/release_publish_orchestration.py +469 -0
- agentic_project_kit/release_state.py +552 -0
- agentic_project_kit/release_verify_core.py +175 -0
- agentic_project_kit/remote_branch_hygiene.py +223 -0
- agentic_project_kit/remote_next.py +89 -0
- agentic_project_kit/remote_next_closeout.py +101 -0
- agentic_project_kit/remote_next_order_contract.py +391 -0
- agentic_project_kit/removed_ns_commands.py +458 -0
- agentic_project_kit/removed_source_audit.py +225 -0
- agentic_project_kit/rendering.py +13 -0
- agentic_project_kit/repair_report.py +79 -0
- agentic_project_kit/repo_identity.py +59 -0
- agentic_project_kit/result_report_classifier.py +57 -0
- agentic_project_kit/rule_ack.py +105 -0
- agentic_project_kit/rule_preservation.py +58 -0
- agentic_project_kit/rule_refresh.py +174 -0
- agentic_project_kit/rule_registry_registration.py +322 -0
- agentic_project_kit/rule_registry_report.py +206 -0
- agentic_project_kit/rule_registry_validator.py +704 -0
- agentic_project_kit/rule_snapshot.py +98 -0
- agentic_project_kit/rule_source_validator.py +133 -0
- agentic_project_kit/run_summary.py +68 -0
- agentic_project_kit/run_summary_renderer.py +238 -0
- agentic_project_kit/runtime_validator.py +68 -0
- agentic_project_kit/safe_file_replace.py +35 -0
- agentic_project_kit/safe_patch.py +47 -0
- agentic_project_kit/safe_push.py +218 -0
- agentic_project_kit/safe_remove_diagnostic.py +51 -0
- agentic_project_kit/scaffold.py +69 -0
- agentic_project_kit/site_claims.py +444 -0
- agentic_project_kit/site_generator.py +1140 -0
- agentic_project_kit/slice_gate.py +225 -0
- agentic_project_kit/slice_runner.py +75 -0
- agentic_project_kit/standard_gates_audit_suite.py +167 -0
- agentic_project_kit/state_freshness.py +135 -0
- agentic_project_kit/status_current_state_audit.py +762 -0
- agentic_project_kit/successor_handoff_package.py +1763 -0
- agentic_project_kit/templates.py +292 -0
- agentic_project_kit/terminal_block_guard.py +166 -0
- agentic_project_kit/terminal_logging.py +275 -0
- agentic_project_kit/todo.py +97 -0
- agentic_project_kit/transfer_closeout.py +136 -0
- agentic_project_kit/transfer_continue.py +215 -0
- agentic_project_kit/transfer_local_runner.py +101 -0
- agentic_project_kit/transfer_operation_monitor.py +236 -0
- agentic_project_kit/transfer_post_merge_lifecycle.py +356 -0
- agentic_project_kit/transfer_post_merge_settle.py +383 -0
- agentic_project_kit/transfer_pr_actions.py +164 -0
- agentic_project_kit/transfer_remote_next.py +959 -0
- agentic_project_kit/transfer_repo_actions.py +2253 -0
- agentic_project_kit/transfer_runner.py +347 -0
- agentic_project_kit/transfer_safety_context.py +291 -0
- agentic_project_kit/transfer_state.py +483 -0
- agentic_project_kit/transfer_uplink.py +471 -0
- agentic_project_kit/transfer_workflow_next.py +148 -0
- agentic_project_kit/typed_work_order_evidence.py +58 -0
- agentic_project_kit/typed_work_order_queue.py +166 -0
- agentic_project_kit/typed_work_order_runner.py +168 -0
- agentic_project_kit/work_cycle.py +317 -0
- agentic_project_kit/work_discard_changes.py +129 -0
- agentic_project_kit/work_order_patch.py +199 -0
- agentic_project_kit/work_order_runner.py +120 -0
- agentic_project_kit/work_order_uploader.py +220 -0
- agentic_project_kit/work_order_validator.py +185 -0
- agentic_project_kit/work_orders.py +246 -0
- agentic_project_kit/workflow_guard.py +262 -0
- agentic_project_kit/workflow_summary_runner.py +124 -0
- agentic_project_kit/workspace.py +665 -0
- agentic_project_kit/workspace_adopt.py +471 -0
- agentic_project_kit/workspace_dpa_intake.py +406 -0
- agentic_project_kit/workspace_init.py +487 -0
- agentic_project_kit/workspace_lock.py +129 -0
- agentic_project_kit/workspace_remove.py +381 -0
- agentic_project_kit/workspace_upgrade.py +324 -0
- agentic_project_kit/wrapper_live_status.py +104 -0
- agentic_project_kit-1.0.1.dist-info/METADATA +724 -0
- agentic_project_kit-1.0.1.dist-info/RECORD +310 -0
- agentic_project_kit-1.0.1.dist-info/WHEEL +4 -0
- agentic_project_kit-1.0.1.dist-info/entry_points.txt +3 -0
- agentic_project_kit-1.0.1.dist-info/licenses/LICENSE +10 -0
|
@@ -0,0 +1,1338 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
|
|
8
|
+
from agentic_project_kit.dpa_dp3_dp4_adjudication import (
|
|
9
|
+
DEFAULT_DP3_DP4_ADJUDICATION_RECORD_PATH,
|
|
10
|
+
evaluate_dp3_dp4_adjudication_record,
|
|
11
|
+
render_dp3_dp4_adjudication_check,
|
|
12
|
+
write_dp3_dp4_adjudication_check_json,
|
|
13
|
+
)
|
|
14
|
+
from agentic_project_kit.dpa_dp5_block_new_gate import (
|
|
15
|
+
DEFAULT_DP5_BLOCK_NEW_BASELINE_PATH,
|
|
16
|
+
DEFAULT_DP5_BLOCK_NEW_STAGE_RECORD_PATH,
|
|
17
|
+
evaluate_dp5_block_new_gate,
|
|
18
|
+
render_dp5_block_new_gate,
|
|
19
|
+
write_dp5_block_new_gate_json,
|
|
20
|
+
)
|
|
21
|
+
from agentic_project_kit.dpa_dp5_strict_gate import (
|
|
22
|
+
evaluate_dp5_strict_gate,
|
|
23
|
+
render_dp5_strict_gate,
|
|
24
|
+
write_dp5_strict_gate_json,
|
|
25
|
+
)
|
|
26
|
+
from agentic_project_kit.dpa_final_closeout import (
|
|
27
|
+
DEFAULT_DPA_FINAL_CLOSEOUT_RECORD_PATH,
|
|
28
|
+
evaluate_dpa_final_closeout_record,
|
|
29
|
+
render_dpa_final_closeout_check,
|
|
30
|
+
write_dpa_final_closeout_check_json,
|
|
31
|
+
)
|
|
32
|
+
from agentic_project_kit.dpa_dp5_stage_adoption import (
|
|
33
|
+
DEFAULT_DP5_STAGE_RECORD_PATH,
|
|
34
|
+
evaluate_dp5_stage_record,
|
|
35
|
+
render_dp5_stage_check,
|
|
36
|
+
write_dp5_stage_check_json,
|
|
37
|
+
)
|
|
38
|
+
from agentic_project_kit.dpa_dp2_decision_readiness import (
|
|
39
|
+
evaluate_dp2_decision_readiness,
|
|
40
|
+
render_dp2_decision_readiness,
|
|
41
|
+
write_dp2_decision_readiness_json,
|
|
42
|
+
)
|
|
43
|
+
from agentic_project_kit.dpa_fixture_evidence import (
|
|
44
|
+
AUTHORIZATION_TOKEN,
|
|
45
|
+
evaluate_dpa_fixture_evidence,
|
|
46
|
+
render_dpa_fixture_evidence,
|
|
47
|
+
write_dpa_fixture_evidence_json,
|
|
48
|
+
)
|
|
49
|
+
from agentic_project_kit.dpa_maintainer_record_check import (
|
|
50
|
+
DEFAULT_MAINTAINER_RECORD_PATH,
|
|
51
|
+
evaluate_dp2_maintainer_record,
|
|
52
|
+
render_dp2_maintainer_record_check,
|
|
53
|
+
write_dp2_maintainer_record_check_json,
|
|
54
|
+
)
|
|
55
|
+
from agentic_project_kit.dpa_current_handoff_lifecycle import (
|
|
56
|
+
DEFAULT_ACCEPTANCE_STATE_PATH,
|
|
57
|
+
evaluate_current_handoff_lifecycle,
|
|
58
|
+
render_current_handoff_lifecycle_result,
|
|
59
|
+
)
|
|
60
|
+
from agentic_project_kit.dpa_probe_002_readiness import (
|
|
61
|
+
evaluate_probe_002_lifecycle_readiness,
|
|
62
|
+
render_probe_002_lifecycle_readiness,
|
|
63
|
+
write_probe_002_readiness_json,
|
|
64
|
+
)
|
|
65
|
+
from agentic_project_kit.dpa_probe_003_readiness import (
|
|
66
|
+
evaluate_probe_003_workflow_readiness,
|
|
67
|
+
render_probe_003_workflow_readiness,
|
|
68
|
+
write_probe_003_readiness_json,
|
|
69
|
+
)
|
|
70
|
+
from agentic_project_kit.dpa_probe_004_readiness import (
|
|
71
|
+
evaluate_probe_004_migration_readiness,
|
|
72
|
+
render_probe_004_migration_readiness,
|
|
73
|
+
write_probe_004_readiness_json,
|
|
74
|
+
)
|
|
75
|
+
from agentic_project_kit.dpa_post_dp2_scope_assessment import (
|
|
76
|
+
evaluate_post_dp2_scope_assessment,
|
|
77
|
+
render_post_dp2_scope_assessment,
|
|
78
|
+
write_post_dp2_scope_assessment_json,
|
|
79
|
+
)
|
|
80
|
+
from agentic_project_kit.dpa_readiness import (
|
|
81
|
+
DEFAULT_READINESS_PATH,
|
|
82
|
+
evaluate_dpa_readiness,
|
|
83
|
+
render_dpa_readiness_result,
|
|
84
|
+
)
|
|
85
|
+
from agentic_project_kit.dpa_repo_adoption_assessment import (
|
|
86
|
+
evaluate_dpa_repo_adoption_assessment,
|
|
87
|
+
render_dpa_repo_adoption_assessment,
|
|
88
|
+
write_dpa_repo_adoption_assessment_json,
|
|
89
|
+
)
|
|
90
|
+
from agentic_project_kit.dpa_readonly_probe_execution import (
|
|
91
|
+
DEFAULT_FIXTURE_MANIFEST_PATH,
|
|
92
|
+
evaluate_dpa_readonly_probe_execution,
|
|
93
|
+
render_dpa_readonly_probe_execution,
|
|
94
|
+
write_dpa_readonly_probe_execution_json,
|
|
95
|
+
)
|
|
96
|
+
from agentic_project_kit.dpa_renderer_readiness import (
|
|
97
|
+
evaluate_renderer_probe_readiness,
|
|
98
|
+
render_renderer_probe_readiness,
|
|
99
|
+
write_renderer_readiness_json,
|
|
100
|
+
)
|
|
101
|
+
from agentic_project_kit.dpa_stable_readiness import (
|
|
102
|
+
DEFAULT_DPA_STABLE_PROMOTION_RECORD_PATH,
|
|
103
|
+
evaluate_dpa_stable_readiness,
|
|
104
|
+
render_dpa_stable_readiness,
|
|
105
|
+
write_dpa_stable_readiness_json,
|
|
106
|
+
)
|
|
107
|
+
from agentic_project_kit.dpa_wrt_ch001_evidence import (
|
|
108
|
+
evaluate_wrt_ch001_admin_refresh_observation,
|
|
109
|
+
fetch_admin_refresh_pr_data,
|
|
110
|
+
load_pr_data,
|
|
111
|
+
render_wrt_ch001_evidence,
|
|
112
|
+
write_wrt_ch001_evidence_json,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
dpa_app = typer.Typer(help="Inspect Document Projection Architecture readiness state.")
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@dpa_app.command("readiness")
|
|
119
|
+
def dpa_readiness_command(
|
|
120
|
+
root: Path = typer.Option(Path("."), "--root", help="Repository root."),
|
|
121
|
+
record: Path = typer.Option(
|
|
122
|
+
DEFAULT_READINESS_PATH,
|
|
123
|
+
"--record",
|
|
124
|
+
help="DPA Assessment readiness JSON record to inspect.",
|
|
125
|
+
),
|
|
126
|
+
output_json: bool = typer.Option(False, "--json", help="Print machine-readable JSON."),
|
|
127
|
+
require_dp2_ready: bool = typer.Option(
|
|
128
|
+
False,
|
|
129
|
+
"--require-dp2-ready",
|
|
130
|
+
help="Fail unless the readiness record structurally authorizes DP2.",
|
|
131
|
+
),
|
|
132
|
+
) -> None:
|
|
133
|
+
"""Validate the DPA DP1 Assessment readiness record without mutating files."""
|
|
134
|
+
result = evaluate_dpa_readiness(root, readiness_path=record)
|
|
135
|
+
if output_json:
|
|
136
|
+
typer.echo(json.dumps(result.as_dict(), indent=2))
|
|
137
|
+
else:
|
|
138
|
+
typer.echo(render_dpa_readiness_result(result), nl=False)
|
|
139
|
+
if result.findings or (require_dp2_ready and not result.dp2_ready):
|
|
140
|
+
raise typer.Exit(1)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@dpa_app.command("repo-adoption-assessment")
|
|
144
|
+
def dpa_repo_adoption_assessment_command(
|
|
145
|
+
root: Path = typer.Option(Path("."), "--root", help="Target repository root."),
|
|
146
|
+
validation_ref: str | None = typer.Option(
|
|
147
|
+
None,
|
|
148
|
+
"--validation-ref",
|
|
149
|
+
help="Optional exact current ref to record instead of repository HEAD.",
|
|
150
|
+
),
|
|
151
|
+
output: Path | None = typer.Option(
|
|
152
|
+
None,
|
|
153
|
+
"--output",
|
|
154
|
+
help="Optional DPA Assessment evidence JSON path under docs/architecture/evidence/dpa/assessment/.",
|
|
155
|
+
),
|
|
156
|
+
execute: bool = typer.Option(False, "--execute", help="Write --output when supplied."),
|
|
157
|
+
output_json: bool = typer.Option(False, "--json", help="Print machine-readable JSON."),
|
|
158
|
+
require_ready: bool = typer.Option(
|
|
159
|
+
False,
|
|
160
|
+
"--require-ready",
|
|
161
|
+
help="Fail unless the target repo is ready for DPA adoption adjudication.",
|
|
162
|
+
),
|
|
163
|
+
) -> None:
|
|
164
|
+
"""Assess a foreign or new repo for DPA-governed adoption without mutation."""
|
|
165
|
+
resolved_root = root.resolve()
|
|
166
|
+
result = evaluate_dpa_repo_adoption_assessment(
|
|
167
|
+
resolved_root,
|
|
168
|
+
validation_ref=validation_ref,
|
|
169
|
+
)
|
|
170
|
+
write_result = None
|
|
171
|
+
if output is not None:
|
|
172
|
+
write_result = write_dpa_repo_adoption_assessment_json(
|
|
173
|
+
result,
|
|
174
|
+
resolved_root,
|
|
175
|
+
output,
|
|
176
|
+
execute=execute,
|
|
177
|
+
)
|
|
178
|
+
payload = result.as_dict()
|
|
179
|
+
if write_result is not None:
|
|
180
|
+
payload["evidence_write"] = write_result
|
|
181
|
+
if output_json:
|
|
182
|
+
typer.echo(json.dumps(payload, indent=2, sort_keys=True))
|
|
183
|
+
else:
|
|
184
|
+
typer.echo(render_dpa_repo_adoption_assessment(result), nl=False)
|
|
185
|
+
if write_result is not None:
|
|
186
|
+
reason = f"|reason={write_result['reason']}" if "reason" in write_result else ""
|
|
187
|
+
typer.echo(
|
|
188
|
+
"EVIDENCE_WRITE="
|
|
189
|
+
f"{write_result['result_status']}|"
|
|
190
|
+
f"path={write_result['output_path']}|"
|
|
191
|
+
f"written={str(write_result.get('written', False)).lower()}"
|
|
192
|
+
f"{reason}"
|
|
193
|
+
)
|
|
194
|
+
if write_result is not None and write_result["result_status"] == "BLOCK":
|
|
195
|
+
raise typer.Exit(2)
|
|
196
|
+
if require_ready and not result.ok:
|
|
197
|
+
raise typer.Exit(1)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
@dpa_app.command("post-dp2-scope-assessment")
|
|
201
|
+
def dpa_post_dp2_scope_assessment_command(
|
|
202
|
+
root: Path = typer.Option(Path("."), "--root", help="Repository root."),
|
|
203
|
+
record: Path = typer.Option(
|
|
204
|
+
DEFAULT_READINESS_PATH,
|
|
205
|
+
"--record",
|
|
206
|
+
help="DPA Assessment readiness JSON record to inspect.",
|
|
207
|
+
),
|
|
208
|
+
adjudication_record: Path = typer.Option(
|
|
209
|
+
DEFAULT_DP3_DP4_ADJUDICATION_RECORD_PATH,
|
|
210
|
+
"--adjudication-record",
|
|
211
|
+
help="Optional DP3/DP4 adjudication record to inspect when clearing post-DP2 blockers.",
|
|
212
|
+
),
|
|
213
|
+
dp5_stage_record: Path = typer.Option(
|
|
214
|
+
DEFAULT_DP5_STAGE_RECORD_PATH,
|
|
215
|
+
"--dp5-stage-record",
|
|
216
|
+
help="Optional DP5 stage-adoption record to inspect when clearing stage blockers.",
|
|
217
|
+
),
|
|
218
|
+
validation_ref: str | None = typer.Option(
|
|
219
|
+
None,
|
|
220
|
+
"--validation-ref",
|
|
221
|
+
help="Optional exact target ref to record instead of the current repository HEAD.",
|
|
222
|
+
),
|
|
223
|
+
output: Path | None = typer.Option(
|
|
224
|
+
None,
|
|
225
|
+
"--output",
|
|
226
|
+
help="Optional DPA Assessment evidence JSON path under docs/architecture/evidence/dpa/assessment/.",
|
|
227
|
+
),
|
|
228
|
+
execute: bool = typer.Option(False, "--execute", help="Write --output when supplied."),
|
|
229
|
+
output_json: bool = typer.Option(False, "--json", help="Print machine-readable JSON."),
|
|
230
|
+
require_closeout_ready: bool = typer.Option(
|
|
231
|
+
False,
|
|
232
|
+
"--require-closeout-ready",
|
|
233
|
+
help="Fail unless DP3, DP4, DP5 and final closeout are structurally ready.",
|
|
234
|
+
),
|
|
235
|
+
) -> None:
|
|
236
|
+
"""Assess post-DP2 DP3-DP5 rollout, migration and strict-gate scope."""
|
|
237
|
+
resolved_root = root.resolve()
|
|
238
|
+
result = evaluate_post_dp2_scope_assessment(
|
|
239
|
+
resolved_root,
|
|
240
|
+
readiness_path=record,
|
|
241
|
+
adjudication_record_path=adjudication_record,
|
|
242
|
+
dp5_stage_record_path=dp5_stage_record,
|
|
243
|
+
validation_ref=validation_ref,
|
|
244
|
+
)
|
|
245
|
+
write_result = None
|
|
246
|
+
if output is not None:
|
|
247
|
+
write_result = write_post_dp2_scope_assessment_json(
|
|
248
|
+
result,
|
|
249
|
+
resolved_root,
|
|
250
|
+
output,
|
|
251
|
+
execute=execute,
|
|
252
|
+
)
|
|
253
|
+
payload = result.as_dict()
|
|
254
|
+
if write_result is not None:
|
|
255
|
+
payload["evidence_write"] = write_result
|
|
256
|
+
if output_json:
|
|
257
|
+
typer.echo(json.dumps(payload, indent=2, sort_keys=True))
|
|
258
|
+
else:
|
|
259
|
+
typer.echo(render_post_dp2_scope_assessment(result), nl=False)
|
|
260
|
+
if write_result is not None:
|
|
261
|
+
reason = f"|reason={write_result['reason']}" if "reason" in write_result else ""
|
|
262
|
+
typer.echo(
|
|
263
|
+
"EVIDENCE_WRITE="
|
|
264
|
+
f"{write_result['result_status']}|"
|
|
265
|
+
f"path={write_result['output_path']}|"
|
|
266
|
+
f"written={str(write_result.get('written', False)).lower()}"
|
|
267
|
+
f"{reason}"
|
|
268
|
+
)
|
|
269
|
+
if write_result is not None and write_result["result_status"] == "BLOCK":
|
|
270
|
+
raise typer.Exit(2)
|
|
271
|
+
if result.findings:
|
|
272
|
+
raise typer.Exit(2)
|
|
273
|
+
if require_closeout_ready and not result.final_closeout_ready:
|
|
274
|
+
raise typer.Exit(1)
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
@dpa_app.command("dp3-dp4-adjudication-check")
|
|
278
|
+
def dpa_dp3_dp4_adjudication_check_command(
|
|
279
|
+
root: Path = typer.Option(Path("."), "--root", help="Repository root."),
|
|
280
|
+
record: Path = typer.Option(
|
|
281
|
+
DEFAULT_DP3_DP4_ADJUDICATION_RECORD_PATH,
|
|
282
|
+
"--record",
|
|
283
|
+
help="DPA DP3/DP4 bounded adjudication record to inspect.",
|
|
284
|
+
),
|
|
285
|
+
validation_ref: str | None = typer.Option(
|
|
286
|
+
None,
|
|
287
|
+
"--validation-ref",
|
|
288
|
+
help="Optional exact current ref to record instead of repository HEAD.",
|
|
289
|
+
),
|
|
290
|
+
output: Path | None = typer.Option(
|
|
291
|
+
None,
|
|
292
|
+
"--output",
|
|
293
|
+
help="Optional DPA Assessment evidence JSON path under docs/architecture/evidence/dpa/assessment/.",
|
|
294
|
+
),
|
|
295
|
+
execute: bool = typer.Option(False, "--execute", help="Write --output when supplied."),
|
|
296
|
+
output_json: bool = typer.Option(False, "--json", help="Print machine-readable JSON."),
|
|
297
|
+
require_valid: bool = typer.Option(
|
|
298
|
+
False,
|
|
299
|
+
"--require-valid",
|
|
300
|
+
help="Fail unless the record structurally accepts the bounded DP3/DP4 slice.",
|
|
301
|
+
),
|
|
302
|
+
) -> None:
|
|
303
|
+
"""Validate a bounded DP3/DP4 adjudication record without authorizing DP5."""
|
|
304
|
+
resolved_root = root.resolve()
|
|
305
|
+
result = evaluate_dp3_dp4_adjudication_record(
|
|
306
|
+
resolved_root,
|
|
307
|
+
record_path=record,
|
|
308
|
+
validation_ref=validation_ref,
|
|
309
|
+
)
|
|
310
|
+
write_result = None
|
|
311
|
+
if output is not None:
|
|
312
|
+
write_result = write_dp3_dp4_adjudication_check_json(
|
|
313
|
+
result,
|
|
314
|
+
resolved_root,
|
|
315
|
+
output,
|
|
316
|
+
execute=execute,
|
|
317
|
+
)
|
|
318
|
+
payload = result.as_dict()
|
|
319
|
+
if write_result is not None:
|
|
320
|
+
payload["evidence_write"] = write_result
|
|
321
|
+
if output_json:
|
|
322
|
+
typer.echo(json.dumps(payload, indent=2, sort_keys=True))
|
|
323
|
+
else:
|
|
324
|
+
typer.echo(render_dp3_dp4_adjudication_check(result), nl=False)
|
|
325
|
+
if write_result is not None:
|
|
326
|
+
reason = f"|reason={write_result['reason']}" if "reason" in write_result else ""
|
|
327
|
+
typer.echo(
|
|
328
|
+
"EVIDENCE_WRITE="
|
|
329
|
+
f"{write_result['result_status']}|"
|
|
330
|
+
f"path={write_result['output_path']}|"
|
|
331
|
+
f"written={str(write_result.get('written', False)).lower()}"
|
|
332
|
+
f"{reason}"
|
|
333
|
+
)
|
|
334
|
+
if write_result is not None and write_result["result_status"] == "BLOCK":
|
|
335
|
+
raise typer.Exit(2)
|
|
336
|
+
if result.findings:
|
|
337
|
+
raise typer.Exit(2)
|
|
338
|
+
if require_valid and not result.ok:
|
|
339
|
+
raise typer.Exit(1)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
@dpa_app.command("dp5-stage-check")
|
|
343
|
+
def dpa_dp5_stage_check_command(
|
|
344
|
+
root: Path = typer.Option(Path("."), "--root", help="Repository root."),
|
|
345
|
+
record: Path = typer.Option(
|
|
346
|
+
DEFAULT_DP5_STAGE_RECORD_PATH,
|
|
347
|
+
"--record",
|
|
348
|
+
help="DPA DP5 stage-adoption record to inspect.",
|
|
349
|
+
),
|
|
350
|
+
validation_ref: str | None = typer.Option(
|
|
351
|
+
None,
|
|
352
|
+
"--validation-ref",
|
|
353
|
+
help="Optional exact current ref to record instead of repository HEAD.",
|
|
354
|
+
),
|
|
355
|
+
output: Path | None = typer.Option(
|
|
356
|
+
None,
|
|
357
|
+
"--output",
|
|
358
|
+
help="Optional DPA Assessment evidence JSON path under docs/architecture/evidence/dpa/assessment/.",
|
|
359
|
+
),
|
|
360
|
+
execute: bool = typer.Option(False, "--execute", help="Write --output when supplied."),
|
|
361
|
+
output_json: bool = typer.Option(False, "--json", help="Print machine-readable JSON."),
|
|
362
|
+
require_valid: bool = typer.Option(
|
|
363
|
+
False,
|
|
364
|
+
"--require-valid",
|
|
365
|
+
help="Fail unless the DP5 stage record is structurally valid.",
|
|
366
|
+
),
|
|
367
|
+
) -> None:
|
|
368
|
+
"""Validate a bounded DP5 lifecycle stage record."""
|
|
369
|
+
resolved_root = root.resolve()
|
|
370
|
+
result = evaluate_dp5_stage_record(
|
|
371
|
+
resolved_root,
|
|
372
|
+
record_path=record,
|
|
373
|
+
validation_ref=validation_ref,
|
|
374
|
+
)
|
|
375
|
+
write_result = None
|
|
376
|
+
if output is not None:
|
|
377
|
+
write_result = write_dp5_stage_check_json(
|
|
378
|
+
result,
|
|
379
|
+
resolved_root,
|
|
380
|
+
output,
|
|
381
|
+
execute=execute,
|
|
382
|
+
)
|
|
383
|
+
payload = result.as_dict()
|
|
384
|
+
if write_result is not None:
|
|
385
|
+
payload["evidence_write"] = write_result
|
|
386
|
+
if output_json:
|
|
387
|
+
typer.echo(json.dumps(payload, indent=2, sort_keys=True))
|
|
388
|
+
else:
|
|
389
|
+
typer.echo(render_dp5_stage_check(result), nl=False)
|
|
390
|
+
if write_result is not None:
|
|
391
|
+
reason = f"|reason={write_result['reason']}" if "reason" in write_result else ""
|
|
392
|
+
typer.echo(
|
|
393
|
+
"EVIDENCE_WRITE="
|
|
394
|
+
f"{write_result['result_status']}|"
|
|
395
|
+
f"path={write_result['output_path']}|"
|
|
396
|
+
f"written={str(write_result.get('written', False)).lower()}"
|
|
397
|
+
f"{reason}"
|
|
398
|
+
)
|
|
399
|
+
if write_result is not None and write_result["result_status"] == "BLOCK":
|
|
400
|
+
raise typer.Exit(2)
|
|
401
|
+
if result.findings:
|
|
402
|
+
raise typer.Exit(2)
|
|
403
|
+
if require_valid and not result.ok:
|
|
404
|
+
raise typer.Exit(1)
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
@dpa_app.command("dp5-block-new-gate")
|
|
408
|
+
def dpa_dp5_block_new_gate_command(
|
|
409
|
+
root: Path = typer.Option(Path("."), "--root", help="Repository root."),
|
|
410
|
+
baseline: Path = typer.Option(
|
|
411
|
+
DEFAULT_DP5_BLOCK_NEW_BASELINE_PATH,
|
|
412
|
+
"--baseline",
|
|
413
|
+
help="Accepted DP5 warn-stage baseline assessment to compare against.",
|
|
414
|
+
),
|
|
415
|
+
dp5_stage_record: Path = typer.Option(
|
|
416
|
+
DEFAULT_DP5_BLOCK_NEW_STAGE_RECORD_PATH,
|
|
417
|
+
"--dp5-stage-record",
|
|
418
|
+
help="DP5 block-new stage-adoption record to inspect.",
|
|
419
|
+
),
|
|
420
|
+
validation_ref: str | None = typer.Option(
|
|
421
|
+
None,
|
|
422
|
+
"--validation-ref",
|
|
423
|
+
help="Optional exact current ref to record instead of repository HEAD.",
|
|
424
|
+
),
|
|
425
|
+
output: Path | None = typer.Option(
|
|
426
|
+
None,
|
|
427
|
+
"--output",
|
|
428
|
+
help="Optional DPA Assessment evidence JSON path under docs/architecture/evidence/dpa/assessment/.",
|
|
429
|
+
),
|
|
430
|
+
execute: bool = typer.Option(False, "--execute", help="Write --output when supplied."),
|
|
431
|
+
output_json: bool = typer.Option(False, "--json", help="Print machine-readable JSON."),
|
|
432
|
+
require_pass: bool = typer.Option(
|
|
433
|
+
False,
|
|
434
|
+
"--require-pass",
|
|
435
|
+
help="Fail unless no new DP5 noncompliance is present against the accepted warn baseline.",
|
|
436
|
+
),
|
|
437
|
+
) -> None:
|
|
438
|
+
"""Block new DP5 noncompliance against the accepted warn-stage baseline."""
|
|
439
|
+
resolved_root = root.resolve()
|
|
440
|
+
result = evaluate_dp5_block_new_gate(
|
|
441
|
+
resolved_root,
|
|
442
|
+
baseline_path=baseline,
|
|
443
|
+
dp5_stage_record_path=dp5_stage_record,
|
|
444
|
+
validation_ref=validation_ref,
|
|
445
|
+
)
|
|
446
|
+
write_result = None
|
|
447
|
+
if output is not None:
|
|
448
|
+
write_result = write_dp5_block_new_gate_json(
|
|
449
|
+
result,
|
|
450
|
+
resolved_root,
|
|
451
|
+
output,
|
|
452
|
+
execute=execute,
|
|
453
|
+
)
|
|
454
|
+
payload = result.as_dict()
|
|
455
|
+
if write_result is not None:
|
|
456
|
+
payload["evidence_write"] = write_result
|
|
457
|
+
if output_json:
|
|
458
|
+
typer.echo(json.dumps(payload, indent=2, sort_keys=True))
|
|
459
|
+
else:
|
|
460
|
+
typer.echo(render_dp5_block_new_gate(result), nl=False)
|
|
461
|
+
if write_result is not None:
|
|
462
|
+
reason = f"|reason={write_result['reason']}" if "reason" in write_result else ""
|
|
463
|
+
typer.echo(
|
|
464
|
+
"EVIDENCE_WRITE="
|
|
465
|
+
f"{write_result['result_status']}|"
|
|
466
|
+
f"path={write_result['output_path']}|"
|
|
467
|
+
f"written={str(write_result.get('written', False)).lower()}"
|
|
468
|
+
f"{reason}"
|
|
469
|
+
)
|
|
470
|
+
if write_result is not None and write_result["result_status"] == "BLOCK":
|
|
471
|
+
raise typer.Exit(2)
|
|
472
|
+
if result.findings:
|
|
473
|
+
raise typer.Exit(2)
|
|
474
|
+
if require_pass and not result.ok:
|
|
475
|
+
raise typer.Exit(1)
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
@dpa_app.command("dp5-strict-gate")
|
|
479
|
+
def dpa_dp5_strict_gate_command(
|
|
480
|
+
root: Path = typer.Option(Path("."), "--root", help="Repository root."),
|
|
481
|
+
dp5_stage_record: Path = typer.Option(
|
|
482
|
+
DEFAULT_DP5_STAGE_RECORD_PATH,
|
|
483
|
+
"--dp5-stage-record",
|
|
484
|
+
help="DP5 strict stage-adoption record to inspect.",
|
|
485
|
+
),
|
|
486
|
+
validation_ref: str | None = typer.Option(
|
|
487
|
+
None,
|
|
488
|
+
"--validation-ref",
|
|
489
|
+
help="Optional exact current ref to record instead of repository HEAD.",
|
|
490
|
+
),
|
|
491
|
+
output: Path | None = typer.Option(
|
|
492
|
+
None,
|
|
493
|
+
"--output",
|
|
494
|
+
help="Optional DPA Assessment evidence JSON path under docs/architecture/evidence/dpa/assessment/.",
|
|
495
|
+
),
|
|
496
|
+
execute: bool = typer.Option(False, "--execute", help="Write --output when supplied."),
|
|
497
|
+
output_json: bool = typer.Option(False, "--json", help="Print machine-readable JSON."),
|
|
498
|
+
require_pass: bool = typer.Option(
|
|
499
|
+
False,
|
|
500
|
+
"--require-pass",
|
|
501
|
+
help="Fail unless strict has zero configured noncompliance in the accepted DPA scope.",
|
|
502
|
+
),
|
|
503
|
+
) -> None:
|
|
504
|
+
"""Block all configured DP5 noncompliance in the accepted DPA scope."""
|
|
505
|
+
resolved_root = root.resolve()
|
|
506
|
+
result = evaluate_dp5_strict_gate(
|
|
507
|
+
resolved_root,
|
|
508
|
+
dp5_stage_record_path=dp5_stage_record,
|
|
509
|
+
validation_ref=validation_ref,
|
|
510
|
+
)
|
|
511
|
+
write_result = None
|
|
512
|
+
if output is not None:
|
|
513
|
+
write_result = write_dp5_strict_gate_json(
|
|
514
|
+
result,
|
|
515
|
+
resolved_root,
|
|
516
|
+
output,
|
|
517
|
+
execute=execute,
|
|
518
|
+
)
|
|
519
|
+
payload = result.as_dict()
|
|
520
|
+
if write_result is not None:
|
|
521
|
+
payload["evidence_write"] = write_result
|
|
522
|
+
if output_json:
|
|
523
|
+
typer.echo(json.dumps(payload, indent=2, sort_keys=True))
|
|
524
|
+
else:
|
|
525
|
+
typer.echo(render_dp5_strict_gate(result), nl=False)
|
|
526
|
+
if write_result is not None:
|
|
527
|
+
reason = f"|reason={write_result['reason']}" if "reason" in write_result else ""
|
|
528
|
+
typer.echo(
|
|
529
|
+
"EVIDENCE_WRITE="
|
|
530
|
+
f"{write_result['result_status']}|"
|
|
531
|
+
f"path={write_result['output_path']}|"
|
|
532
|
+
f"written={str(write_result.get('written', False)).lower()}"
|
|
533
|
+
f"{reason}"
|
|
534
|
+
)
|
|
535
|
+
if write_result is not None and write_result["result_status"] == "BLOCK":
|
|
536
|
+
raise typer.Exit(2)
|
|
537
|
+
if result.findings:
|
|
538
|
+
raise typer.Exit(2)
|
|
539
|
+
if require_pass and not result.ok:
|
|
540
|
+
raise typer.Exit(1)
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
@dpa_app.command("final-closeout-check")
|
|
544
|
+
def dpa_final_closeout_check_command(
|
|
545
|
+
root: Path = typer.Option(Path("."), "--root", help="Repository root."),
|
|
546
|
+
record: Path = typer.Option(
|
|
547
|
+
DEFAULT_DPA_FINAL_CLOSEOUT_RECORD_PATH,
|
|
548
|
+
"--record",
|
|
549
|
+
help="DPA final closeout record to inspect.",
|
|
550
|
+
),
|
|
551
|
+
validation_ref: str | None = typer.Option(
|
|
552
|
+
None,
|
|
553
|
+
"--validation-ref",
|
|
554
|
+
help="Optional exact current ref to record instead of repository HEAD.",
|
|
555
|
+
),
|
|
556
|
+
output: Path | None = typer.Option(
|
|
557
|
+
None,
|
|
558
|
+
"--output",
|
|
559
|
+
help="Optional DPA Assessment evidence JSON path under docs/architecture/evidence/dpa/assessment/.",
|
|
560
|
+
),
|
|
561
|
+
execute: bool = typer.Option(False, "--execute", help="Write --output when supplied."),
|
|
562
|
+
output_json: bool = typer.Option(False, "--json", help="Print machine-readable JSON."),
|
|
563
|
+
require_valid: bool = typer.Option(
|
|
564
|
+
False,
|
|
565
|
+
"--require-valid",
|
|
566
|
+
help="Fail unless the final closeout record is structurally valid.",
|
|
567
|
+
),
|
|
568
|
+
) -> None:
|
|
569
|
+
"""Validate the bounded DP1-DP5 final closeout record."""
|
|
570
|
+
resolved_root = root.resolve()
|
|
571
|
+
result = evaluate_dpa_final_closeout_record(
|
|
572
|
+
resolved_root,
|
|
573
|
+
record_path=record,
|
|
574
|
+
validation_ref=validation_ref,
|
|
575
|
+
)
|
|
576
|
+
write_result = None
|
|
577
|
+
if output is not None:
|
|
578
|
+
write_result = write_dpa_final_closeout_check_json(
|
|
579
|
+
result,
|
|
580
|
+
resolved_root,
|
|
581
|
+
output,
|
|
582
|
+
execute=execute,
|
|
583
|
+
)
|
|
584
|
+
payload = result.as_dict()
|
|
585
|
+
if write_result is not None:
|
|
586
|
+
payload["evidence_write"] = write_result
|
|
587
|
+
if output_json:
|
|
588
|
+
typer.echo(json.dumps(payload, indent=2, sort_keys=True))
|
|
589
|
+
else:
|
|
590
|
+
typer.echo(render_dpa_final_closeout_check(result), nl=False)
|
|
591
|
+
if write_result is not None:
|
|
592
|
+
reason = f"|reason={write_result['reason']}" if "reason" in write_result else ""
|
|
593
|
+
typer.echo(
|
|
594
|
+
"EVIDENCE_WRITE="
|
|
595
|
+
f"{write_result['result_status']}|"
|
|
596
|
+
f"path={write_result['output_path']}|"
|
|
597
|
+
f"written={str(write_result.get('written', False)).lower()}"
|
|
598
|
+
f"{reason}"
|
|
599
|
+
)
|
|
600
|
+
if write_result is not None and write_result["result_status"] == "BLOCK":
|
|
601
|
+
raise typer.Exit(2)
|
|
602
|
+
if result.findings:
|
|
603
|
+
raise typer.Exit(2)
|
|
604
|
+
if require_valid and not result.ok:
|
|
605
|
+
raise typer.Exit(1)
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
@dpa_app.command("stable-readiness-check")
|
|
609
|
+
def dpa_stable_readiness_check_command(
|
|
610
|
+
root: Path = typer.Option(Path("."), "--root", help="Repository root."),
|
|
611
|
+
record: Path = typer.Option(
|
|
612
|
+
DEFAULT_DPA_STABLE_PROMOTION_RECORD_PATH,
|
|
613
|
+
"--record",
|
|
614
|
+
help="DPA Stable Promotion record to inspect.",
|
|
615
|
+
),
|
|
616
|
+
validation_ref: str | None = typer.Option(
|
|
617
|
+
None,
|
|
618
|
+
"--validation-ref",
|
|
619
|
+
help="Optional exact current ref to record instead of repository HEAD.",
|
|
620
|
+
),
|
|
621
|
+
output: Path | None = typer.Option(
|
|
622
|
+
None,
|
|
623
|
+
"--output",
|
|
624
|
+
help="Optional DPA Assessment evidence JSON path under docs/architecture/evidence/dpa/assessment/.",
|
|
625
|
+
),
|
|
626
|
+
execute: bool = typer.Option(False, "--execute", help="Write --output when supplied."),
|
|
627
|
+
output_json: bool = typer.Option(False, "--json", help="Print machine-readable JSON."),
|
|
628
|
+
require_ready: bool = typer.Option(
|
|
629
|
+
False,
|
|
630
|
+
"--require-ready",
|
|
631
|
+
help="Fail unless the current DPA state is ready for Stable Promotion or already stable.",
|
|
632
|
+
),
|
|
633
|
+
require_stable: bool = typer.Option(
|
|
634
|
+
False,
|
|
635
|
+
"--require-stable",
|
|
636
|
+
help="Fail unless the Stable Promotion record is valid and DPA specs are stable.",
|
|
637
|
+
),
|
|
638
|
+
) -> None:
|
|
639
|
+
"""Validate Stable-DPA readiness and the bounded Stable Promotion record."""
|
|
640
|
+
resolved_root = root.resolve()
|
|
641
|
+
result = evaluate_dpa_stable_readiness(
|
|
642
|
+
resolved_root,
|
|
643
|
+
record_path=record,
|
|
644
|
+
validation_ref=validation_ref,
|
|
645
|
+
)
|
|
646
|
+
write_result = None
|
|
647
|
+
if output is not None:
|
|
648
|
+
write_result = write_dpa_stable_readiness_json(
|
|
649
|
+
result,
|
|
650
|
+
resolved_root,
|
|
651
|
+
output,
|
|
652
|
+
execute=execute,
|
|
653
|
+
)
|
|
654
|
+
payload = result.as_dict()
|
|
655
|
+
if write_result is not None:
|
|
656
|
+
payload["evidence_write"] = write_result
|
|
657
|
+
if output_json:
|
|
658
|
+
typer.echo(json.dumps(payload, indent=2, sort_keys=True))
|
|
659
|
+
else:
|
|
660
|
+
typer.echo(render_dpa_stable_readiness(result), nl=False)
|
|
661
|
+
if write_result is not None:
|
|
662
|
+
reason = f"|reason={write_result['reason']}" if "reason" in write_result else ""
|
|
663
|
+
typer.echo(
|
|
664
|
+
"EVIDENCE_WRITE="
|
|
665
|
+
f"{write_result['result_status']}|"
|
|
666
|
+
f"path={write_result['output_path']}|"
|
|
667
|
+
f"written={str(write_result.get('written', False)).lower()}"
|
|
668
|
+
f"{reason}"
|
|
669
|
+
)
|
|
670
|
+
if write_result is not None and write_result["result_status"] == "BLOCK":
|
|
671
|
+
raise typer.Exit(2)
|
|
672
|
+
if result.findings:
|
|
673
|
+
raise typer.Exit(2)
|
|
674
|
+
if require_ready and not result.ok:
|
|
675
|
+
raise typer.Exit(1)
|
|
676
|
+
if require_stable and not result.stable_promoted:
|
|
677
|
+
raise typer.Exit(1)
|
|
678
|
+
|
|
679
|
+
|
|
680
|
+
@dpa_app.command("current-handoff-refresh")
|
|
681
|
+
def dpa_current_handoff_refresh_command(
|
|
682
|
+
root: Path = typer.Option(Path("."), "--root", help="Repository root."),
|
|
683
|
+
target: Path | None = typer.Option(
|
|
684
|
+
None,
|
|
685
|
+
"--target",
|
|
686
|
+
help="Optional registered CURRENT_HANDOFF target override; defaults to the workspace handoff resolver.",
|
|
687
|
+
),
|
|
688
|
+
acceptance_state: Path | None = typer.Option(
|
|
689
|
+
None,
|
|
690
|
+
"--acceptance-state",
|
|
691
|
+
help=f"Optional DPA acceptance-state record override; legacy default is {DEFAULT_ACCEPTANCE_STATE_PATH.as_posix()}.",
|
|
692
|
+
),
|
|
693
|
+
readiness_record: Path = typer.Option(
|
|
694
|
+
DEFAULT_READINESS_PATH,
|
|
695
|
+
"--readiness-record",
|
|
696
|
+
help="DPA Assessment readiness record that must authorize DP2.",
|
|
697
|
+
),
|
|
698
|
+
validation_ref: str | None = typer.Option(
|
|
699
|
+
None,
|
|
700
|
+
"--validation-ref",
|
|
701
|
+
help="Optional exact repository ref; when supplied it must match current HEAD.",
|
|
702
|
+
),
|
|
703
|
+
initialize_acceptance: bool = typer.Option(
|
|
704
|
+
False,
|
|
705
|
+
"--initialize-acceptance",
|
|
706
|
+
help="Allow first acceptance-state creation when no prior DPA state exists.",
|
|
707
|
+
),
|
|
708
|
+
execute: bool = typer.Option(False, "--execute", help="Write target bytes and acceptance state."),
|
|
709
|
+
output_json: bool = typer.Option(False, "--json", help="Print machine-readable JSON."),
|
|
710
|
+
) -> None:
|
|
711
|
+
"""Refresh CURRENT_HANDOFF through DPA freshness, locking and acceptance-state gates."""
|
|
712
|
+
resolved_root = root.resolve()
|
|
713
|
+
result = evaluate_current_handoff_lifecycle(
|
|
714
|
+
resolved_root,
|
|
715
|
+
target_path=target,
|
|
716
|
+
acceptance_state_path=acceptance_state,
|
|
717
|
+
readiness_path=readiness_record,
|
|
718
|
+
validation_ref=validation_ref,
|
|
719
|
+
execute=execute,
|
|
720
|
+
initialize_acceptance=initialize_acceptance,
|
|
721
|
+
)
|
|
722
|
+
if output_json:
|
|
723
|
+
typer.echo(json.dumps(result.as_dict(), indent=2, sort_keys=True))
|
|
724
|
+
else:
|
|
725
|
+
typer.echo(render_current_handoff_lifecycle_result(result), nl=False)
|
|
726
|
+
if not result.ok:
|
|
727
|
+
raise typer.Exit(2)
|
|
728
|
+
|
|
729
|
+
|
|
730
|
+
@dpa_app.command("readonly-probe-execution")
|
|
731
|
+
def dpa_readonly_probe_execution_command(
|
|
732
|
+
root: Path = typer.Option(Path("."), "--root", help="Repository root."),
|
|
733
|
+
fixture_manifest: Path = typer.Option(
|
|
734
|
+
DEFAULT_FIXTURE_MANIFEST_PATH,
|
|
735
|
+
"--fixture-manifest",
|
|
736
|
+
help="DPA DP1 Probe fixture manifest to inspect.",
|
|
737
|
+
),
|
|
738
|
+
validation_ref: str | None = typer.Option(
|
|
739
|
+
None,
|
|
740
|
+
"--validation-ref",
|
|
741
|
+
help="Optional exact target ref to record instead of the current repository HEAD.",
|
|
742
|
+
),
|
|
743
|
+
output: Path | None = typer.Option(
|
|
744
|
+
None,
|
|
745
|
+
"--output",
|
|
746
|
+
help="Optional DPA probe evidence JSON path under docs/architecture/evidence/dpa/probes/.",
|
|
747
|
+
),
|
|
748
|
+
execute: bool = typer.Option(False, "--execute", help="Write --output when supplied."),
|
|
749
|
+
plan_only: bool = typer.Option(
|
|
750
|
+
False,
|
|
751
|
+
"--plan-only",
|
|
752
|
+
help="Classify eligible read-only fixture cases without executing commands.",
|
|
753
|
+
),
|
|
754
|
+
output_json: bool = typer.Option(False, "--json", help="Print machine-readable JSON."),
|
|
755
|
+
timeout_seconds: int = typer.Option(180, "--timeout-seconds", min=1, help="Per-command timeout."),
|
|
756
|
+
require_no_command_failures: bool = typer.Option(
|
|
757
|
+
False,
|
|
758
|
+
"--require-no-command-failures",
|
|
759
|
+
help="Fail unless every executed read-only command succeeds.",
|
|
760
|
+
),
|
|
761
|
+
) -> None:
|
|
762
|
+
"""Execute only non-mutating DP1 Probe fixture cases."""
|
|
763
|
+
resolved_root = root.resolve()
|
|
764
|
+
result = evaluate_dpa_readonly_probe_execution(
|
|
765
|
+
resolved_root,
|
|
766
|
+
fixture_manifest_path=fixture_manifest,
|
|
767
|
+
validation_ref=validation_ref,
|
|
768
|
+
plan_only=plan_only,
|
|
769
|
+
timeout_seconds=timeout_seconds,
|
|
770
|
+
)
|
|
771
|
+
write_result = None
|
|
772
|
+
if output is not None:
|
|
773
|
+
write_result = write_dpa_readonly_probe_execution_json(
|
|
774
|
+
result,
|
|
775
|
+
resolved_root,
|
|
776
|
+
output,
|
|
777
|
+
execute=execute,
|
|
778
|
+
)
|
|
779
|
+
payload = result.as_dict()
|
|
780
|
+
if write_result is not None:
|
|
781
|
+
payload["evidence_write"] = write_result
|
|
782
|
+
if output_json:
|
|
783
|
+
typer.echo(json.dumps(payload, indent=2, sort_keys=True))
|
|
784
|
+
else:
|
|
785
|
+
typer.echo(render_dpa_readonly_probe_execution(result), nl=False)
|
|
786
|
+
if write_result is not None:
|
|
787
|
+
reason = f"|reason={write_result['reason']}" if "reason" in write_result else ""
|
|
788
|
+
typer.echo(
|
|
789
|
+
"EVIDENCE_WRITE="
|
|
790
|
+
f"{write_result['result_status']}|"
|
|
791
|
+
f"path={write_result['output_path']}|"
|
|
792
|
+
f"written={str(write_result.get('written', False)).lower()}"
|
|
793
|
+
f"{reason}"
|
|
794
|
+
)
|
|
795
|
+
if write_result is not None and write_result["result_status"] == "BLOCK":
|
|
796
|
+
raise typer.Exit(2)
|
|
797
|
+
if result.findings or result.command_failures:
|
|
798
|
+
raise typer.Exit(2)
|
|
799
|
+
if require_no_command_failures and result.command_failures:
|
|
800
|
+
raise typer.Exit(1)
|
|
801
|
+
|
|
802
|
+
|
|
803
|
+
@dpa_app.command("fixture-evidence")
|
|
804
|
+
def dpa_fixture_evidence_command(
|
|
805
|
+
root: Path = typer.Option(Path("."), "--root", help="Repository root."),
|
|
806
|
+
fixture_manifest: Path = typer.Option(
|
|
807
|
+
DEFAULT_FIXTURE_MANIFEST_PATH,
|
|
808
|
+
"--fixture-manifest",
|
|
809
|
+
help="DPA DP1 Probe fixture manifest to execute.",
|
|
810
|
+
),
|
|
811
|
+
validation_ref: str | None = typer.Option(
|
|
812
|
+
None,
|
|
813
|
+
"--validation-ref",
|
|
814
|
+
help="Optional exact target ref to record instead of the current repository HEAD.",
|
|
815
|
+
),
|
|
816
|
+
authorized_by: str | None = typer.Option(
|
|
817
|
+
None,
|
|
818
|
+
"--authorized-by",
|
|
819
|
+
help="Maintainer/operator authorization identity for non-production fixture execution.",
|
|
820
|
+
),
|
|
821
|
+
authorization_token: str | None = typer.Option(
|
|
822
|
+
None,
|
|
823
|
+
"--authorization-token",
|
|
824
|
+
help=f"Required token for non-production fixture execution: {AUTHORIZATION_TOKEN}.",
|
|
825
|
+
),
|
|
826
|
+
output: Path | None = typer.Option(
|
|
827
|
+
None,
|
|
828
|
+
"--output",
|
|
829
|
+
help="Optional DPA probe evidence JSON path under docs/architecture/evidence/dpa/probes/.",
|
|
830
|
+
),
|
|
831
|
+
execute: bool = typer.Option(False, "--execute", help="Write --output when supplied."),
|
|
832
|
+
plan_only: bool = typer.Option(
|
|
833
|
+
False,
|
|
834
|
+
"--plan-only",
|
|
835
|
+
help="Classify fixture cases without executing temporary/disposable fixture actions.",
|
|
836
|
+
),
|
|
837
|
+
output_json: bool = typer.Option(False, "--json", help="Print machine-readable JSON."),
|
|
838
|
+
require_full_evidence: bool = typer.Option(
|
|
839
|
+
False,
|
|
840
|
+
"--require-full-evidence",
|
|
841
|
+
help="Fail unless every fixture case executes and all full-evidence families are satisfied.",
|
|
842
|
+
),
|
|
843
|
+
) -> None:
|
|
844
|
+
"""Execute authorized non-production DPA fixture evidence cases."""
|
|
845
|
+
resolved_root = root.resolve()
|
|
846
|
+
result = evaluate_dpa_fixture_evidence(
|
|
847
|
+
resolved_root,
|
|
848
|
+
fixture_manifest_path=fixture_manifest,
|
|
849
|
+
validation_ref=validation_ref,
|
|
850
|
+
authorized_by=authorized_by,
|
|
851
|
+
authorization_token=authorization_token,
|
|
852
|
+
plan_only=plan_only,
|
|
853
|
+
)
|
|
854
|
+
write_result = None
|
|
855
|
+
if output is not None:
|
|
856
|
+
write_result = write_dpa_fixture_evidence_json(
|
|
857
|
+
result,
|
|
858
|
+
resolved_root,
|
|
859
|
+
output,
|
|
860
|
+
execute=execute,
|
|
861
|
+
)
|
|
862
|
+
payload = result.as_dict()
|
|
863
|
+
if write_result is not None:
|
|
864
|
+
payload["evidence_write"] = write_result
|
|
865
|
+
if output_json:
|
|
866
|
+
typer.echo(json.dumps(payload, indent=2, sort_keys=True))
|
|
867
|
+
else:
|
|
868
|
+
typer.echo(render_dpa_fixture_evidence(result), nl=False)
|
|
869
|
+
if write_result is not None:
|
|
870
|
+
reason = f"|reason={write_result['reason']}" if "reason" in write_result else ""
|
|
871
|
+
typer.echo(
|
|
872
|
+
"EVIDENCE_WRITE="
|
|
873
|
+
f"{write_result['result_status']}|"
|
|
874
|
+
f"path={write_result['output_path']}|"
|
|
875
|
+
f"written={str(write_result.get('written', False)).lower()}"
|
|
876
|
+
f"{reason}"
|
|
877
|
+
)
|
|
878
|
+
if write_result is not None and write_result["result_status"] == "BLOCK":
|
|
879
|
+
raise typer.Exit(2)
|
|
880
|
+
if result.findings or not result.authorization_ok or result.failed_cases:
|
|
881
|
+
raise typer.Exit(2)
|
|
882
|
+
if require_full_evidence and (
|
|
883
|
+
result.result_status != "FULL_FIXTURE_EVIDENCE_RECORDED"
|
|
884
|
+
or not all(result.full_evidence_by_family.values())
|
|
885
|
+
or not result.rollback_cleanup_proven
|
|
886
|
+
):
|
|
887
|
+
raise typer.Exit(1)
|
|
888
|
+
|
|
889
|
+
|
|
890
|
+
@dpa_app.command("dp2-decision-readiness")
|
|
891
|
+
def dpa_dp2_decision_readiness_command(
|
|
892
|
+
root: Path = typer.Option(Path("."), "--root", help="Repository root."),
|
|
893
|
+
record: Path = typer.Option(
|
|
894
|
+
DEFAULT_READINESS_PATH,
|
|
895
|
+
"--record",
|
|
896
|
+
help="DPA Assessment readiness JSON record to inspect.",
|
|
897
|
+
),
|
|
898
|
+
validation_ref: str | None = typer.Option(
|
|
899
|
+
None,
|
|
900
|
+
"--validation-ref",
|
|
901
|
+
help="Optional exact target ref to record instead of the current repository HEAD.",
|
|
902
|
+
),
|
|
903
|
+
output: Path | None = typer.Option(
|
|
904
|
+
None,
|
|
905
|
+
"--output",
|
|
906
|
+
help="Optional DPA Assessment evidence JSON path under docs/architecture/evidence/dpa/assessment/.",
|
|
907
|
+
),
|
|
908
|
+
execute: bool = typer.Option(False, "--execute", help="Write --output when supplied."),
|
|
909
|
+
output_json: bool = typer.Option(False, "--json", help="Print machine-readable JSON."),
|
|
910
|
+
require_ready: bool = typer.Option(
|
|
911
|
+
False,
|
|
912
|
+
"--require-ready",
|
|
913
|
+
help="Fail unless the decision package is structurally ready for Maintainer review.",
|
|
914
|
+
),
|
|
915
|
+
) -> None:
|
|
916
|
+
"""Prepare DP2 decision readiness without recording Maintainer authorization."""
|
|
917
|
+
resolved_root = root.resolve()
|
|
918
|
+
result = evaluate_dp2_decision_readiness(
|
|
919
|
+
resolved_root,
|
|
920
|
+
readiness_path=record,
|
|
921
|
+
validation_ref=validation_ref,
|
|
922
|
+
)
|
|
923
|
+
write_result = None
|
|
924
|
+
if output is not None:
|
|
925
|
+
write_result = write_dp2_decision_readiness_json(
|
|
926
|
+
result,
|
|
927
|
+
resolved_root,
|
|
928
|
+
output,
|
|
929
|
+
execute=execute,
|
|
930
|
+
)
|
|
931
|
+
payload = result.as_dict()
|
|
932
|
+
if write_result is not None:
|
|
933
|
+
payload["evidence_write"] = write_result
|
|
934
|
+
if output_json:
|
|
935
|
+
typer.echo(json.dumps(payload, indent=2, sort_keys=True))
|
|
936
|
+
else:
|
|
937
|
+
typer.echo(render_dp2_decision_readiness(result), nl=False)
|
|
938
|
+
if write_result is not None:
|
|
939
|
+
reason = f"|reason={write_result['reason']}" if "reason" in write_result else ""
|
|
940
|
+
typer.echo(
|
|
941
|
+
"EVIDENCE_WRITE="
|
|
942
|
+
f"{write_result['result_status']}|"
|
|
943
|
+
f"path={write_result['output_path']}|"
|
|
944
|
+
f"written={str(write_result.get('written', False)).lower()}"
|
|
945
|
+
f"{reason}"
|
|
946
|
+
)
|
|
947
|
+
if write_result is not None and write_result["result_status"] == "BLOCK":
|
|
948
|
+
raise typer.Exit(2)
|
|
949
|
+
if result.findings:
|
|
950
|
+
raise typer.Exit(2)
|
|
951
|
+
if require_ready and result.result_status != "READY_FOR_MAINTAINER_DECISION_DP2_BLOCKED":
|
|
952
|
+
raise typer.Exit(1)
|
|
953
|
+
|
|
954
|
+
|
|
955
|
+
@dpa_app.command("maintainer-record-check")
|
|
956
|
+
def dpa_maintainer_record_check_command(
|
|
957
|
+
root: Path = typer.Option(Path("."), "--root", help="Repository root."),
|
|
958
|
+
record: Path = typer.Option(
|
|
959
|
+
DEFAULT_MAINTAINER_RECORD_PATH,
|
|
960
|
+
"--record",
|
|
961
|
+
help="DPA DP2 Maintainer Assessment record to inspect.",
|
|
962
|
+
),
|
|
963
|
+
readiness_record: Path = typer.Option(
|
|
964
|
+
DEFAULT_READINESS_PATH,
|
|
965
|
+
"--readiness-record",
|
|
966
|
+
help="DPA Assessment readiness JSON record that the Maintainer record must bind to.",
|
|
967
|
+
),
|
|
968
|
+
validation_ref: str | None = typer.Option(
|
|
969
|
+
None,
|
|
970
|
+
"--validation-ref",
|
|
971
|
+
help="Optional exact target ref to record instead of the current repository HEAD.",
|
|
972
|
+
),
|
|
973
|
+
output: Path | None = typer.Option(
|
|
974
|
+
None,
|
|
975
|
+
"--output",
|
|
976
|
+
help="Optional DPA Assessment evidence JSON path under docs/architecture/evidence/dpa/assessment/.",
|
|
977
|
+
),
|
|
978
|
+
execute: bool = typer.Option(False, "--execute", help="Write --output when supplied."),
|
|
979
|
+
output_json: bool = typer.Option(False, "--json", help="Print machine-readable JSON."),
|
|
980
|
+
require_authorization: bool = typer.Option(
|
|
981
|
+
False,
|
|
982
|
+
"--require-authorization",
|
|
983
|
+
help="Fail unless the record is a valid DP2 authorization record.",
|
|
984
|
+
),
|
|
985
|
+
) -> None:
|
|
986
|
+
"""Validate a DP2 Maintainer Assessment record without authorizing DP2."""
|
|
987
|
+
resolved_root = root.resolve()
|
|
988
|
+
result = evaluate_dp2_maintainer_record(
|
|
989
|
+
resolved_root,
|
|
990
|
+
record_path=record,
|
|
991
|
+
readiness_path=readiness_record,
|
|
992
|
+
validation_ref=validation_ref,
|
|
993
|
+
)
|
|
994
|
+
write_result = None
|
|
995
|
+
if output is not None:
|
|
996
|
+
write_result = write_dp2_maintainer_record_check_json(
|
|
997
|
+
result,
|
|
998
|
+
resolved_root,
|
|
999
|
+
output,
|
|
1000
|
+
execute=execute,
|
|
1001
|
+
)
|
|
1002
|
+
payload = result.as_dict()
|
|
1003
|
+
if write_result is not None:
|
|
1004
|
+
payload["evidence_write"] = write_result
|
|
1005
|
+
if output_json:
|
|
1006
|
+
typer.echo(json.dumps(payload, indent=2, sort_keys=True))
|
|
1007
|
+
else:
|
|
1008
|
+
typer.echo(render_dp2_maintainer_record_check(result), nl=False)
|
|
1009
|
+
if write_result is not None:
|
|
1010
|
+
reason = f"|reason={write_result['reason']}" if "reason" in write_result else ""
|
|
1011
|
+
typer.echo(
|
|
1012
|
+
"EVIDENCE_WRITE="
|
|
1013
|
+
f"{write_result['result_status']}|"
|
|
1014
|
+
f"path={write_result['output_path']}|"
|
|
1015
|
+
f"written={str(write_result.get('written', False)).lower()}"
|
|
1016
|
+
f"{reason}"
|
|
1017
|
+
)
|
|
1018
|
+
if write_result is not None and write_result["result_status"] == "BLOCK":
|
|
1019
|
+
raise typer.Exit(2)
|
|
1020
|
+
if result.findings:
|
|
1021
|
+
raise typer.Exit(2)
|
|
1022
|
+
if require_authorization and result.result_status != "VALID_AUTHORIZATION_RECORD":
|
|
1023
|
+
raise typer.Exit(1)
|
|
1024
|
+
|
|
1025
|
+
|
|
1026
|
+
@dpa_app.command("probe-002-readiness")
|
|
1027
|
+
def dpa_probe_002_readiness_command(
|
|
1028
|
+
root: Path = typer.Option(Path("."), "--root", help="Repository root."),
|
|
1029
|
+
record: Path = typer.Option(
|
|
1030
|
+
DEFAULT_READINESS_PATH,
|
|
1031
|
+
"--record",
|
|
1032
|
+
help="DPA Assessment readiness JSON record to inspect.",
|
|
1033
|
+
),
|
|
1034
|
+
output: Path | None = typer.Option(
|
|
1035
|
+
None,
|
|
1036
|
+
"--output",
|
|
1037
|
+
help="Optional DPA probe evidence JSON path under docs/architecture/evidence/dpa/probes/.",
|
|
1038
|
+
),
|
|
1039
|
+
execute: bool = typer.Option(False, "--execute", help="Write --output when supplied."),
|
|
1040
|
+
output_json: bool = typer.Option(False, "--json", help="Print machine-readable JSON."),
|
|
1041
|
+
require_full_evidence: bool = typer.Option(
|
|
1042
|
+
False,
|
|
1043
|
+
"--require-full-evidence",
|
|
1044
|
+
help="Fail unless PROBE-002 full evidence is structurally satisfied.",
|
|
1045
|
+
),
|
|
1046
|
+
) -> None:
|
|
1047
|
+
"""Inspect PROBE-002 lifecycle and selected-writer readiness without production mutation."""
|
|
1048
|
+
resolved_root = root.resolve()
|
|
1049
|
+
result = evaluate_probe_002_lifecycle_readiness(resolved_root, readiness_path=record)
|
|
1050
|
+
write_result = None
|
|
1051
|
+
if output is not None:
|
|
1052
|
+
write_result = write_probe_002_readiness_json(
|
|
1053
|
+
result,
|
|
1054
|
+
resolved_root,
|
|
1055
|
+
output,
|
|
1056
|
+
execute=execute,
|
|
1057
|
+
)
|
|
1058
|
+
payload = result.as_dict()
|
|
1059
|
+
if write_result is not None:
|
|
1060
|
+
payload["evidence_write"] = write_result
|
|
1061
|
+
if output_json:
|
|
1062
|
+
typer.echo(json.dumps(payload, indent=2, sort_keys=True))
|
|
1063
|
+
else:
|
|
1064
|
+
typer.echo(render_probe_002_lifecycle_readiness(result), nl=False)
|
|
1065
|
+
if write_result is not None:
|
|
1066
|
+
reason = f"|reason={write_result['reason']}" if "reason" in write_result else ""
|
|
1067
|
+
typer.echo(
|
|
1068
|
+
"EVIDENCE_WRITE="
|
|
1069
|
+
f"{write_result['result_status']}|"
|
|
1070
|
+
f"path={write_result['output_path']}|"
|
|
1071
|
+
f"written={str(write_result.get('written', False)).lower()}"
|
|
1072
|
+
f"{reason}"
|
|
1073
|
+
)
|
|
1074
|
+
if write_result is not None and write_result["result_status"] == "BLOCK":
|
|
1075
|
+
raise typer.Exit(2)
|
|
1076
|
+
if result.findings:
|
|
1077
|
+
raise typer.Exit(2)
|
|
1078
|
+
if require_full_evidence and not result.full_evidence_satisfied:
|
|
1079
|
+
raise typer.Exit(1)
|
|
1080
|
+
|
|
1081
|
+
|
|
1082
|
+
@dpa_app.command("wrt-ch001-evidence")
|
|
1083
|
+
def dpa_wrt_ch001_evidence_command(
|
|
1084
|
+
source_pr: int = typer.Option(..., "--source-pr", help="Substantive PR that triggered the admin refresh."),
|
|
1085
|
+
admin_pr: int = typer.Option(..., "--admin-pr", help="Administrative handoff refresh PR to observe."),
|
|
1086
|
+
root: Path = typer.Option(Path("."), "--root", help="Repository root."),
|
|
1087
|
+
input_path: Path | None = typer.Option(
|
|
1088
|
+
None,
|
|
1089
|
+
"--input",
|
|
1090
|
+
help="Optional gh-pr-view JSON input. If omitted, gh pr view is used.",
|
|
1091
|
+
),
|
|
1092
|
+
output: Path | None = typer.Option(
|
|
1093
|
+
None,
|
|
1094
|
+
"--output",
|
|
1095
|
+
help="Optional DPA probe evidence JSON path under docs/architecture/evidence/dpa/probes/.",
|
|
1096
|
+
),
|
|
1097
|
+
execute: bool = typer.Option(False, "--execute", help="Write --output when supplied."),
|
|
1098
|
+
output_json: bool = typer.Option(False, "--json", help="Print machine-readable JSON."),
|
|
1099
|
+
require_disposable_fixture: bool = typer.Option(
|
|
1100
|
+
False,
|
|
1101
|
+
"--require-disposable-fixture",
|
|
1102
|
+
help="Fail unless this evidence satisfies disposable WRT-CH-001 fixture execution.",
|
|
1103
|
+
),
|
|
1104
|
+
) -> None:
|
|
1105
|
+
"""Observe a WRT-CH-001 admin refresh PR without claiming disposable fixture PASS."""
|
|
1106
|
+
resolved_root = root.resolve()
|
|
1107
|
+
pr_data = load_pr_data(input_path) if input_path is not None else fetch_admin_refresh_pr_data(admin_pr, root=resolved_root)
|
|
1108
|
+
result = evaluate_wrt_ch001_admin_refresh_observation(
|
|
1109
|
+
resolved_root,
|
|
1110
|
+
source_pr=source_pr,
|
|
1111
|
+
admin_pr=admin_pr,
|
|
1112
|
+
pr_data=pr_data,
|
|
1113
|
+
)
|
|
1114
|
+
write_result = None
|
|
1115
|
+
if output is not None:
|
|
1116
|
+
write_result = write_wrt_ch001_evidence_json(
|
|
1117
|
+
result,
|
|
1118
|
+
resolved_root,
|
|
1119
|
+
output,
|
|
1120
|
+
execute=execute,
|
|
1121
|
+
)
|
|
1122
|
+
payload = result.as_dict()
|
|
1123
|
+
if write_result is not None:
|
|
1124
|
+
payload["evidence_write"] = write_result
|
|
1125
|
+
if output_json:
|
|
1126
|
+
typer.echo(json.dumps(payload, indent=2, sort_keys=True))
|
|
1127
|
+
else:
|
|
1128
|
+
typer.echo(render_wrt_ch001_evidence(result), nl=False)
|
|
1129
|
+
if write_result is not None:
|
|
1130
|
+
reason = f"|reason={write_result['reason']}" if "reason" in write_result else ""
|
|
1131
|
+
typer.echo(
|
|
1132
|
+
"EVIDENCE_WRITE="
|
|
1133
|
+
f"{write_result['result_status']}|"
|
|
1134
|
+
f"path={write_result['output_path']}|"
|
|
1135
|
+
f"written={str(write_result.get('written', False)).lower()}"
|
|
1136
|
+
f"{reason}"
|
|
1137
|
+
)
|
|
1138
|
+
if write_result is not None and write_result["result_status"] == "BLOCK":
|
|
1139
|
+
raise typer.Exit(2)
|
|
1140
|
+
if result.findings:
|
|
1141
|
+
raise typer.Exit(2)
|
|
1142
|
+
if require_disposable_fixture and not result.full_wrt_ch001_fixture_satisfied:
|
|
1143
|
+
raise typer.Exit(1)
|
|
1144
|
+
|
|
1145
|
+
|
|
1146
|
+
@dpa_app.command("probe-003-readiness")
|
|
1147
|
+
def dpa_probe_003_readiness_command(
|
|
1148
|
+
root: Path = typer.Option(Path("."), "--root", help="Repository root."),
|
|
1149
|
+
record: Path = typer.Option(
|
|
1150
|
+
DEFAULT_READINESS_PATH,
|
|
1151
|
+
"--record",
|
|
1152
|
+
help="DPA Assessment readiness JSON record to inspect.",
|
|
1153
|
+
),
|
|
1154
|
+
validation_ref: str | None = typer.Option(
|
|
1155
|
+
None,
|
|
1156
|
+
"--validation-ref",
|
|
1157
|
+
help="Optional exact target ref to record instead of the current repository HEAD.",
|
|
1158
|
+
),
|
|
1159
|
+
output: Path | None = typer.Option(
|
|
1160
|
+
None,
|
|
1161
|
+
"--output",
|
|
1162
|
+
help="Optional DPA probe evidence JSON path under docs/architecture/evidence/dpa/probes/.",
|
|
1163
|
+
),
|
|
1164
|
+
execute: bool = typer.Option(False, "--execute", help="Write --output when supplied."),
|
|
1165
|
+
output_json: bool = typer.Option(False, "--json", help="Print machine-readable JSON."),
|
|
1166
|
+
require_full_evidence: bool = typer.Option(
|
|
1167
|
+
False,
|
|
1168
|
+
"--require-full-evidence",
|
|
1169
|
+
help="Fail unless PROBE-003 full evidence is structurally satisfied.",
|
|
1170
|
+
),
|
|
1171
|
+
) -> None:
|
|
1172
|
+
"""Inspect PROBE-003 workflow serialization readiness without workflow mutation."""
|
|
1173
|
+
resolved_root = root.resolve()
|
|
1174
|
+
result = evaluate_probe_003_workflow_readiness(
|
|
1175
|
+
resolved_root,
|
|
1176
|
+
readiness_path=record,
|
|
1177
|
+
validation_ref=validation_ref,
|
|
1178
|
+
)
|
|
1179
|
+
write_result = None
|
|
1180
|
+
if output is not None:
|
|
1181
|
+
write_result = write_probe_003_readiness_json(
|
|
1182
|
+
result,
|
|
1183
|
+
resolved_root,
|
|
1184
|
+
output,
|
|
1185
|
+
execute=execute,
|
|
1186
|
+
)
|
|
1187
|
+
payload = result.as_dict()
|
|
1188
|
+
if write_result is not None:
|
|
1189
|
+
payload["evidence_write"] = write_result
|
|
1190
|
+
if output_json:
|
|
1191
|
+
typer.echo(json.dumps(payload, indent=2, sort_keys=True))
|
|
1192
|
+
else:
|
|
1193
|
+
typer.echo(render_probe_003_workflow_readiness(result), nl=False)
|
|
1194
|
+
if write_result is not None:
|
|
1195
|
+
reason = f"|reason={write_result['reason']}" if "reason" in write_result else ""
|
|
1196
|
+
typer.echo(
|
|
1197
|
+
"EVIDENCE_WRITE="
|
|
1198
|
+
f"{write_result['result_status']}|"
|
|
1199
|
+
f"path={write_result['output_path']}|"
|
|
1200
|
+
f"written={str(write_result.get('written', False)).lower()}"
|
|
1201
|
+
f"{reason}"
|
|
1202
|
+
)
|
|
1203
|
+
if write_result is not None and write_result["result_status"] == "BLOCK":
|
|
1204
|
+
raise typer.Exit(2)
|
|
1205
|
+
if result.findings:
|
|
1206
|
+
raise typer.Exit(2)
|
|
1207
|
+
if require_full_evidence and not result.full_evidence_satisfied:
|
|
1208
|
+
raise typer.Exit(1)
|
|
1209
|
+
|
|
1210
|
+
|
|
1211
|
+
@dpa_app.command("renderer-readiness")
|
|
1212
|
+
def dpa_renderer_readiness_command(
|
|
1213
|
+
root: Path = typer.Option(Path("."), "--root", help="Repository root."),
|
|
1214
|
+
record: Path = typer.Option(
|
|
1215
|
+
DEFAULT_READINESS_PATH,
|
|
1216
|
+
"--record",
|
|
1217
|
+
help="DPA Assessment readiness JSON record to inspect.",
|
|
1218
|
+
),
|
|
1219
|
+
validation_ref: str | None = typer.Option(
|
|
1220
|
+
None,
|
|
1221
|
+
"--validation-ref",
|
|
1222
|
+
help="Optional exact target ref to record instead of the current repository HEAD.",
|
|
1223
|
+
),
|
|
1224
|
+
output: Path | None = typer.Option(
|
|
1225
|
+
None,
|
|
1226
|
+
"--output",
|
|
1227
|
+
help="Optional DPA probe evidence JSON path under docs/architecture/evidence/dpa/probes/.",
|
|
1228
|
+
),
|
|
1229
|
+
execute: bool = typer.Option(False, "--execute", help="Write --output when supplied."),
|
|
1230
|
+
output_json: bool = typer.Option(False, "--json", help="Print machine-readable JSON."),
|
|
1231
|
+
require_full_evidence: bool = typer.Option(
|
|
1232
|
+
False,
|
|
1233
|
+
"--require-full-evidence",
|
|
1234
|
+
help="Fail unless Renderer Probe full evidence is structurally satisfied.",
|
|
1235
|
+
),
|
|
1236
|
+
) -> None:
|
|
1237
|
+
"""Inspect Renderer Probe readiness without renderer conformance claims."""
|
|
1238
|
+
resolved_root = root.resolve()
|
|
1239
|
+
result = evaluate_renderer_probe_readiness(
|
|
1240
|
+
resolved_root,
|
|
1241
|
+
readiness_path=record,
|
|
1242
|
+
validation_ref=validation_ref,
|
|
1243
|
+
)
|
|
1244
|
+
write_result = None
|
|
1245
|
+
if output is not None:
|
|
1246
|
+
write_result = write_renderer_readiness_json(
|
|
1247
|
+
result,
|
|
1248
|
+
resolved_root,
|
|
1249
|
+
output,
|
|
1250
|
+
execute=execute,
|
|
1251
|
+
)
|
|
1252
|
+
payload = result.as_dict()
|
|
1253
|
+
if write_result is not None:
|
|
1254
|
+
payload["evidence_write"] = write_result
|
|
1255
|
+
if output_json:
|
|
1256
|
+
typer.echo(json.dumps(payload, indent=2, sort_keys=True))
|
|
1257
|
+
else:
|
|
1258
|
+
typer.echo(render_renderer_probe_readiness(result), nl=False)
|
|
1259
|
+
if write_result is not None:
|
|
1260
|
+
reason = f"|reason={write_result['reason']}" if "reason" in write_result else ""
|
|
1261
|
+
typer.echo(
|
|
1262
|
+
"EVIDENCE_WRITE="
|
|
1263
|
+
f"{write_result['result_status']}|"
|
|
1264
|
+
f"path={write_result['output_path']}|"
|
|
1265
|
+
f"written={str(write_result.get('written', False)).lower()}"
|
|
1266
|
+
f"{reason}"
|
|
1267
|
+
)
|
|
1268
|
+
if write_result is not None and write_result["result_status"] == "BLOCK":
|
|
1269
|
+
raise typer.Exit(2)
|
|
1270
|
+
if result.findings:
|
|
1271
|
+
raise typer.Exit(2)
|
|
1272
|
+
if require_full_evidence and not result.full_evidence_satisfied:
|
|
1273
|
+
raise typer.Exit(1)
|
|
1274
|
+
|
|
1275
|
+
|
|
1276
|
+
@dpa_app.command("probe-004-readiness")
|
|
1277
|
+
def dpa_probe_004_readiness_command(
|
|
1278
|
+
root: Path = typer.Option(Path("."), "--root", help="Repository root."),
|
|
1279
|
+
record: Path = typer.Option(
|
|
1280
|
+
DEFAULT_READINESS_PATH,
|
|
1281
|
+
"--record",
|
|
1282
|
+
help="DPA Assessment readiness JSON record to inspect.",
|
|
1283
|
+
),
|
|
1284
|
+
validation_ref: str | None = typer.Option(
|
|
1285
|
+
None,
|
|
1286
|
+
"--validation-ref",
|
|
1287
|
+
help="Optional exact target ref to record instead of the current repository HEAD.",
|
|
1288
|
+
),
|
|
1289
|
+
output: Path | None = typer.Option(
|
|
1290
|
+
None,
|
|
1291
|
+
"--output",
|
|
1292
|
+
help="Optional DPA probe evidence JSON path under docs/architecture/evidence/dpa/probes/.",
|
|
1293
|
+
),
|
|
1294
|
+
execute: bool = typer.Option(False, "--execute", help="Write --output when supplied."),
|
|
1295
|
+
output_json: bool = typer.Option(False, "--json", help="Print machine-readable JSON."),
|
|
1296
|
+
require_full_evidence: bool = typer.Option(
|
|
1297
|
+
False,
|
|
1298
|
+
"--require-full-evidence",
|
|
1299
|
+
help="Fail unless PROBE-004 full evidence is structurally satisfied.",
|
|
1300
|
+
),
|
|
1301
|
+
) -> None:
|
|
1302
|
+
"""Inspect PROBE-004 migration and rollback readiness without migration."""
|
|
1303
|
+
resolved_root = root.resolve()
|
|
1304
|
+
result = evaluate_probe_004_migration_readiness(
|
|
1305
|
+
resolved_root,
|
|
1306
|
+
readiness_path=record,
|
|
1307
|
+
validation_ref=validation_ref,
|
|
1308
|
+
)
|
|
1309
|
+
write_result = None
|
|
1310
|
+
if output is not None:
|
|
1311
|
+
write_result = write_probe_004_readiness_json(
|
|
1312
|
+
result,
|
|
1313
|
+
resolved_root,
|
|
1314
|
+
output,
|
|
1315
|
+
execute=execute,
|
|
1316
|
+
)
|
|
1317
|
+
payload = result.as_dict()
|
|
1318
|
+
if write_result is not None:
|
|
1319
|
+
payload["evidence_write"] = write_result
|
|
1320
|
+
if output_json:
|
|
1321
|
+
typer.echo(json.dumps(payload, indent=2, sort_keys=True))
|
|
1322
|
+
else:
|
|
1323
|
+
typer.echo(render_probe_004_migration_readiness(result), nl=False)
|
|
1324
|
+
if write_result is not None:
|
|
1325
|
+
reason = f"|reason={write_result['reason']}" if "reason" in write_result else ""
|
|
1326
|
+
typer.echo(
|
|
1327
|
+
"EVIDENCE_WRITE="
|
|
1328
|
+
f"{write_result['result_status']}|"
|
|
1329
|
+
f"path={write_result['output_path']}|"
|
|
1330
|
+
f"written={str(write_result.get('written', False)).lower()}"
|
|
1331
|
+
f"{reason}"
|
|
1332
|
+
)
|
|
1333
|
+
if write_result is not None and write_result["result_status"] == "BLOCK":
|
|
1334
|
+
raise typer.Exit(2)
|
|
1335
|
+
if result.findings:
|
|
1336
|
+
raise typer.Exit(2)
|
|
1337
|
+
if require_full_evidence and not result.full_evidence_satisfied:
|
|
1338
|
+
raise typer.Exit(1)
|