consequa-x 1.2.0__tar.gz → 2.0.0__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.
- {consequa_x-1.2.0 → consequa_x-2.0.0}/CHANGELOG.md +118 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/MANIFEST.in +2 -0
- {consequa_x-1.2.0/src/consequa_x.egg-info → consequa_x-2.0.0}/PKG-INFO +82 -72
- {consequa_x-1.2.0 → consequa_x-2.0.0}/README.md +81 -71
- consequa_x-2.0.0/docs/application-integration.md +130 -0
- consequa_x-2.0.0/docs/design-2.0.md +109 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/design.md +2 -2
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/framework-integration.md +45 -30
- consequa_x-2.0.0/docs/migrating-to-2.0.md +100 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/offline-reports.md +16 -5
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/product-roadmap.md +55 -54
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/quickstart.md +15 -13
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/release-notes.md +28 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/research-roadmap.md +5 -4
- consequa_x-2.0.0/docs/stable-api.md +110 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/examples/agent_loop_sqlite.py +8 -8
- {consequa_x-1.2.0 → consequa_x-2.0.0}/examples/artifact_delivery.py +33 -33
- {consequa_x-1.2.0 → consequa_x-2.0.0}/pyproject.toml +1 -1
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/analyze_matched_local_study.py +7 -7
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/audit_interaction_sampling.py +10 -10
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/audit_refund_interactions.py +1 -1
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/audit_release_artifacts.py +3 -2
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/build_public_docs.py +6 -6
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/build_site_demo.py +10 -9
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/check_installed_release.py +173 -77
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/export_render_site.py +1 -1
- consequa_x-2.0.0/scripts/refresh_sample_report.py +61 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/run_matched_trace_judge.py +1 -1
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/run_tau_benchmark_validation.py +18 -18
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/run_upstream_car_study.py +5 -3
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/summarize_matched_execution.py +2 -2
- consequa_x-2.0.0/src/consequa_x/__init__.py +54 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/attribution.py +3 -1
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/benchmark/decision_replay.py +6 -5
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/benchmark/evaluation.py +8 -8
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/benchmark/interaction_sampling.py +1 -1
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/benchmark/payments.py +5 -4
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/benchmark/policy_experiment.py +5 -5
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/benchmark/policy_runner.py +17 -15
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/benchmark/runner.py +25 -20
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/benchmark/targets.py +1 -1
- consequa_x-2.0.0/src/consequa_x/capture.py +547 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/cli.py +209 -6
- consequa_x-2.0.0/src/consequa_x/compare.py +106 -0
- consequa_x-2.0.0/src/consequa_x/errors.py +35 -0
- consequa_x-2.0.0/src/consequa_x/explanation.py +222 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/graph.py +26 -15
- consequa_x-2.0.0/src/consequa_x/guard.py +79 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/mcp_capture.py +10 -6
- consequa_x-2.0.0/src/consequa_x/migrate.py +180 -0
- consequa_x-2.0.0/src/consequa_x/models.py +733 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/policies.py +6 -12
- consequa_x-2.0.0/src/consequa_x/readback.py +102 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/record_verifier.py +61 -61
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/report.py +123 -50
- consequa_x-2.0.0/src/consequa_x/research.py +22 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/schema.py +8 -5
- consequa_x-1.2.0/src/consequa_x/schemas/trace-v0.1.json → consequa_x-2.0.0/src/consequa_x/schemas/trace-v1.0.json +617 -543
- consequa_x-2.0.0/src/consequa_x/store.py +57 -0
- consequa_x-2.0.0/src/consequa_x/summary.py +142 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/verification.py +95 -18
- {consequa_x-1.2.0 → consequa_x-2.0.0/src/consequa_x.egg-info}/PKG-INFO +82 -72
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x.egg-info/SOURCES.txt +27 -2
- consequa_x-2.0.0/tests/fixtures/v0.1/README.md +13 -0
- consequa_x-2.0.0/tests/fixtures/v0.1/record-timeout-after-commit.json +234 -0
- consequa_x-2.0.0/tests/fixtures/v0.1/refund-another-actor.json +267 -0
- consequa_x-2.0.0/tests/fixtures/v0.1/refund-stale-readback.json +273 -0
- consequa_x-2.0.0/tests/fixtures/v0.1/refund-timeout-after-commit.explanation.json +455 -0
- consequa_x-2.0.0/tests/fixtures/v0.1/refund-timeout-after-commit.json +273 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_agent_loop_example.py +1 -1
- consequa_x-2.0.0/tests/test_async_capture.py +98 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_calibration.py +1 -1
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_calibration_mechanisms.py +1 -1
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_capture.py +49 -35
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_cli.py +1 -1
- consequa_x-2.0.0/tests/test_compare_verify_redact.py +95 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_decision_coalition.py +6 -3
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_decision_contrastive.py +3 -2
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_decision_replay.py +7 -5
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_decision_shapley.py +2 -1
- consequa_x-2.0.0/tests/test_docs_examples.py +20 -0
- consequa_x-2.0.0/tests/test_errors.py +87 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_graph.py +13 -9
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_graph_identity.py +6 -6
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_installed_release_check.py +7 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_integration.py +28 -28
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_interval_replay.py +3 -3
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_matched_baseline_audit.py +4 -4
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_matched_local_study.py +6 -6
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_matched_trace_judge.py +8 -7
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_mcp_capture.py +1 -1
- consequa_x-2.0.0/tests/test_migrate.py +118 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_model_eval_integration.py +4 -4
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_models.py +90 -50
- consequa_x-2.0.0/tests/test_multi_action.py +165 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_ollama.py +2 -2
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_payments.py +5 -4
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_policies.py +4 -4
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_policy_experiment.py +3 -3
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_policy_experiment_integration.py +5 -5
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_policy_runner.py +11 -10
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_public_integration.py +76 -88
- consequa_x-2.0.0/tests/test_readback_guard.py +96 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_record_verifier.py +46 -29
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_refund_interactions.py +1 -1
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_release_inventory.py +1 -1
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_replay_targets.py +4 -3
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_report.py +45 -41
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_report_cli.py +3 -3
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_research_integration.py +1 -1
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_schema.py +14 -13
- consequa_x-2.0.0/tests/test_summary_store.py +105 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_task_templates.py +1 -1
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_tau_benchmark_validation.py +5 -5
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_verification.py +7 -4
- consequa_x-1.2.0/docs/application-integration.md +0 -145
- consequa_x-1.2.0/docs/stable-api.md +0 -100
- consequa_x-1.2.0/src/consequa_x/__init__.py +0 -28
- consequa_x-1.2.0/src/consequa_x/capture.py +0 -376
- consequa_x-1.2.0/src/consequa_x/explanation.py +0 -216
- consequa_x-1.2.0/src/consequa_x/models.py +0 -532
- {consequa_x-1.2.0 → consequa_x-2.0.0}/CONTRIBUTING.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/LICENSE +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/SECURITY.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/attribution-calibration.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/build-contract.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/car-reproduction-plan.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/completion-plan.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/decision-contrastive.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/decision-replay.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/decision-shapley.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/graph-witnesses.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/interaction-sampling.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/interval-followup-plan.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/launch-readiness.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/local-pypi-setup.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/matched-trace-judge.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/policy-evaluation.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/policy-replay.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/refund-interactions.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/release-readiness.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/studies/matched-local-2026-10-18.json +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/studies/refund-family-candidates-v1.json +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/study-manifests.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/study-plan.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/tau-benchmark-validation.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/upstream-car-comparison.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/v1.1-release.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/docs/variable-length-game-plan.md +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/examples/decision_shapley_fixture.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/examples/report_quickstart.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/requirements-dev.lock +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/audit_interval_comparison.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/audit_review_revision.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/build_matched_study_figures.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/configure_pypi_auth.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/draw_paper_diagrams.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/finalize_interval_artifacts.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/finalize_matched_local_study.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/finalize_refund_artifacts.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/plot_interval_comparison.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/plot_paper_results.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/publish_alpha.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/publish_release.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/run_interaction_sampling.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/run_matched_local_study.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/scripts/summarize_interaction_sampling.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/setup.cfg +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/__main__.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/adapters/__init__.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/adapters/ollama.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/benchmark/__init__.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/benchmark/assessment_metrics.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/benchmark/calibration.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/benchmark/calibration_export.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/benchmark/calibration_mechanisms.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/benchmark/decision_coalition.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/benchmark/decision_contrastive.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/benchmark/decision_shapley.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/benchmark/interaction_export.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/benchmark/interaction_mechanisms.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/benchmark/interval_comparison.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/benchmark/intervals.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/benchmark/study.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/benchmark/templates.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x/py.typed +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x.egg-info/dependency_links.txt +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x.egg-info/entry_points.txt +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x.egg-info/requires.txt +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/src/consequa_x.egg-info/top_level.txt +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_assessment_metrics.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_attribution.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_calibration_cli.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_decision_contrastive_cli.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_decision_shapley_cli.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_interaction_sampling.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_interaction_sampling_cli.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_interaction_workers.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_interval_comparison.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_intervals.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_matched_execution_summary.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_matched_figure_builder.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_matched_study_finalizer.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_policy_evaluation.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_prompt_profile_cli.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_refund_interactions_cli.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_release_helpers.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_render_site_export.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_site_demo.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_snapshot_integrity.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_stable_release.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_study.py +0 -0
- {consequa_x-1.2.0 → consequa_x-2.0.0}/tests/test_upstream_car_study.py +0 -0
|
@@ -1,5 +1,118 @@
|
|
|
1
1
|
# Changes
|
|
2
2
|
|
|
3
|
+
## 2.0.0 - 19 October 2026 (breaking)
|
|
4
|
+
|
|
5
|
+
See [the 2.0 design](docs/design-2.0.md) and the
|
|
6
|
+
[migration guide](docs/migrating-to-2.0.md). Deferred to 2.1: verifier
|
|
7
|
+
composition, optional framework integrations and OpenTelemetry export.
|
|
8
|
+
|
|
9
|
+
- Typed exceptions: every intentional error derives from `ConsequaError` and
|
|
10
|
+
still from `ValueError` or `TypeError`. `ValidationError` (invalid records,
|
|
11
|
+
traces and settings; malformed JSON is now one too), `SchemaVersionError`,
|
|
12
|
+
`ConsequaTypeError`, `ContractError` (a verifier cannot evaluate the
|
|
13
|
+
contract), `ReceiptError` (a verifier or matcher result crosses its identity
|
|
14
|
+
boundary, or recorded evidence cannot support the interpretation) and
|
|
15
|
+
`RecorderError`. `InsufficientEvidenceError` and `PolicyError` join the
|
|
16
|
+
hierarchy.
|
|
17
|
+
- Captured payloads are deeply read-only. Event data, arguments, contract
|
|
18
|
+
expectations, results, readback records, scopes and evidence details are
|
|
19
|
+
`FrozenDict` and `FrozenList` values: they compare equal to and serialize
|
|
20
|
+
like ordinary dicts and lists, but any change raises `ConsequaTypeError`.
|
|
21
|
+
`copy.deepcopy` returns the same read-only value; `thaw()` returns an
|
|
22
|
+
editable copy, and `to_dict()` still exports ordinary dicts and lists.
|
|
23
|
+
- Trace schema `1.0`. A trace holds one or more `actions`, each with its own
|
|
24
|
+
contract; `responses`, `assessments` (zero or more per action) and
|
|
25
|
+
`verifications` each name their `action_id`. A required `time_base`
|
|
26
|
+
(`unix_ms` or `relative_ms`) says what the integer millisecond times count
|
|
27
|
+
from. `trace_id` is no longer repeated on actions and events. All records
|
|
28
|
+
are keyword-only. Schema `0.1` input is refused with a `SchemaVersionError`
|
|
29
|
+
that names the migration route; the packaged schema is `trace-v1.0.json`.
|
|
30
|
+
New helpers: `Trace.get_action`, `single_action`, `responses_for`,
|
|
31
|
+
`assessments_for`, `verifications_for`, `latest_assessment`,
|
|
32
|
+
`latest_verification`.
|
|
33
|
+
- `TraceRecorder.register` can be called for several actions and returns an
|
|
34
|
+
`ActionCapture` whose `attempt`, `call`, `dispatch`, `response`,
|
|
35
|
+
`assessment` and `verify` record for that action. The recorder-level methods
|
|
36
|
+
still work while exactly one action is registered. Assessments are optional
|
|
37
|
+
and may be repeated. The default clock is wall-clock `unix_ms`; a custom
|
|
38
|
+
clock records `relative_ms` unless told otherwise. `capture_tool` and
|
|
39
|
+
`call_mcp_tool` accept an `ActionCapture`.
|
|
40
|
+
- `explain()` returns a `TraceExplanation` with one `ActionExplanation` per
|
|
41
|
+
action (`for_action`, `single_action`). An action without verification is
|
|
42
|
+
reported as `NO_VERIFICATION` instead of raising. The evidence graph has a
|
|
43
|
+
contract node per action, and offline reports show every action, with an
|
|
44
|
+
Action column for responses and verifications and the time base in the
|
|
45
|
+
footer.
|
|
46
|
+
- Verifiers own domain interpretation. `VerificationResult` gains
|
|
47
|
+
`target_effect_ids` (`None` when the verifier did no target matching,
|
|
48
|
+
otherwise this action's effects that match the full target) and `findings`
|
|
49
|
+
(`Finding(code, effect_ids, detail)`). `RefundVerifier` records refund
|
|
50
|
+
matches and the `EXCESS_EFFECTS`, `DUPLICATE_EFFECT`, `PARAMETER_MISMATCH`,
|
|
51
|
+
`PARTIAL_EFFECT` and `REVERSED_EFFECT` findings; `RecordVerifier` records
|
|
52
|
+
record matches and `EXCESS_EFFECTS`, `DUPLICATE_EFFECT`,
|
|
53
|
+
`PARAMETER_MISMATCH` and `REMOVED_EFFECT`. `TargetMatcher`,
|
|
54
|
+
`RecordTargetMatcher`, `RecordVerifier.target_matcher()` and
|
|
55
|
+
`explain(..., target_matcher=...)` are removed; a custom verifier sets
|
|
56
|
+
`target_effect_ids` instead.
|
|
57
|
+
- `explain()` is domain-independent: it reads receipts, responses and
|
|
58
|
+
assessments and never reinterprets evidence details. Diagnoses are
|
|
59
|
+
structured `Diagnosis(code, evidence, message)` records; `codes` gives the
|
|
60
|
+
codes and `diagnosis` a display label. `UNASSESSABLE_ASSESSMENT` now applies
|
|
61
|
+
to every predicate whenever the outcome is known but alignment cannot be
|
|
62
|
+
judged (1.x omitted it for refunds). `CORE_DIAGNOSES` lists the codes
|
|
63
|
+
`explain()` produces.
|
|
64
|
+
- Offline reports show each action's assessment alignment and diagnosis
|
|
65
|
+
codes, computed from the recorded receipts. Codes from custom verifiers are
|
|
66
|
+
counted rather than printed.
|
|
67
|
+
- Migration: `migrate_trace()` and `consequa-x migrate OLD --output NEW`
|
|
68
|
+
convert schema `0.1` traces. Target matches and findings are added only when
|
|
69
|
+
the 2.0 verifier (the refund verifier by default; pass others with
|
|
70
|
+
`verifiers=`) reproduces the recorded receipt exactly; no recorded conclusion
|
|
71
|
+
is changed. `consequa-x validate` checks trace files. Migrated traces of the
|
|
72
|
+
1.x demo reproduce their 1.x explanations; fixtures written by the released
|
|
73
|
+
1.2.0 package are in `tests/fixtures/v0.1`.
|
|
74
|
+
- `summarize(traces)` and `consequa-x summarize PATH... [--format text|markdown|json]`
|
|
75
|
+
count verified state, origin, alignment, tool responses and diagnoses over
|
|
76
|
+
every action, with stated denominators; `unknown` and `unverified` stay
|
|
77
|
+
separate from failures, and actions with divergences or violations are
|
|
78
|
+
listed. Folders (non-trace JSON is skipped and counted) and `.jsonl` stores
|
|
79
|
+
are accepted; invalid inputs are listed by path and error type only and make
|
|
80
|
+
the command exit 2.
|
|
81
|
+
- `poll_readback(capture, read, until_ms=, interval_ms=)` waits until the
|
|
82
|
+
contract horizon, then reads back and verifies repeatedly (every observation
|
|
83
|
+
and receipt is recorded) until the outcome is `satisfied` or `violated` or the
|
|
84
|
+
time limit passes; an unresolved `unknown` is returned as is.
|
|
85
|
+
- Async agents: `capture_tool` wraps `async def` tools, `ActionCapture.acall`
|
|
86
|
+
(and `TraceRecorder.acall`) awaits a tool as one recorded attempt,
|
|
87
|
+
`averify`/`ActionCapture.averify` accept verifiers whose `verify` is a
|
|
88
|
+
coroutine (receipts are checked exactly as `verify` checks them), and
|
|
89
|
+
`apoll_readback` polls with awaited reads and `asyncio.sleep`.
|
|
90
|
+
- `retry_advice(receipt or trace)` turns verified evidence into
|
|
91
|
+
`DO_NOT_RETRY` (the outcome already holds, whoever produced it), `WAIT`
|
|
92
|
+
(missing or unknown readback), `ESCALATE` (relevant effects that do not
|
|
93
|
+
satisfy the contract) or `RETRY_PERMITTED` (a complete readback shows no
|
|
94
|
+
relevant effect; retry with an idempotency key, since an in-flight attempt can
|
|
95
|
+
still commit), each with a reason.
|
|
96
|
+
- `compare(left, right)` and `consequa-x compare A B [--fail-on-difference]`
|
|
97
|
+
compare two traces action by action: contract, tool responses, latest
|
|
98
|
+
assessment, verified state and origin, alignment and diagnosis codes, plus
|
|
99
|
+
actions present in only one trace.
|
|
100
|
+
- `consequa-x verify TRACE --readback OBS.json [--scope-field F] --output NEW`
|
|
101
|
+
verifies a captured readback file with the built-in refund or record
|
|
102
|
+
verifier and saves the trace with the new receipt, without Python code.
|
|
103
|
+
- `render_report(..., include_details=True, redact=("card_number", ...))` and
|
|
104
|
+
`consequa-x report --include-details --redact KEY` replace the values of the
|
|
105
|
+
named JSON keys everywhere in the included trace. Values under other keys are
|
|
106
|
+
kept; this is omission by name, not anonymization.
|
|
107
|
+
- `TraceStore(path)`: an append-only JSON Lines file of validated traces with
|
|
108
|
+
unique trace IDs; reading reports the line number of an invalid entry.
|
|
109
|
+
- Research interfaces (`EffectEstimate`, `Intervention`, `leave_one_out`,
|
|
110
|
+
`recency_attribution`, the policy types) are imported from
|
|
111
|
+
`consequa_x.research` instead of the top-level namespace.
|
|
112
|
+
- Research code (benchmark, replay, policies, studies and their audit
|
|
113
|
+
scripts) produces and reads schema `1.0` traces. Retained 1.x study outputs
|
|
114
|
+
under `output/` are unchanged.
|
|
115
|
+
|
|
3
116
|
## 1.2.0 - 19 October 2026
|
|
4
117
|
|
|
5
118
|
Additive only: the 1.x API and trace schema `0.1` are unchanged.
|
|
@@ -33,6 +146,11 @@ Additive only: the 1.x API and trace schema `0.1` are unchanged.
|
|
|
33
146
|
- The website's workflow cards, documentation and quickstart show the capture
|
|
34
147
|
API. `scripts/check_installed_release.py` now also exercises the recorder,
|
|
35
148
|
tool capture and record verifier from the installed wheel.
|
|
149
|
+
- Published to PyPI with registry hashes verified; see the
|
|
150
|
+
[release record](output/release-1.2.0-2026-10-19/README.md). Installed checks
|
|
151
|
+
passed on Windows Python 3.11.9 and 3.12.10, on one Alpine Linux 3.24.2 QEMU
|
|
152
|
+
guest with Python 3.14.8 and from a fresh PyPI install. macOS has never been
|
|
153
|
+
tested.
|
|
36
154
|
|
|
37
155
|
## 1.1.1 - 18 October 2026
|
|
38
156
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: consequa-x
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: Evidence-aware explanation of consequential agent actions
|
|
5
5
|
Author: Devrajsinh Jhala
|
|
6
6
|
License-Expression: MIT
|
|
@@ -76,98 +76,103 @@ evaluation only; never pass it to an explainer.
|
|
|
76
76
|
|
|
77
77
|
## Use it in Python
|
|
78
78
|
|
|
79
|
-
Register
|
|
80
|
-
|
|
79
|
+
Register each consequential action with its intended outcome before running it,
|
|
80
|
+
let the recorder capture what happens, read the outcome back from a trusted
|
|
81
|
+
read-only source, then verify and explain:
|
|
81
82
|
|
|
82
83
|
```python
|
|
83
84
|
from consequa_x import (
|
|
84
|
-
|
|
85
|
-
Trace, explain, render_report, verify,
|
|
85
|
+
Observation, OutcomeContract, RecordVerifier, TraceRecorder, explain, render_report,
|
|
86
86
|
)
|
|
87
87
|
|
|
88
|
-
expected = {"payment_id": "p1", "amount_minor": 1000, "currency": "INR"}
|
|
89
|
-
contract = OutcomeContract("contract-1", "refund_processed", expected,
|
|
90
|
-
deadline_ms=50, stability_ms=20)
|
|
91
|
-
action = Action("refund-1", "trace-1", "agent", "refund", expected, 0, contract)
|
|
92
|
-
|
|
93
|
-
# In an application, capture this independently from a trusted read-only source.
|
|
94
|
-
observation = Observation(
|
|
95
|
-
"readback-1", "independent-ledger", 100, 100, {"payment_id": "p1"},
|
|
96
|
-
({**expected, "effect_id": "effect-1", "committed_at_ms": 25,
|
|
97
|
-
"status": "processed", "action_id": "refund-1", "actor": "agent"},),
|
|
98
|
-
)
|
|
99
|
-
receipt = verify(action, observation)
|
|
100
|
-
trace = Trace("trace-1", action, (), (),
|
|
101
|
-
AgentAssessment(AssessmentStatus.FAILURE, 10),
|
|
102
|
-
(observation,), (receipt,))
|
|
103
|
-
|
|
104
|
-
assert receipt.status.value == "satisfied" # the refund really happened
|
|
105
|
-
assert receipt.origin.value == "confirmed" # and this action produced it
|
|
106
|
-
assert explain(trace).assessment_alignment == "contradicted" # the agent said failure
|
|
107
|
-
html = render_report(trace) # offline, minimal disclosure
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
The built-in `refund_processed` verifier checks payment, integer amount,
|
|
111
|
-
currency, exact count, commit deadline and a persistence window. Unavailable,
|
|
112
|
-
incomplete, wrongly scoped or stale readback produces `unknown`. Effect origin is
|
|
113
|
-
a separate conclusion: `confirmed`, `other_actor` or `unknown`.
|
|
114
|
-
|
|
115
|
-
Traces round-trip through a portable, versioned JSON schema (`0.1`):
|
|
116
|
-
`Trace.from_json(trace.to_json())` rejects unknown fields, broken identity links
|
|
117
|
-
and dependency cycles. `consequa_x.schema.get_trace_schema()` returns the bundled
|
|
118
|
-
JSON Schema.
|
|
119
|
-
|
|
120
|
-
## Capture a real agent's tool call
|
|
121
|
-
|
|
122
|
-
`TraceRecorder` records an action while your agent runs, and `RecordVerifier`
|
|
123
|
-
checks any outcome that leaves records behind (rows, orders, tickets, files):
|
|
124
|
-
|
|
125
|
-
```python
|
|
126
|
-
from consequa_x import OutcomeContract, RecordVerifier, TraceRecorder, explain
|
|
127
|
-
|
|
128
|
-
contract = OutcomeContract("refund-o-17", "record_present",
|
|
129
|
-
{"order_id": "o-17", "amount_minor": 5000, "currency": "INR"},
|
|
130
|
-
deadline_ms=200, stability_ms=50)
|
|
131
88
|
verifier = RecordVerifier(scope_fields=("order_id",))
|
|
89
|
+
rec = TraceRecorder("run-17", actor="support-agent", time_base="relative_ms")
|
|
90
|
+
refund = rec.register(
|
|
91
|
+
"refund-o-17", "issue_refund", {"order_id": "o-17"}, at_ms=0,
|
|
92
|
+
contract=OutcomeContract(contract_id="refund-o-17", predicate="record_present",
|
|
93
|
+
expected={"order_id": "o-17", "amount_minor": 5000},
|
|
94
|
+
deadline_ms=200, stability_ms=50))
|
|
132
95
|
|
|
133
|
-
rec = TraceRecorder("run-17", actor="support-agent")
|
|
134
|
-
rec.register("refund-o-17", "issue_refund", {"order_id": "o-17"}, contract=contract)
|
|
135
96
|
try:
|
|
136
|
-
with
|
|
137
|
-
|
|
138
|
-
|
|
97
|
+
with refund.attempt(at_ms=5) as attempt: # your tool call goes here
|
|
98
|
+
attempt.at_ms = 30
|
|
99
|
+
raise TimeoutError # ...and it timed out
|
|
139
100
|
except TimeoutError:
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
101
|
+
refund.assessment("failure", at_ms=31) # what the agent reported
|
|
102
|
+
|
|
103
|
+
# Captured independently, after the horizon, from a read-only replica of the orders table.
|
|
104
|
+
readback = Observation(
|
|
105
|
+
observation_id="read-1", source="orders-replica", observed_at_ms=300, as_of_ms=300,
|
|
106
|
+
scope={"order_id": "o-17"},
|
|
107
|
+
records=({"effect_id": "rf-1", "order_id": "o-17", "amount_minor": 5000,
|
|
108
|
+
"committed_at_ms": 20, "action_id": "refund-o-17",
|
|
109
|
+
"attempt_id": "refund-o-17:attempt-1", "actor": "support-agent"},))
|
|
110
|
+
receipt = refund.verify(readback, verifier=verifier)
|
|
111
|
+
|
|
112
|
+
result = explain(rec.trace()).for_action("refund-o-17")
|
|
113
|
+
assert receipt.status.value == "satisfied" # the refund really happened
|
|
114
|
+
assert receipt.origin.value == "confirmed" # and this action produced it
|
|
115
|
+
assert result.assessment_alignment == "contradicted" # the agent said failure
|
|
116
|
+
print(result.codes) # ('ASSESSMENT_DIVERGENCE', 'ACKNOWLEDGEMENT_EFFECT_DIVERGENCE')
|
|
117
|
+
html = render_report(rec.trace()) # offline, minimal disclosure
|
|
143
118
|
```
|
|
144
119
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
120
|
+
A run can register several actions; each `register` returns that action's
|
|
121
|
+
`ActionCapture`, and its attempts, assessments and verifications stay separate.
|
|
122
|
+
`capture_tool` decorates a tool (synchronous or `async def`) so every call is
|
|
123
|
+
recorded. `poll_readback` re-reads a lagging source until the outcome is known,
|
|
124
|
+
and `retry_advice` turns the receipt into a retry decision.
|
|
125
|
+
|
|
126
|
+
The built-in verifiers are `RecordVerifier` (rows, orders, tickets, files:
|
|
127
|
+
`record_present`) and `RefundVerifier` (`refund_processed`). Both check values,
|
|
128
|
+
count, commit deadline and persistence; unavailable, incomplete, wrongly scoped or
|
|
129
|
+
stale readback produces `unknown`. Effect origin is a separate conclusion:
|
|
130
|
+
`confirmed`, `other_actor` or `unknown`. Verifiers also record which effects match
|
|
131
|
+
the target and domain findings (excess, duplicate, mismatched, reversed or
|
|
132
|
+
removed effects); `explain` reads those receipts without any domain logic of its
|
|
133
|
+
own.
|
|
134
|
+
|
|
135
|
+
The [agent-loop example](https://github.com/Devrajsinh-Jhala/consequa-x/blob/main/examples/agent_loop_sqlite.py)
|
|
136
|
+
runs this end to end against a real SQLite database, offline, in three modes: a
|
|
137
|
+
timeout after the refund committed, a refund made by someone else, and a readback
|
|
138
|
+
too stale to decide. The
|
|
139
|
+
[framework guide](https://github.com/Devrajsinh-Jhala/consequa-x/blob/main/docs/framework-integration.md)
|
|
140
|
+
shows where the calls go in OpenAI Agents SDK, LangChain, Claude Agent SDK and MCP
|
|
141
|
+
tool loops.
|
|
142
|
+
|
|
143
|
+
Traces round-trip through a portable, versioned JSON schema (`1.0`):
|
|
144
|
+
`Trace.from_json(trace.to_json())` rejects unknown fields, broken identity links
|
|
145
|
+
and dependency cycles, and every captured payload is read-only.
|
|
151
146
|
|
|
152
147
|
## Bring your own domain
|
|
153
148
|
|
|
154
|
-
|
|
155
|
-
|
|
149
|
+
Write a read-only `Verifier` for your predicate. It returns a
|
|
150
|
+
`VerificationResult` with the state, origin and the effects it saw; to let the
|
|
151
|
+
agent's report be judged, it also records `target_effect_ids` (this action's
|
|
152
|
+
effects that match the full target):
|
|
156
153
|
|
|
157
154
|
```python
|
|
158
155
|
receipt = verify(action, observation, verifier=MyVerifier())
|
|
159
|
-
explanation = explain(trace, target_matcher=MyTargetMatcher())
|
|
160
156
|
```
|
|
161
157
|
|
|
162
158
|
Your application owns source trust, scope, completeness, timing and provenance;
|
|
163
|
-
Consequa-X checks that receipts bind to the supplied contract and
|
|
164
|
-
and keeps the evidence structured. The
|
|
159
|
+
Consequa-X checks that receipts bind to the supplied action, contract and
|
|
160
|
+
observation, and keeps the evidence structured. The
|
|
165
161
|
[artifact-delivery example](https://github.com/Devrajsinh-Jhala/consequa-x/blob/main/examples/artifact_delivery.py)
|
|
166
|
-
implements
|
|
162
|
+
implements a verifier with public APIs only, and the
|
|
167
163
|
[integration guide](https://github.com/Devrajsinh-Jhala/consequa-x/blob/main/docs/application-integration.md)
|
|
168
164
|
describes the boundary in detail. The
|
|
169
165
|
[stable API](https://github.com/Devrajsinh-Jhala/consequa-x/blob/main/docs/stable-api.md)
|
|
170
|
-
page lists what version
|
|
166
|
+
page lists what version 2 guarantees.
|
|
167
|
+
|
|
168
|
+
## Upgrading from 1.x
|
|
169
|
+
|
|
170
|
+
Version 2.0 changes the trace schema to `1.0` (several actions per trace, a
|
|
171
|
+
declared time base, keyword-only and read-only records) and moves domain
|
|
172
|
+
interpretation into verifiers. Convert saved 1.x traces with
|
|
173
|
+
`consequa-x migrate OLD.json --output NEW.json` or `migrate_trace()`. The
|
|
174
|
+
[migration guide](https://github.com/Devrajsinh-Jhala/consequa-x/blob/main/docs/migrating-to-2.0.md)
|
|
175
|
+
lists every change and its replacement.
|
|
171
176
|
|
|
172
177
|
## Command line
|
|
173
178
|
|
|
@@ -175,12 +180,17 @@ page lists what version 1 guarantees.
|
|
|
175
180
|
| --- | --- |
|
|
176
181
|
| `consequa-x demo --output DIR` | Write the twelve synthetic refund scenarios: traces, explanations, schema and manifest |
|
|
177
182
|
| `consequa-x explain TRACE [--output FILE]` | Explain an existing trace without replay; prints JSON or writes a new file |
|
|
178
|
-
| `consequa-x report TRACE --output FILE` | Render a self-contained HTML report;
|
|
183
|
+
| `consequa-x report TRACE --output FILE` | Render a self-contained HTML report; `--include-details` embeds the full capture, `--redact KEY` blanks named keys in it |
|
|
184
|
+
| `consequa-x summarize PATH... [--format markdown]` | Count outcomes, alignment and divergences across trace files, folders and `.jsonl` stores |
|
|
185
|
+
| `consequa-x compare A B` | Compare two traces action by action |
|
|
186
|
+
| `consequa-x verify TRACE --readback OBS --output NEW` | Verify a captured readback file with a built-in verifier |
|
|
187
|
+
| `consequa-x validate TRACE...` / `consequa-x migrate OLD --output NEW` | Check traces; convert schema `0.1` traces |
|
|
179
188
|
| `consequa-x experiment …` and research commands | Paired replay, decision attribution and calibration studies (see Research) |
|
|
180
189
|
|
|
181
190
|
## What it does not do
|
|
182
191
|
|
|
183
192
|
- It does not watch or control a live agent; your application captures the records.
|
|
193
|
+
`retry_advice` is advice derived from captured evidence, not a guarantee.
|
|
184
194
|
- It does not authenticate a readback source or prove that provider metadata is true.
|
|
185
195
|
- An evidence-graph link records provenance, not causal necessity.
|
|
186
196
|
- Default reports omit captured strings and identifiers, but keep times, counts
|
|
@@ -189,8 +199,8 @@ page lists what version 1 guarantees.
|
|
|
189
199
|
|
|
190
200
|
## Research
|
|
191
201
|
|
|
192
|
-
The repository also contains declared research interfaces,
|
|
193
|
-
|
|
202
|
+
The repository also contains declared research interfaces, imported from
|
|
203
|
+
`consequa_x.research`: isolated replay, contrastive and Shapley-style decision attribution,
|
|
194
204
|
calibration studies, an optional local Ollama adapter, and the retained evidence
|
|
195
205
|
for each study. Results so far are synthetic or exploratory local-model studies
|
|
196
206
|
and are reported with their denominators and limits. Start with the
|
|
@@ -49,98 +49,103 @@ evaluation only; never pass it to an explainer.
|
|
|
49
49
|
|
|
50
50
|
## Use it in Python
|
|
51
51
|
|
|
52
|
-
Register
|
|
53
|
-
|
|
52
|
+
Register each consequential action with its intended outcome before running it,
|
|
53
|
+
let the recorder capture what happens, read the outcome back from a trusted
|
|
54
|
+
read-only source, then verify and explain:
|
|
54
55
|
|
|
55
56
|
```python
|
|
56
57
|
from consequa_x import (
|
|
57
|
-
|
|
58
|
-
Trace, explain, render_report, verify,
|
|
58
|
+
Observation, OutcomeContract, RecordVerifier, TraceRecorder, explain, render_report,
|
|
59
59
|
)
|
|
60
60
|
|
|
61
|
-
expected = {"payment_id": "p1", "amount_minor": 1000, "currency": "INR"}
|
|
62
|
-
contract = OutcomeContract("contract-1", "refund_processed", expected,
|
|
63
|
-
deadline_ms=50, stability_ms=20)
|
|
64
|
-
action = Action("refund-1", "trace-1", "agent", "refund", expected, 0, contract)
|
|
65
|
-
|
|
66
|
-
# In an application, capture this independently from a trusted read-only source.
|
|
67
|
-
observation = Observation(
|
|
68
|
-
"readback-1", "independent-ledger", 100, 100, {"payment_id": "p1"},
|
|
69
|
-
({**expected, "effect_id": "effect-1", "committed_at_ms": 25,
|
|
70
|
-
"status": "processed", "action_id": "refund-1", "actor": "agent"},),
|
|
71
|
-
)
|
|
72
|
-
receipt = verify(action, observation)
|
|
73
|
-
trace = Trace("trace-1", action, (), (),
|
|
74
|
-
AgentAssessment(AssessmentStatus.FAILURE, 10),
|
|
75
|
-
(observation,), (receipt,))
|
|
76
|
-
|
|
77
|
-
assert receipt.status.value == "satisfied" # the refund really happened
|
|
78
|
-
assert receipt.origin.value == "confirmed" # and this action produced it
|
|
79
|
-
assert explain(trace).assessment_alignment == "contradicted" # the agent said failure
|
|
80
|
-
html = render_report(trace) # offline, minimal disclosure
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
The built-in `refund_processed` verifier checks payment, integer amount,
|
|
84
|
-
currency, exact count, commit deadline and a persistence window. Unavailable,
|
|
85
|
-
incomplete, wrongly scoped or stale readback produces `unknown`. Effect origin is
|
|
86
|
-
a separate conclusion: `confirmed`, `other_actor` or `unknown`.
|
|
87
|
-
|
|
88
|
-
Traces round-trip through a portable, versioned JSON schema (`0.1`):
|
|
89
|
-
`Trace.from_json(trace.to_json())` rejects unknown fields, broken identity links
|
|
90
|
-
and dependency cycles. `consequa_x.schema.get_trace_schema()` returns the bundled
|
|
91
|
-
JSON Schema.
|
|
92
|
-
|
|
93
|
-
## Capture a real agent's tool call
|
|
94
|
-
|
|
95
|
-
`TraceRecorder` records an action while your agent runs, and `RecordVerifier`
|
|
96
|
-
checks any outcome that leaves records behind (rows, orders, tickets, files):
|
|
97
|
-
|
|
98
|
-
```python
|
|
99
|
-
from consequa_x import OutcomeContract, RecordVerifier, TraceRecorder, explain
|
|
100
|
-
|
|
101
|
-
contract = OutcomeContract("refund-o-17", "record_present",
|
|
102
|
-
{"order_id": "o-17", "amount_minor": 5000, "currency": "INR"},
|
|
103
|
-
deadline_ms=200, stability_ms=50)
|
|
104
61
|
verifier = RecordVerifier(scope_fields=("order_id",))
|
|
62
|
+
rec = TraceRecorder("run-17", actor="support-agent", time_base="relative_ms")
|
|
63
|
+
refund = rec.register(
|
|
64
|
+
"refund-o-17", "issue_refund", {"order_id": "o-17"}, at_ms=0,
|
|
65
|
+
contract=OutcomeContract(contract_id="refund-o-17", predicate="record_present",
|
|
66
|
+
expected={"order_id": "o-17", "amount_minor": 5000},
|
|
67
|
+
deadline_ms=200, stability_ms=50))
|
|
105
68
|
|
|
106
|
-
rec = TraceRecorder("run-17", actor="support-agent")
|
|
107
|
-
rec.register("refund-o-17", "issue_refund", {"order_id": "o-17"}, contract=contract)
|
|
108
69
|
try:
|
|
109
|
-
with
|
|
110
|
-
|
|
111
|
-
|
|
70
|
+
with refund.attempt(at_ms=5) as attempt: # your tool call goes here
|
|
71
|
+
attempt.at_ms = 30
|
|
72
|
+
raise TimeoutError # ...and it timed out
|
|
112
73
|
except TimeoutError:
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
74
|
+
refund.assessment("failure", at_ms=31) # what the agent reported
|
|
75
|
+
|
|
76
|
+
# Captured independently, after the horizon, from a read-only replica of the orders table.
|
|
77
|
+
readback = Observation(
|
|
78
|
+
observation_id="read-1", source="orders-replica", observed_at_ms=300, as_of_ms=300,
|
|
79
|
+
scope={"order_id": "o-17"},
|
|
80
|
+
records=({"effect_id": "rf-1", "order_id": "o-17", "amount_minor": 5000,
|
|
81
|
+
"committed_at_ms": 20, "action_id": "refund-o-17",
|
|
82
|
+
"attempt_id": "refund-o-17:attempt-1", "actor": "support-agent"},))
|
|
83
|
+
receipt = refund.verify(readback, verifier=verifier)
|
|
84
|
+
|
|
85
|
+
result = explain(rec.trace()).for_action("refund-o-17")
|
|
86
|
+
assert receipt.status.value == "satisfied" # the refund really happened
|
|
87
|
+
assert receipt.origin.value == "confirmed" # and this action produced it
|
|
88
|
+
assert result.assessment_alignment == "contradicted" # the agent said failure
|
|
89
|
+
print(result.codes) # ('ASSESSMENT_DIVERGENCE', 'ACKNOWLEDGEMENT_EFFECT_DIVERGENCE')
|
|
90
|
+
html = render_report(rec.trace()) # offline, minimal disclosure
|
|
116
91
|
```
|
|
117
92
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
93
|
+
A run can register several actions; each `register` returns that action's
|
|
94
|
+
`ActionCapture`, and its attempts, assessments and verifications stay separate.
|
|
95
|
+
`capture_tool` decorates a tool (synchronous or `async def`) so every call is
|
|
96
|
+
recorded. `poll_readback` re-reads a lagging source until the outcome is known,
|
|
97
|
+
and `retry_advice` turns the receipt into a retry decision.
|
|
98
|
+
|
|
99
|
+
The built-in verifiers are `RecordVerifier` (rows, orders, tickets, files:
|
|
100
|
+
`record_present`) and `RefundVerifier` (`refund_processed`). Both check values,
|
|
101
|
+
count, commit deadline and persistence; unavailable, incomplete, wrongly scoped or
|
|
102
|
+
stale readback produces `unknown`. Effect origin is a separate conclusion:
|
|
103
|
+
`confirmed`, `other_actor` or `unknown`. Verifiers also record which effects match
|
|
104
|
+
the target and domain findings (excess, duplicate, mismatched, reversed or
|
|
105
|
+
removed effects); `explain` reads those receipts without any domain logic of its
|
|
106
|
+
own.
|
|
107
|
+
|
|
108
|
+
The [agent-loop example](https://github.com/Devrajsinh-Jhala/consequa-x/blob/main/examples/agent_loop_sqlite.py)
|
|
109
|
+
runs this end to end against a real SQLite database, offline, in three modes: a
|
|
110
|
+
timeout after the refund committed, a refund made by someone else, and a readback
|
|
111
|
+
too stale to decide. The
|
|
112
|
+
[framework guide](https://github.com/Devrajsinh-Jhala/consequa-x/blob/main/docs/framework-integration.md)
|
|
113
|
+
shows where the calls go in OpenAI Agents SDK, LangChain, Claude Agent SDK and MCP
|
|
114
|
+
tool loops.
|
|
115
|
+
|
|
116
|
+
Traces round-trip through a portable, versioned JSON schema (`1.0`):
|
|
117
|
+
`Trace.from_json(trace.to_json())` rejects unknown fields, broken identity links
|
|
118
|
+
and dependency cycles, and every captured payload is read-only.
|
|
124
119
|
|
|
125
120
|
## Bring your own domain
|
|
126
121
|
|
|
127
|
-
|
|
128
|
-
|
|
122
|
+
Write a read-only `Verifier` for your predicate. It returns a
|
|
123
|
+
`VerificationResult` with the state, origin and the effects it saw; to let the
|
|
124
|
+
agent's report be judged, it also records `target_effect_ids` (this action's
|
|
125
|
+
effects that match the full target):
|
|
129
126
|
|
|
130
127
|
```python
|
|
131
128
|
receipt = verify(action, observation, verifier=MyVerifier())
|
|
132
|
-
explanation = explain(trace, target_matcher=MyTargetMatcher())
|
|
133
129
|
```
|
|
134
130
|
|
|
135
131
|
Your application owns source trust, scope, completeness, timing and provenance;
|
|
136
|
-
Consequa-X checks that receipts bind to the supplied contract and
|
|
137
|
-
and keeps the evidence structured. The
|
|
132
|
+
Consequa-X checks that receipts bind to the supplied action, contract and
|
|
133
|
+
observation, and keeps the evidence structured. The
|
|
138
134
|
[artifact-delivery example](https://github.com/Devrajsinh-Jhala/consequa-x/blob/main/examples/artifact_delivery.py)
|
|
139
|
-
implements
|
|
135
|
+
implements a verifier with public APIs only, and the
|
|
140
136
|
[integration guide](https://github.com/Devrajsinh-Jhala/consequa-x/blob/main/docs/application-integration.md)
|
|
141
137
|
describes the boundary in detail. The
|
|
142
138
|
[stable API](https://github.com/Devrajsinh-Jhala/consequa-x/blob/main/docs/stable-api.md)
|
|
143
|
-
page lists what version
|
|
139
|
+
page lists what version 2 guarantees.
|
|
140
|
+
|
|
141
|
+
## Upgrading from 1.x
|
|
142
|
+
|
|
143
|
+
Version 2.0 changes the trace schema to `1.0` (several actions per trace, a
|
|
144
|
+
declared time base, keyword-only and read-only records) and moves domain
|
|
145
|
+
interpretation into verifiers. Convert saved 1.x traces with
|
|
146
|
+
`consequa-x migrate OLD.json --output NEW.json` or `migrate_trace()`. The
|
|
147
|
+
[migration guide](https://github.com/Devrajsinh-Jhala/consequa-x/blob/main/docs/migrating-to-2.0.md)
|
|
148
|
+
lists every change and its replacement.
|
|
144
149
|
|
|
145
150
|
## Command line
|
|
146
151
|
|
|
@@ -148,12 +153,17 @@ page lists what version 1 guarantees.
|
|
|
148
153
|
| --- | --- |
|
|
149
154
|
| `consequa-x demo --output DIR` | Write the twelve synthetic refund scenarios: traces, explanations, schema and manifest |
|
|
150
155
|
| `consequa-x explain TRACE [--output FILE]` | Explain an existing trace without replay; prints JSON or writes a new file |
|
|
151
|
-
| `consequa-x report TRACE --output FILE` | Render a self-contained HTML report;
|
|
156
|
+
| `consequa-x report TRACE --output FILE` | Render a self-contained HTML report; `--include-details` embeds the full capture, `--redact KEY` blanks named keys in it |
|
|
157
|
+
| `consequa-x summarize PATH... [--format markdown]` | Count outcomes, alignment and divergences across trace files, folders and `.jsonl` stores |
|
|
158
|
+
| `consequa-x compare A B` | Compare two traces action by action |
|
|
159
|
+
| `consequa-x verify TRACE --readback OBS --output NEW` | Verify a captured readback file with a built-in verifier |
|
|
160
|
+
| `consequa-x validate TRACE...` / `consequa-x migrate OLD --output NEW` | Check traces; convert schema `0.1` traces |
|
|
152
161
|
| `consequa-x experiment …` and research commands | Paired replay, decision attribution and calibration studies (see Research) |
|
|
153
162
|
|
|
154
163
|
## What it does not do
|
|
155
164
|
|
|
156
165
|
- It does not watch or control a live agent; your application captures the records.
|
|
166
|
+
`retry_advice` is advice derived from captured evidence, not a guarantee.
|
|
157
167
|
- It does not authenticate a readback source or prove that provider metadata is true.
|
|
158
168
|
- An evidence-graph link records provenance, not causal necessity.
|
|
159
169
|
- Default reports omit captured strings and identifiers, but keep times, counts
|
|
@@ -162,8 +172,8 @@ page lists what version 1 guarantees.
|
|
|
162
172
|
|
|
163
173
|
## Research
|
|
164
174
|
|
|
165
|
-
The repository also contains declared research interfaces,
|
|
166
|
-
|
|
175
|
+
The repository also contains declared research interfaces, imported from
|
|
176
|
+
`consequa_x.research`: isolated replay, contrastive and Shapley-style decision attribution,
|
|
167
177
|
calibration studies, an optional local Ollama adapter, and the retained evidence
|
|
168
178
|
for each study. Results so far are synthetic or exploratory local-model studies
|
|
169
179
|
and are reported with their denominators and limits. Start with the
|