devagent-ai 0.8.4__tar.gz → 0.8.6__tar.gz
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.
- {devagent_ai-0.8.4/devagent_ai.egg-info → devagent_ai-0.8.6}/PKG-INFO +23 -1
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/README.md +20 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/__init__.py +1 -1
- devagent_ai-0.8.6/devagent/__main__.py +4 -0
- devagent_ai-0.8.6/devagent/entrypoint.py +22 -0
- devagent_ai-0.8.6/devagent/plc/__init__.py +185 -0
- devagent_ai-0.8.6/devagent/plc/agent_harness_install_v15.py +27 -0
- devagent_ai-0.8.6/devagent/plc/agent_harness_v15.py +208 -0
- devagent_ai-0.8.6/devagent/plc/analysis.py +650 -0
- devagent_ai-0.8.6/devagent/plc/cli.py +320 -0
- devagent_ai-0.8.6/devagent/plc/execution_trust.py +176 -0
- devagent_ai-0.8.6/devagent/plc/fat_procedure_v12.py +165 -0
- devagent_ai-0.8.6/devagent/plc/four_contract_v13.py +196 -0
- devagent_ai-0.8.6/devagent/plc/inspect_cli.py +164 -0
- devagent_ai-0.8.6/devagent/plc/models.py +332 -0
- devagent_ai-0.8.6/devagent/plc/plc_dispatch.py +41 -0
- devagent_ai-0.8.6/devagent/plc/production.py +480 -0
- devagent_ai-0.8.6/devagent/plc/production_ai.py +440 -0
- devagent_ai-0.8.6/devagent/plc/production_evidence.py +159 -0
- devagent_ai-0.8.6/devagent/plc/production_models.py +220 -0
- devagent_ai-0.8.6/devagent/plc/production_readiness.py +223 -0
- devagent_ai-0.8.6/devagent/plc/production_readiness_v5.py +279 -0
- devagent_ai-0.8.6/devagent/plc/production_regression.py +306 -0
- devagent_ai-0.8.6/devagent/plc/production_report.py +325 -0
- devagent_ai-0.8.6/devagent/plc/production_review.py +253 -0
- devagent_ai-0.8.6/devagent/plc/production_utils.py +57 -0
- devagent_ai-0.8.6/devagent/plc/production_v5.py +412 -0
- devagent_ai-0.8.6/devagent/plc/production_verification.py +397 -0
- devagent_ai-0.8.6/devagent/plc/professional_report_install_v14.py +37 -0
- devagent_ai-0.8.6/devagent/plc/professional_report_v14.py +252 -0
- devagent_ai-0.8.6/devagent/plc/release_policy.py +230 -0
- devagent_ai-0.8.6/devagent/plc/report.py +114 -0
- devagent_ai-0.8.6/devagent/plc/report_clarity_install_v16.py +65 -0
- devagent_ai-0.8.6/devagent/plc/requirements.py +260 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_action_requirements.py +146 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_alias_hardening.py +273 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_branch_coverage_v16.py +90 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_closeout.py +307 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_closeout_gate_hardening.py +224 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_compare.py +489 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_compare_hardening.py +466 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_compare_reachability_hardening.py +127 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_core_review_v12.py +226 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_echo.py +483 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_echo_gate.py +42 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_entrypoint_hardening.py +227 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_general_actions.py +387 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_l5x.py +509 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_motion_runtime_v11.py +149 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_regression_case_compat_v12.py +86 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_regression_evidence_hardening.py +583 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_requirement_hardening.py +127 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_risk_hardening.py +155 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_semantic_capabilities.py +92 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_st_case_v11.py +215 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_st_v10.py +52 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_standard_catalog.py +146 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_state_machine_v11.py +219 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_stateful_runtime.py +288 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_structure.py +260 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_system_service_install_v17.py +147 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_system_service_report_install_v17.py +51 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_system_service_v17.py +363 -0
- devagent_ai-0.8.6/devagent/plc/rockwell_v10_semantics.py +352 -0
- devagent_ai-0.8.6/devagent/plc/safe_analysis.py +247 -0
- devagent_ai-0.8.6/devagent/plc/semantic_coverage.py +238 -0
- devagent_ai-0.8.6/devagent/plc/semantic_coverage_report.py +197 -0
- devagent_ai-0.8.6/devagent/plc/siemens_call_graph_v3.py +1719 -0
- devagent_ai-0.8.6/devagent/plc/siemens_cli_install_v1.py +38 -0
- devagent_ai-0.8.6/devagent/plc/siemens_flgnet_extended_hardening_v4.py +257 -0
- devagent_ai-0.8.6/devagent/plc/siemens_flgnet_extended_v4.py +916 -0
- devagent_ai-0.8.6/devagent/plc/siemens_flgnet_hardening_v4.py +128 -0
- devagent_ai-0.8.6/devagent/plc/siemens_flgnet_v4.py +1284 -0
- devagent_ai-0.8.6/devagent/plc/siemens_integration_v1.py +526 -0
- devagent_ai-0.8.6/devagent/plc/siemens_interlock_permissive_v6.py +694 -0
- devagent_ai-0.8.6/devagent/plc/siemens_recovery_v7.py +567 -0
- devagent_ai-0.8.6/devagent/plc/siemens_scl_control_flow_hardening_v2.py +97 -0
- devagent_ai-0.8.6/devagent/plc/siemens_scl_control_flow_v2.py +588 -0
- devagent_ai-0.8.6/devagent/plc/siemens_state_machine_hardening_v5.py +206 -0
- devagent_ai-0.8.6/devagent/plc/siemens_state_machine_v5.py +1067 -0
- devagent_ai-0.8.6/devagent/plc/siemens_tia_v1.py +1050 -0
- devagent_ai-0.8.6/devagent/plc/siemens_v5_bindings_v1.py +32 -0
- devagent_ai-0.8.6/devagent/plc/siemens_v6_v7_token_hardening.py +155 -0
- devagent_ai-0.8.6/devagent/plc/signature_trust.py +212 -0
- devagent_ai-0.8.6/devagent/plc/trusted_snapshot.py +333 -0
- devagent_ai-0.8.6/devagent/plc/v2_guardrails.py +234 -0
- devagent_ai-0.8.6/devagent/plc/v2_semantics.py +780 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6/devagent_ai.egg-info}/PKG-INFO +23 -1
- devagent_ai-0.8.6/devagent_ai.egg-info/SOURCES.txt +222 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent_ai.egg-info/entry_points.txt +1 -1
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent_ai.egg-info/requires.txt +1 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/pyproject.toml +4 -2
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_packaging_metadata.py +1 -1
- devagent_ai-0.8.6/tests/test_plc_agent_harness_trace_v15.py +91 -0
- devagent_ai-0.8.6/tests/test_plc_agent_harness_v15.py +259 -0
- devagent_ai-0.8.6/tests/test_plc_execution_trust.py +63 -0
- devagent_ai-0.8.6/tests/test_plc_four_contract_v13.py +179 -0
- devagent_ai-0.8.6/tests/test_plc_product_contract_v12.py +190 -0
- devagent_ai-0.8.6/tests/test_plc_production.py +453 -0
- devagent_ai-0.8.6/tests/test_plc_production_v5.py +358 -0
- devagent_ai-0.8.6/tests/test_plc_release_policy.py +78 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_boolean_alias_proof.py +92 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_canonical_risks.py +82 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_closeout_v9.py +180 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_closeout_v9_guardrails.py +85 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_closeout_v9_review_regressions.py +78 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_compare_v8.py +227 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_compare_v8_aliases.py +147 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_compare_v8_hardening.py +122 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_compare_v8_identity_assertions.py +185 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_compare_v8_review_regressions.py +145 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_echo_cli_v6.py +47 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_echo_v6.py +337 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_hardening.py +207 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_semantics_v7.py +140 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_v1.py +218 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_v10_action_requirements.py +78 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_v10_arbitrary_project_qualification.py +142 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_v10_echo_compatibility.py +119 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_v10_general_actions.py +110 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_v10_general_semantics.py +264 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_v10_inspect_cli.py +92 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_v10_semantic_coverage.py +144 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_v10_st_safe_functions.py +46 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_v10_stateful_runtime.py +67 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_v11_reporting.py +53 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_v11_st_motion.py +106 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_v11_state_machine.py +68 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_v16_semantic_hardening.py +99 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_v17_system_service_fat.py +150 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_v17_system_service_generic.py +61 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_v2.py +242 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_v9_entry_edgecases.py +105 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_v9_final_codex.py +319 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_v9_merge_gates.py +125 -0
- devagent_ai-0.8.6/tests/test_plc_rockwell_v9_reachable_writers.py +186 -0
- devagent_ai-0.8.6/tests/test_plc_siemens_v1.py +240 -0
- devagent_ai-0.8.6/tests/test_plc_siemens_v2.py +251 -0
- devagent_ai-0.8.6/tests/test_plc_siemens_v3_call_graph.py +636 -0
- devagent_ai-0.8.6/tests/test_plc_siemens_v4_extended.py +335 -0
- devagent_ai-0.8.6/tests/test_plc_siemens_v4_flgnet.py +412 -0
- devagent_ai-0.8.6/tests/test_plc_siemens_v5_state_machine.py +307 -0
- devagent_ai-0.8.6/tests/test_plc_siemens_v6_v7.py +415 -0
- devagent_ai-0.8.6/tests/test_plc_signature_trust.py +167 -0
- devagent_ai-0.8.6/tests/test_plc_v5_security_floor.py +101 -0
- devagent_ai-0.8.6/tests/test_plc_v5_toctou.py +116 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_production_v040.py +1 -1
- devagent_ai-0.8.4/devagent/__main__.py +0 -4
- devagent_ai-0.8.4/devagent_ai.egg-info/SOURCES.txt +0 -86
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/LICENSE +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/NOTICE +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/agent/__init__.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/agent/llm.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/agent/loop.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/agent/memory.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/agent/prompts.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/agent/tools.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/artifacts.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/automations.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/autonomy.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/browser.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/cli.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/config.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/discovery.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/evaluation.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/memory.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/models.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/orchestrator.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/provider_benchmark.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/providers.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/qualification.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/realworld.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/report.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/retrieval.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/routing.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/runtime.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/safety.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/skills.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/source_control.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/state_machine.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/tasking.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/technical_review.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/workspace.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent/worktree.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent_ai.egg-info/dependency_links.txt +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/devagent_ai.egg-info/top_level.txt +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/setup.cfg +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_acceptance_contract.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_benchmark_catalog.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_browser_verification.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_capability_discovery.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_cli.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_cli_progress.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_developer_review_report.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_discovery_memory.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_e2e_fake_provider.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_evaluation_harness.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_evaluation_matrix.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_evaluation_regression_evidence.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_functional_qualification.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_huge_monorepo_v070.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_migration_e2e_v070.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_model_routing.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_multilang_technical_review.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_multistack_devagent_e2e.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_multistack_qualification.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_plan_verification_normalization.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_preservation_contradiction.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_production_hardening.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_realworld_benchmark.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_requirement_compiler_v082.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_requirement_intelligence_v083.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_retrieval.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_runtime_sandbox.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_safety_workspace.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_source_control_publish.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_structural_devagent_e2e_v070.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_structural_operations.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_structured_provider_contract.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_tasking_state.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_v070_engineering_breadth.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_v080_autonomy.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_v080_provider_benchmark.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_v080_skills_automations.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_workspace_environment.py +0 -0
- {devagent_ai-0.8.4 → devagent_ai-0.8.6}/tests/test_worktree.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devagent-ai
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.6
|
|
4
4
|
Summary: Evidence-driven local autonomous software engineering agent
|
|
5
5
|
Author: Tom Ha
|
|
6
6
|
Maintainer: Tom Ha
|
|
@@ -9,6 +9,7 @@ Project-URL: Homepage, https://github.com/tomha85/devagent
|
|
|
9
9
|
Project-URL: Repository, https://github.com/tomha85/devagent
|
|
10
10
|
Project-URL: Issues, https://github.com/tomha85/devagent/issues
|
|
11
11
|
Project-URL: Changelog, https://github.com/tomha85/devagent/blob/main/CHANGELOG.md
|
|
12
|
+
Project-URL: Sponsor, https://github.com/sponsors/tomha85
|
|
12
13
|
Keywords: ai,agent,developer-tools,software-engineering,verification,local-first
|
|
13
14
|
Classifier: Development Status :: 4 - Beta
|
|
14
15
|
Classifier: Intended Audience :: Developers
|
|
@@ -23,6 +24,7 @@ License-File: LICENSE
|
|
|
23
24
|
License-File: NOTICE
|
|
24
25
|
Requires-Dist: openai>=1.40.0
|
|
25
26
|
Requires-Dist: anthropic>=0.34.0
|
|
27
|
+
Requires-Dist: cryptography>=42.0.0
|
|
26
28
|
Requires-Dist: tomli>=2.0.0; python_version < "3.11"
|
|
27
29
|
Provides-Extra: dev
|
|
28
30
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
@@ -35,11 +37,14 @@ Dynamic: license-file
|
|
|
35
37
|
[](https://www.python.org/)
|
|
36
38
|
[](#project-status)
|
|
37
39
|
[](https://github.com/tomha85/devagent/actions/workflows/ci.yml)
|
|
40
|
+
[](https://github.com/sponsors/tomha85)
|
|
38
41
|
|
|
39
42
|
**A local, evidence-driven software engineering agent that turns a requirement into a tested, independently reviewed patch, prints a developer-grade engineering report, and only publishes a branch when the result is `VERIFIED`.**
|
|
40
43
|
|
|
41
44
|
> **From requirement to evidence-backed verified branch.**
|
|
42
45
|
|
|
46
|
+
> ❤️ **DevAgent is free during public beta.** If DevAgent saves you engineering time, consider [sponsoring continued development](https://github.com/sponsors/tomha85).
|
|
47
|
+
|
|
43
48
|
DevAgent runs against a developer's local repository. It discovers the application, gathers source evidence, compiles explicit acceptance criteria, plans a bounded change, creates backups, implements the minimum necessary patch, runs repository-supported verification, independently reviews the final diff, and decides `VERIFIED`, `PARTIALLY_VERIFIED`, or `BLOCKED` from evidence rather than model confidence.
|
|
44
49
|
|
|
45
50
|
For a normal verified run the deterministic harness prints the complete engineering report first, then commits reviewed paths and fast-forward pushes the developer's current non-protected branch. If the developer starts on `main`, `master`, or `trunk`, DevAgent creates a new safe branch instead. Runtime DevAgent never creates a pull request, merges, rebases, force-pushes, or deploys.
|
|
@@ -545,6 +550,23 @@ Remaining work is primarily **breadth and external validation**, not missing cor
|
|
|
545
550
|
|
|
546
551
|
The project intentionally prioritizes trustworthy outcomes, reproducible evidence, and safe engineering behavior over feature count or unsupported "best agent" claims.
|
|
547
552
|
|
|
553
|
+
## ❤️ Support DevAgent
|
|
554
|
+
|
|
555
|
+
DevAgent is currently free to use during public beta.
|
|
556
|
+
|
|
557
|
+
If DevAgent saves you engineering time or helps you deliver safer, better-verified software or PLC engineering work, you can support continued development through [GitHub Sponsors](https://github.com/sponsors/tomha85).
|
|
558
|
+
|
|
559
|
+
Your sponsorship helps fund:
|
|
560
|
+
|
|
561
|
+
- new engineering and PLC capabilities;
|
|
562
|
+
- Siemens and Rockwell verification;
|
|
563
|
+
- additional AI provider support;
|
|
564
|
+
- regression and production qualification;
|
|
565
|
+
- documentation and examples;
|
|
566
|
+
- continued free public releases.
|
|
567
|
+
|
|
568
|
+
[](https://github.com/sponsors/tomha85)
|
|
569
|
+
|
|
548
570
|
## Contributing
|
|
549
571
|
|
|
550
572
|
Contributions are welcome. Read [CONTRIBUTING.md](CONTRIBUTING.md) before opening a pull request. Changes to safety, verification, reporting, acceptance semantics, providers, or bounded publication behavior should include regression evidence and must not give model-generated actions unrestricted Git publishing authority.
|
|
@@ -4,11 +4,14 @@
|
|
|
4
4
|
[](https://www.python.org/)
|
|
5
5
|
[](#project-status)
|
|
6
6
|
[](https://github.com/tomha85/devagent/actions/workflows/ci.yml)
|
|
7
|
+
[](https://github.com/sponsors/tomha85)
|
|
7
8
|
|
|
8
9
|
**A local, evidence-driven software engineering agent that turns a requirement into a tested, independently reviewed patch, prints a developer-grade engineering report, and only publishes a branch when the result is `VERIFIED`.**
|
|
9
10
|
|
|
10
11
|
> **From requirement to evidence-backed verified branch.**
|
|
11
12
|
|
|
13
|
+
> ❤️ **DevAgent is free during public beta.** If DevAgent saves you engineering time, consider [sponsoring continued development](https://github.com/sponsors/tomha85).
|
|
14
|
+
|
|
12
15
|
DevAgent runs against a developer's local repository. It discovers the application, gathers source evidence, compiles explicit acceptance criteria, plans a bounded change, creates backups, implements the minimum necessary patch, runs repository-supported verification, independently reviews the final diff, and decides `VERIFIED`, `PARTIALLY_VERIFIED`, or `BLOCKED` from evidence rather than model confidence.
|
|
13
16
|
|
|
14
17
|
For a normal verified run the deterministic harness prints the complete engineering report first, then commits reviewed paths and fast-forward pushes the developer's current non-protected branch. If the developer starts on `main`, `master`, or `trunk`, DevAgent creates a new safe branch instead. Runtime DevAgent never creates a pull request, merges, rebases, force-pushes, or deploys.
|
|
@@ -514,6 +517,23 @@ Remaining work is primarily **breadth and external validation**, not missing cor
|
|
|
514
517
|
|
|
515
518
|
The project intentionally prioritizes trustworthy outcomes, reproducible evidence, and safe engineering behavior over feature count or unsupported "best agent" claims.
|
|
516
519
|
|
|
520
|
+
## ❤️ Support DevAgent
|
|
521
|
+
|
|
522
|
+
DevAgent is currently free to use during public beta.
|
|
523
|
+
|
|
524
|
+
If DevAgent saves you engineering time or helps you deliver safer, better-verified software or PLC engineering work, you can support continued development through [GitHub Sponsors](https://github.com/sponsors/tomha85).
|
|
525
|
+
|
|
526
|
+
Your sponsorship helps fund:
|
|
527
|
+
|
|
528
|
+
- new engineering and PLC capabilities;
|
|
529
|
+
- Siemens and Rockwell verification;
|
|
530
|
+
- additional AI provider support;
|
|
531
|
+
- regression and production qualification;
|
|
532
|
+
- documentation and examples;
|
|
533
|
+
- continued free public releases.
|
|
534
|
+
|
|
535
|
+
[](https://github.com/sponsors/tomha85)
|
|
536
|
+
|
|
517
537
|
## Contributing
|
|
518
538
|
|
|
519
539
|
Contributions are welcome. Read [CONTRIBUTING.md](CONTRIBUTING.md) before opening a pull request. Changes to safety, verification, reporting, acceptance semantics, providers, or bounded publication behavior should include regression evidence and must not give model-generated actions unrestricted Git publishing authority.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from typing import Sequence
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def main(argv: Sequence[str] | None = None) -> int:
|
|
8
|
+
"""Route domain subcommands without changing the existing software CLI."""
|
|
9
|
+
|
|
10
|
+
arguments = list(sys.argv[1:] if argv is None else argv)
|
|
11
|
+
if len(arguments) >= 2 and arguments[0] == "plc" and arguments[1] == "inspect":
|
|
12
|
+
from devagent.plc.inspect_cli import main as plc_inspect_main
|
|
13
|
+
|
|
14
|
+
return plc_inspect_main(arguments[2:])
|
|
15
|
+
if arguments and arguments[0] == "plc":
|
|
16
|
+
from devagent.plc.cli import main as plc_main
|
|
17
|
+
|
|
18
|
+
return plc_main(arguments[1:])
|
|
19
|
+
|
|
20
|
+
from devagent.cli import main as software_main
|
|
21
|
+
|
|
22
|
+
return software_main(arguments)
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"""Vendor-neutral PLC engineering and production verification foundations for DevAgent."""
|
|
2
|
+
|
|
3
|
+
from devagent.plc import analysis as _analysis
|
|
4
|
+
from devagent.plc.rockwell_compare_hardening import install as _install_rockwell_compare_hardening
|
|
5
|
+
from devagent.plc.rockwell_alias_hardening import install as _install_rockwell_alias_hardening
|
|
6
|
+
from devagent.plc.rockwell_entrypoint_hardening import install as _install_rockwell_entrypoint_hardening
|
|
7
|
+
from devagent.plc.rockwell_st_v10 import install as _install_rockwell_st_v10
|
|
8
|
+
|
|
9
|
+
# Install fail-closed compare, alias, controller-entrypoint, and ST guards before
|
|
10
|
+
# production verification is imported. Every downstream Rockwell proof must
|
|
11
|
+
# share the same canonical writer identity and executable-entrypoint model.
|
|
12
|
+
_install_rockwell_compare_hardening()
|
|
13
|
+
_install_rockwell_alias_hardening()
|
|
14
|
+
_install_rockwell_entrypoint_hardening()
|
|
15
|
+
_install_rockwell_st_v10()
|
|
16
|
+
|
|
17
|
+
from devagent.plc.rockwell_compare_reachability_hardening import (
|
|
18
|
+
install as _install_rockwell_compare_reachability_hardening,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
# The typed-compare theorem/FAT path is independent from boolean output-logic
|
|
22
|
+
# normalization, so explicitly bind it to the same executable routine closure.
|
|
23
|
+
_install_rockwell_compare_reachability_hardening()
|
|
24
|
+
|
|
25
|
+
from devagent.plc.rockwell_requirement_hardening import install as _install_rockwell_requirement_hardening
|
|
26
|
+
from devagent.plc.rockwell_v10_semantics import install as _install_rockwell_v10_semantics
|
|
27
|
+
from devagent.plc.rockwell_action_requirements import install as _install_rockwell_action_requirements
|
|
28
|
+
from devagent.plc.rockwell_risk_hardening import install as _install_rockwell_risk_hardening
|
|
29
|
+
from devagent.plc.rockwell_closeout_gate_hardening import install as _install_rockwell_closeout_gate_hardening
|
|
30
|
+
|
|
31
|
+
_install_rockwell_requirement_hardening()
|
|
32
|
+
# V10 extends the already-hardened V9 theorem. It proves bounded OTL/OTU action
|
|
33
|
+
# effects and may prove final retained scan state only inside the deliberately
|
|
34
|
+
# narrow same-active-Main-RLL-routine ordering theorem. Wider scheduling remains
|
|
35
|
+
# fail-closed until explicitly modeled.
|
|
36
|
+
_install_rockwell_v10_semantics()
|
|
37
|
+
# Explicit natural-language requirements may bind to deterministic MOV/COPY/
|
|
38
|
+
# CLR/RES local action effects, but never to final scan/process behavior.
|
|
39
|
+
_install_rockwell_action_requirements()
|
|
40
|
+
_install_rockwell_risk_hardening()
|
|
41
|
+
# Install the V9 support-contract guard before importing regression/production
|
|
42
|
+
# modules. Those modules import safe_analysis by value, so the patched support
|
|
43
|
+
# check must already be visible when safe_analysis is first loaded.
|
|
44
|
+
_install_rockwell_closeout_gate_hardening()
|
|
45
|
+
|
|
46
|
+
from devagent.plc.rockwell_core_review_v12 import install as _install_rockwell_core_review_v12
|
|
47
|
+
|
|
48
|
+
# V12 makes the commercial engineering-review contract explicit: cause/effect,
|
|
49
|
+
# unreachable logic, contradictory linear paths, and sequence-branch risks are
|
|
50
|
+
# deterministic review outputs. They remain evidence-backed findings, not AI
|
|
51
|
+
# guesses and not runtime PASS claims.
|
|
52
|
+
_install_rockwell_core_review_v12()
|
|
53
|
+
|
|
54
|
+
from devagent.plc.fat_procedure_v12 import install as _install_fat_procedure_v12
|
|
55
|
+
|
|
56
|
+
# Every FAT candidate, including tests created later by requirement mapping,
|
|
57
|
+
# must be an engineer-ready manual procedure. DevAgent plans the FAT; it does not
|
|
58
|
+
# connect to or execute the engineer's external simulator/HIL/controller.
|
|
59
|
+
_install_fat_procedure_v12()
|
|
60
|
+
|
|
61
|
+
from devagent.plc.rockwell_regression_evidence_hardening import (
|
|
62
|
+
install as _install_rockwell_regression_evidence_hardening,
|
|
63
|
+
install_domain_evidence as _install_rockwell_regression_domain_evidence,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
_install_rockwell_regression_evidence_hardening()
|
|
67
|
+
|
|
68
|
+
from devagent.plc.rockwell_regression_case_compat_v12 import (
|
|
69
|
+
install as _install_rockwell_regression_case_compat_v12,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# FAT-plan regression is semantic and case-insensitive. Studio 5000 identifier
|
|
73
|
+
# spelling changes alone must not force a retest or create a false regression.
|
|
74
|
+
_install_rockwell_regression_case_compat_v12()
|
|
75
|
+
|
|
76
|
+
from devagent.plc.rockwell_branch_coverage_v16 import install as _install_rockwell_branch_coverage_v16
|
|
77
|
+
|
|
78
|
+
# V16 reconciles branch coverage with the full deterministic theorem set. A
|
|
79
|
+
# neutral-text branch proven by the bounded data/compute action theorem counts
|
|
80
|
+
# as modeled even when it is not an OTE/OTL/OTU boolean-output branch. Mixed or
|
|
81
|
+
# partially understood branch grammars remain fail-closed and withheld.
|
|
82
|
+
_install_rockwell_branch_coverage_v16()
|
|
83
|
+
|
|
84
|
+
from devagent.plc.rockwell_system_service_install_v17 import (
|
|
85
|
+
install as _install_rockwell_system_service_v17,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# V17 does not widen static proof. Reachable GSV/SSV system-service logic stays
|
|
89
|
+
# PARTIAL, but every such runtime-dependent gap receives an evidence-linked,
|
|
90
|
+
# engineer-executed FAT procedure and a specific commissioning risk. The install
|
|
91
|
+
# happens before production imports capture analysis/risk functions by value.
|
|
92
|
+
_install_rockwell_system_service_v17()
|
|
93
|
+
|
|
94
|
+
from devagent.plc.semantic_coverage_report import install as _install_semantic_coverage_report
|
|
95
|
+
|
|
96
|
+
# Ensure any later CLI import of render_production_report receives the
|
|
97
|
+
# reachability-aware semantic coverage augmentation.
|
|
98
|
+
_install_semantic_coverage_report()
|
|
99
|
+
|
|
100
|
+
from devagent.plc.rockwell_system_service_report_install_v17 import (
|
|
101
|
+
install as _install_rockwell_system_service_report_v17,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# Keep the public report renderer identity stable while adding an explicit V17
|
|
105
|
+
# system-service runtime boundary inside the semantic coverage section.
|
|
106
|
+
_install_rockwell_system_service_report_v17()
|
|
107
|
+
|
|
108
|
+
from devagent.plc.four_contract_v13 import install as _install_four_contract_v13
|
|
109
|
+
|
|
110
|
+
# V13 makes the commercial four-core contract explicit and testable:
|
|
111
|
+
# engineering analysis, logic/risk review, five-area optimization recommendations,
|
|
112
|
+
# and engineer-ready FAT planning. All optimization output is advisory only.
|
|
113
|
+
_install_four_contract_v13()
|
|
114
|
+
|
|
115
|
+
from devagent.plc.professional_report_install_v14 import install as _install_professional_report_v14
|
|
116
|
+
|
|
117
|
+
# V14 adds a customer-facing executive layer while preserving every detailed
|
|
118
|
+
# engineering/evidence section and the established public renderer identity.
|
|
119
|
+
# This is presentation-only: it cannot change deterministic verdicts/readiness.
|
|
120
|
+
_install_professional_report_v14()
|
|
121
|
+
|
|
122
|
+
from devagent.plc.report_clarity_install_v16 import install as _install_report_clarity_v16
|
|
123
|
+
|
|
124
|
+
# V16 clarifies project-only review and coverage terminology without changing
|
|
125
|
+
# deterministic engineering, risk, FAT, or release-readiness decisions.
|
|
126
|
+
_install_report_clarity_v16()
|
|
127
|
+
|
|
128
|
+
from devagent.plc.agent_harness_install_v15 import install as _install_agent_harness_v15
|
|
129
|
+
|
|
130
|
+
# V15 applies modern agent orchestration only to the probabilistic assistance
|
|
131
|
+
# layer: bounded propose/critic/revise graphs, deterministic evidence guards, and
|
|
132
|
+
# per-run trace capture. The PLC proof/risk/readiness core stays authoritative.
|
|
133
|
+
_install_agent_harness_v15()
|
|
134
|
+
|
|
135
|
+
from devagent.plc.siemens_integration_v1 import install as _install_siemens_integration_v1
|
|
136
|
+
|
|
137
|
+
# Siemens V1 is a vendor branch over the already-qualified production contract.
|
|
138
|
+
# It accepts offline TIA Portal Openness/XML and generated-source exports, proves
|
|
139
|
+
# only bounded top-level SCL semantics, and leaves control-flow/LAD/FBD/GRAPH/STL
|
|
140
|
+
# or protected behavior PARTIAL/OPAQUE. Qualified Rockwell dispatch still enters
|
|
141
|
+
# the exact guarded Rockwell analyzer above.
|
|
142
|
+
_install_siemens_integration_v1()
|
|
143
|
+
|
|
144
|
+
from devagent.plc.siemens_scl_control_flow_v2 import install as _install_siemens_scl_control_flow_v2
|
|
145
|
+
|
|
146
|
+
# Siemens V2 adds a deliberately bounded deterministic theorem for complete,
|
|
147
|
+
# single-level IF/ELSIF/ELSE Boolean assignment chains. Missing/incomplete branch
|
|
148
|
+
# assignments, nesting, CASE/loops, calls, cyclic/self-references, and unsupported
|
|
149
|
+
# expressions stay fail-closed and require engineer-executed FAT evidence.
|
|
150
|
+
_install_siemens_scl_control_flow_v2()
|
|
151
|
+
|
|
152
|
+
from devagent.plc.siemens_scl_control_flow_hardening_v2 import (
|
|
153
|
+
install as _install_siemens_scl_control_flow_hardening_v2,
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
# A syntactically complete inner IF is still nested control flow. Do not allow an
|
|
157
|
+
# inner chain to become independently FULL when its enclosing region is outside
|
|
158
|
+
# the V2 single-level theorem.
|
|
159
|
+
_install_siemens_scl_control_flow_hardening_v2()
|
|
160
|
+
|
|
161
|
+
from devagent.plc.production_v5 import run_production_verification_v5
|
|
162
|
+
from devagent.plc.siemens_v5_bindings_v1 import install as _install_siemens_v5_bindings_v1
|
|
163
|
+
|
|
164
|
+
# Agent Harness V15 loads Production V5 before Siemens integration. Refresh only
|
|
165
|
+
# V5's by-value shared production/evidence/review bindings after Siemens installs.
|
|
166
|
+
# Siemens then reaches the vendor dispatcher while Rockwell remains behind the
|
|
167
|
+
# exact qualified Rockwell functions selected by those vendor-aware wrappers.
|
|
168
|
+
_install_siemens_v5_bindings_v1()
|
|
169
|
+
|
|
170
|
+
# Production is now loaded; bind the stage-14 baseline evidence augmentation.
|
|
171
|
+
_install_rockwell_regression_domain_evidence()
|
|
172
|
+
from devagent.plc.safe_analysis import analyze_rockwell_l5x
|
|
173
|
+
from devagent.plc.plc_dispatch import analyze_plc_project
|
|
174
|
+
from devagent.plc.siemens_cli_install_v1 import install as _install_siemens_cli_v1
|
|
175
|
+
|
|
176
|
+
# CLI parsing is loaded only after production_v5 exists, avoiding circular
|
|
177
|
+
# imports while exposing both vendor input contracts through `devagent plc`.
|
|
178
|
+
_install_siemens_cli_v1()
|
|
179
|
+
|
|
180
|
+
# Keep existing imports from ``devagent.plc.analysis`` on the guarded Rockwell
|
|
181
|
+
# public path. The base module remains reusable by ``safe_analysis`` without
|
|
182
|
+
# recursive calls; vendor-neutral callers should use analyze_plc_project.
|
|
183
|
+
_analysis.analyze_rockwell_l5x = analyze_rockwell_l5x
|
|
184
|
+
|
|
185
|
+
__all__ = ["analyze_plc_project", "analyze_rockwell_l5x", "run_production_verification_v5"]
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Callable
|
|
4
|
+
|
|
5
|
+
from devagent.plc.agent_harness_v15 import begin_run_trace, end_run_trace
|
|
6
|
+
from devagent.plc import production_v5
|
|
7
|
+
|
|
8
|
+
_ORIGINAL: Callable[..., Any] = production_v5.run_production_verification_v5
|
|
9
|
+
_INSTALLED = False
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _run_with_harness_trace(*args: Any, **kwargs: Any):
|
|
13
|
+
trace, token = begin_run_trace()
|
|
14
|
+
try:
|
|
15
|
+
result = _ORIGINAL(*args, **kwargs)
|
|
16
|
+
result.ai_harness_trace = list(trace)
|
|
17
|
+
return result
|
|
18
|
+
finally:
|
|
19
|
+
end_run_trace(token)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def install() -> None:
|
|
23
|
+
global _INSTALLED
|
|
24
|
+
if _INSTALLED:
|
|
25
|
+
return
|
|
26
|
+
production_v5.run_production_verification_v5 = _run_with_harness_trace
|
|
27
|
+
_INSTALLED = True
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from contextvars import ContextVar, Token
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from devagent.providers import ModelProvider
|
|
7
|
+
|
|
8
|
+
# The PLC agent harness is deliberately small and explicit. It is not part of the
|
|
9
|
+
# deterministic PLC proof engine. It only governs AI review candidates before
|
|
10
|
+
# they are admitted as AI_CANDIDATE observations.
|
|
11
|
+
MAX_REVIEW_ITERATIONS = 2
|
|
12
|
+
_ACTIVE_TRACE: ContextVar[list[dict[str, Any]] | None] = ContextVar(
|
|
13
|
+
"devagent_plc_agent_harness_trace",
|
|
14
|
+
default=None,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
REVIEW_CRITIC_SCHEMA: dict[str, Any] = {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"additionalProperties": False,
|
|
20
|
+
"required": ["decisions"],
|
|
21
|
+
"properties": {
|
|
22
|
+
"decisions": {
|
|
23
|
+
"type": "array",
|
|
24
|
+
"maxItems": 24,
|
|
25
|
+
"items": {
|
|
26
|
+
"type": "object",
|
|
27
|
+
"additionalProperties": False,
|
|
28
|
+
"required": ["finding_id", "decision", "reason", "supported_evidence_ids"],
|
|
29
|
+
"properties": {
|
|
30
|
+
"finding_id": {"type": "string", "minLength": 1},
|
|
31
|
+
"decision": {"type": "string", "enum": ["ACCEPT", "REVISE", "REJECT"]},
|
|
32
|
+
"reason": {"type": "string", "minLength": 1},
|
|
33
|
+
"supported_evidence_ids": {
|
|
34
|
+
"type": "array",
|
|
35
|
+
"maxItems": 8,
|
|
36
|
+
"items": {"type": "string", "minLength": 1},
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
REQUIREMENT_CRITIC_SCHEMA: dict[str, Any] = {
|
|
45
|
+
"type": "object",
|
|
46
|
+
"additionalProperties": False,
|
|
47
|
+
"required": ["decisions"],
|
|
48
|
+
"properties": {
|
|
49
|
+
"decisions": {
|
|
50
|
+
"type": "array",
|
|
51
|
+
"maxItems": 50,
|
|
52
|
+
"items": {
|
|
53
|
+
"type": "object",
|
|
54
|
+
"additionalProperties": False,
|
|
55
|
+
"required": ["requirement_id", "decision", "reason", "supported_evidence_ids"],
|
|
56
|
+
"properties": {
|
|
57
|
+
"requirement_id": {"type": "string", "minLength": 1},
|
|
58
|
+
"decision": {"type": "string", "enum": ["ACCEPT", "REJECT"]},
|
|
59
|
+
"reason": {"type": "string", "minLength": 1},
|
|
60
|
+
"supported_evidence_ids": {
|
|
61
|
+
"type": "array",
|
|
62
|
+
"maxItems": 8,
|
|
63
|
+
"items": {"type": "string", "minLength": 1},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def begin_run_trace() -> tuple[list[dict[str, Any]], Token[list[dict[str, Any]] | None]]:
|
|
73
|
+
sink: list[dict[str, Any]] = []
|
|
74
|
+
return sink, _ACTIVE_TRACE.set(sink)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def end_run_trace(token: Token[list[dict[str, Any]] | None]) -> None:
|
|
78
|
+
_ACTIVE_TRACE.reset(token)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def trace(
|
|
82
|
+
sink: list[dict[str, Any]] | None,
|
|
83
|
+
*,
|
|
84
|
+
graph: str,
|
|
85
|
+
node: str,
|
|
86
|
+
iteration: int,
|
|
87
|
+
outcome: str,
|
|
88
|
+
detail: str,
|
|
89
|
+
counts: dict[str, int] | None = None,
|
|
90
|
+
) -> None:
|
|
91
|
+
target = sink if sink is not None else _ACTIVE_TRACE.get()
|
|
92
|
+
if target is None:
|
|
93
|
+
return
|
|
94
|
+
event: dict[str, Any] = {
|
|
95
|
+
"graph": graph,
|
|
96
|
+
"node": node,
|
|
97
|
+
"iteration": iteration,
|
|
98
|
+
"outcome": outcome,
|
|
99
|
+
"detail": detail,
|
|
100
|
+
}
|
|
101
|
+
if counts:
|
|
102
|
+
event["counts"] = dict(sorted(counts.items()))
|
|
103
|
+
target.append(event)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def critique_review_candidates(
|
|
107
|
+
provider: ModelProvider,
|
|
108
|
+
*,
|
|
109
|
+
candidates: list[dict[str, Any]],
|
|
110
|
+
evidence: list[dict[str, Any]],
|
|
111
|
+
iteration: int,
|
|
112
|
+
trace_sink: list[dict[str, Any]] | None,
|
|
113
|
+
) -> dict[str, dict[str, Any]]:
|
|
114
|
+
if not candidates:
|
|
115
|
+
return {}
|
|
116
|
+
trace(
|
|
117
|
+
trace_sink,
|
|
118
|
+
graph="PLC_ENGINEERING_REVIEW",
|
|
119
|
+
node="CRITIC",
|
|
120
|
+
iteration=iteration,
|
|
121
|
+
outcome="START",
|
|
122
|
+
detail="Evaluate AI review candidates for evidence support, boundedness, and unsupported runtime/safety claims.",
|
|
123
|
+
counts={"candidates": len(candidates)},
|
|
124
|
+
)
|
|
125
|
+
response = provider.request(
|
|
126
|
+
role="plc_engineering_critic",
|
|
127
|
+
payload={
|
|
128
|
+
"instruction": (
|
|
129
|
+
"Act as an independent PLC review critic. Evaluate only the supplied candidate findings and evidence. "
|
|
130
|
+
"ACCEPT only when the finding is directly supported by its cited evidence and does not claim runtime behavior, safety certification, PASS, or release readiness. "
|
|
131
|
+
"Use REVISE when the core concern is supported but wording/claims overreach. REJECT unsupported findings. "
|
|
132
|
+
"supported_evidence_ids must be a subset of evidence actually supporting the candidate."
|
|
133
|
+
),
|
|
134
|
+
"candidates": candidates,
|
|
135
|
+
"evidence": evidence,
|
|
136
|
+
},
|
|
137
|
+
schema=REVIEW_CRITIC_SCHEMA,
|
|
138
|
+
)
|
|
139
|
+
decisions = {
|
|
140
|
+
str(item["finding_id"]): item
|
|
141
|
+
for item in response.get("decisions", [])
|
|
142
|
+
if isinstance(item, dict) and item.get("finding_id")
|
|
143
|
+
}
|
|
144
|
+
trace(
|
|
145
|
+
trace_sink,
|
|
146
|
+
graph="PLC_ENGINEERING_REVIEW",
|
|
147
|
+
node="CRITIC",
|
|
148
|
+
iteration=iteration,
|
|
149
|
+
outcome="COMPLETE",
|
|
150
|
+
detail="Independent critic completed candidate evaluation.",
|
|
151
|
+
counts={
|
|
152
|
+
"accepted": sum(1 for item in decisions.values() if item.get("decision") == "ACCEPT"),
|
|
153
|
+
"revise": sum(1 for item in decisions.values() if item.get("decision") == "REVISE"),
|
|
154
|
+
"rejected": sum(1 for item in decisions.values() if item.get("decision") == "REJECT"),
|
|
155
|
+
},
|
|
156
|
+
)
|
|
157
|
+
return decisions
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def critique_requirement_mappings(
|
|
161
|
+
provider: ModelProvider,
|
|
162
|
+
*,
|
|
163
|
+
mappings: list[dict[str, Any]],
|
|
164
|
+
evidence: list[dict[str, Any]],
|
|
165
|
+
iteration: int,
|
|
166
|
+
trace_sink: list[dict[str, Any]] | None,
|
|
167
|
+
) -> dict[str, dict[str, Any]]:
|
|
168
|
+
if not mappings:
|
|
169
|
+
return {}
|
|
170
|
+
trace(
|
|
171
|
+
trace_sink,
|
|
172
|
+
graph="PLC_REQUIREMENT_MAPPING",
|
|
173
|
+
node="CRITIC",
|
|
174
|
+
iteration=iteration,
|
|
175
|
+
outcome="START",
|
|
176
|
+
detail="Evaluate AI requirement trace candidates without permitting verification promotion.",
|
|
177
|
+
counts={"mappings": len(mappings)},
|
|
178
|
+
)
|
|
179
|
+
response = provider.request(
|
|
180
|
+
role="plc_requirement_critic",
|
|
181
|
+
payload={
|
|
182
|
+
"instruction": (
|
|
183
|
+
"Evaluate only whether each proposed requirement-to-evidence trace candidate is plausibly supported by the supplied evidence. "
|
|
184
|
+
"Never declare VERIFIED, PASS, SAFE, compliant, or release-ready. ACCEPT only grounded traceability candidates; otherwise REJECT."
|
|
185
|
+
),
|
|
186
|
+
"mappings": mappings,
|
|
187
|
+
"evidence": evidence,
|
|
188
|
+
},
|
|
189
|
+
schema=REQUIREMENT_CRITIC_SCHEMA,
|
|
190
|
+
)
|
|
191
|
+
decisions = {
|
|
192
|
+
str(item["requirement_id"]): item
|
|
193
|
+
for item in response.get("decisions", [])
|
|
194
|
+
if isinstance(item, dict) and item.get("requirement_id")
|
|
195
|
+
}
|
|
196
|
+
trace(
|
|
197
|
+
trace_sink,
|
|
198
|
+
graph="PLC_REQUIREMENT_MAPPING",
|
|
199
|
+
node="CRITIC",
|
|
200
|
+
iteration=iteration,
|
|
201
|
+
outcome="COMPLETE",
|
|
202
|
+
detail="Independent requirement critic completed mapping evaluation.",
|
|
203
|
+
counts={
|
|
204
|
+
"accepted": sum(1 for item in decisions.values() if item.get("decision") == "ACCEPT"),
|
|
205
|
+
"rejected": sum(1 for item in decisions.values() if item.get("decision") == "REJECT"),
|
|
206
|
+
},
|
|
207
|
+
)
|
|
208
|
+
return decisions
|