arbiter-engine 0.2.3__tar.gz → 0.2.4__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.
Files changed (236) hide show
  1. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/CHANGELOG.md +42 -13
  2. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/CITATION.cff +1 -1
  3. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/PKG-INFO +1 -1
  4. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/mcp/server.py +32 -0
  5. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/pyproject.toml +1 -1
  6. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_declared_floor_is_checked_on_every_path.py +6 -5
  7. arbiter_engine-0.2.4/tests/test_every_declared_tool_has_a_wrapper.py +110 -0
  8. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/.gitattributes +0 -0
  9. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  10. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/.github/PUBLISH_FROM_CI +0 -0
  11. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  12. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/.github/workflows/release.yml +0 -0
  13. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/.github/workflows/tests.yml +0 -0
  14. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/.github/workflows/verify-published.yml +0 -0
  15. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/.github/workflows/verify-tag-artifact.yml +0 -0
  16. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/.gitignore +0 -0
  17. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/AI_ATTRIBUTION.md +0 -0
  18. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/AUTHORS.md +0 -0
  19. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/BRIDGES.md +0 -0
  20. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/CODE_OF_CONDUCT.md +0 -0
  21. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/COMPATIBILITY.md +0 -0
  22. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/CONTRIBUTING.md +0 -0
  23. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/LICENSE +0 -0
  24. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/MODELING.md +0 -0
  25. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/NOTICE +0 -0
  26. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/PRIVACY.md +0 -0
  27. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/README.md +0 -0
  28. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/ROADMAP.md +0 -0
  29. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/SECURITY.md +0 -0
  30. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/SUPPORT.md +0 -0
  31. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/TRADEMARK.md +0 -0
  32. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/__init__.py +0 -0
  33. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/api.py +0 -0
  34. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/axiom_thresholds.py +0 -0
  35. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/causal/__init__.py +0 -0
  36. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/causal/discovery.py +0 -0
  37. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/causal/granger.py +0 -0
  38. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/causal/leadlag.py +0 -0
  39. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/clock.py +0 -0
  40. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/derived/__init__.py +0 -0
  41. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/derived/indicator.py +0 -0
  42. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/derived/parser.py +0 -0
  43. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/envelope.py +0 -0
  44. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/examples/battery_pack.yaml +0 -0
  45. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/examples/factory_line.yaml +0 -0
  46. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/examples/kubernetes_node.yaml +0 -0
  47. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/examples/margin_book.yaml +0 -0
  48. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/examples/water_tank.yaml +0 -0
  49. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/fire_frequency.py +0 -0
  50. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/forecast/__init__.py +0 -0
  51. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/forecast/contract.py +0 -0
  52. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/forecast/envelope.py +0 -0
  53. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/forecast/ingest.py +0 -0
  54. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/forecast/monitor.py +0 -0
  55. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/forecast/shadow.py +0 -0
  56. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/history/__init__.py +0 -0
  57. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/history/calendar.py +0 -0
  58. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/history/observation.py +0 -0
  59. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/history/observation_production.py +0 -0
  60. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/history/observation_source_wiring.py +0 -0
  61. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/history/readiness.py +0 -0
  62. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/history/sqlite_store.py +0 -0
  63. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/inference/__init__.py +0 -0
  64. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/inference/causal.py +0 -0
  65. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/inference/runner.py +0 -0
  66. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/inference/ve.py +0 -0
  67. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/interfaces.py +0 -0
  68. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/mcp/__init__.py +0 -0
  69. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/ontology/__init__.py +0 -0
  70. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/ontology/axiom_verdicts_production.py +0 -0
  71. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/ontology/axioms/__init__.py +0 -0
  72. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/ontology/axioms/boundedness.py +0 -0
  73. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/ontology/axioms/connectivity.py +0 -0
  74. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/ontology/axioms/conservation.py +0 -0
  75. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/ontology/axioms/consistency.py +0 -0
  76. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/ontology/axioms/extensions.py +0 -0
  77. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/ontology/axioms/homeostasis.py +0 -0
  78. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/ontology/axioms/monotonicity.py +0 -0
  79. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/ontology/axioms/peers.py +0 -0
  80. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/ontology/axioms/responsiveness.py +0 -0
  81. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/ontology/axioms/roles.py +0 -0
  82. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/ontology/axioms/stability.py +0 -0
  83. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/ontology/domain_loader.py +0 -0
  84. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/ontology/entail.py +0 -0
  85. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/ontology/loader.py +0 -0
  86. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/ontology/prediction_production.py +0 -0
  87. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/ontology/reasoner.py +0 -0
  88. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/projection/__init__.py +0 -0
  89. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/projection/projector.py +0 -0
  90. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/projection/runner.py +0 -0
  91. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/propagation/__init__.py +0 -0
  92. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/propagation/impact_estimator.py +0 -0
  93. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/propagation/lp_confidence.py +0 -0
  94. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/propagation/mcts_root_cause.py +0 -0
  95. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/propagation/root_cause.py +0 -0
  96. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/propagation/weight_learner.py +0 -0
  97. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/rca/__init__.py +0 -0
  98. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/rca/greedy_set_cover.py +0 -0
  99. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/replay.py +0 -0
  100. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/residual/__init__.py +0 -0
  101. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/residual/predict_vs_mirror.py +0 -0
  102. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/residual/sqlite_ledger.py +0 -0
  103. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/schema/envelope.schema.json +0 -0
  104. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/scripts/__init__.py +0 -0
  105. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/scripts/benchmark_check.py +0 -0
  106. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/subenvelope.py +0 -0
  107. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/temporal/__init__.py +0 -0
  108. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/temporal/temporal_edge.py +0 -0
  109. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/temporal/trend_projection.py +0 -0
  110. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/twin/__init__.py +0 -0
  111. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/twin/action_clears_problem.py +0 -0
  112. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/twin/actions.py +0 -0
  113. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/twin/builder.py +0 -0
  114. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/twin/gap.py +0 -0
  115. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/twin/hypothesis_generator.py +0 -0
  116. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/twin/hypothesis_production.py +0 -0
  117. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/twin/kernel_pipeline_executor.py +0 -0
  118. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/twin/monte_carlo_predictor.py +0 -0
  119. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/twin/optimization_production.py +0 -0
  120. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/twin/pipeline_production.py +0 -0
  121. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/twin/planner.py +0 -0
  122. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/twin/rollout.py +0 -0
  123. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/twin/topology.py +0 -0
  124. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/twin/topology_optimizer.py +0 -0
  125. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/twin/transition_learner.py +0 -0
  126. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/twin/traverser.py +0 -0
  127. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/twin/traverser_production.py +0 -0
  128. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/arbiter_engine/types.py +0 -0
  129. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/evidence/README.md +0 -0
  130. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/evidence/alpha1_evidence_pack.md +0 -0
  131. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/evidence/customer_deployment_runbook.md +0 -0
  132. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/evidence/extended_fault_scenarios.md +0 -0
  133. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/evidence/l5_surprise_synthesis.md +0 -0
  134. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/evidence/observability_handoff_guide.md +0 -0
  135. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/evidence/tech_brief.md +0 -0
  136. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/evidence/use-case-catalogue.md +0 -0
  137. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/examples/battery_pack.yaml +0 -0
  138. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/examples/factory_line.yaml +0 -0
  139. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/examples/kubernetes_node.yaml +0 -0
  140. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/examples/margin_book.yaml +0 -0
  141. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/examples/water_tank.yaml +0 -0
  142. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/schema/envelope.schema.json +0 -0
  143. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/conftest.py +0 -0
  144. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_balance_may_cross_an_entity_boundary.py +0 -0
  145. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_bound_can_belong_to_one_instance.py +0 -0
  146. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_calibration_figure_names_its_population.py +0 -0
  147. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_check_that_cannot_run_says_so.py +0 -0
  148. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_check_that_declines_is_heard.py +0 -0
  149. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_checker_asks_no_entity_type.py +0 -0
  150. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_declared_bad_state_is_not_silent.py +0 -0
  151. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_declared_calendar_is_actually_read.py +0 -0
  152. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_declared_edge_reaches_the_published_surface.py +0 -0
  153. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_declared_gain_moves_the_downstream_value.py +0 -0
  154. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_declared_number_is_the_first_breach.py +0 -0
  155. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_derived_indicator_is_computed_not_fed.py +0 -0
  156. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_discipline_reports_its_own_denominator.py +0 -0
  157. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_dropped_declaration_is_not_silent.py +0 -0
  158. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_filed_source_says_who_is_not_a_producer.py +0 -0
  159. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_forecast_batch_is_filed_or_accounted_for.py +0 -0
  160. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_forecast_check_that_refused_says_so_out_loud.py +0 -0
  161. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_forecast_is_measured_against_a_random_walk.py +0 -0
  162. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_forecast_is_scored_not_just_stored.py +0 -0
  163. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_forecast_states_its_own_distribution.py +0 -0
  164. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_forecast_widens_and_says_what_it_assumed.py +0 -0
  165. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_forecaster_is_judged_by_the_same_eight_axioms.py +0 -0
  166. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_freeze_is_found_inside_its_window.py +0 -0
  167. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_latency_without_a_threshold_says_so.py +0 -0
  168. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_lead_lag_p_value_means_what_it_says.py +0 -0
  169. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_learned_gain_is_a_proposal.py +0 -0
  170. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_nested_block_is_checked_too.py +0 -0
  171. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_per_instance_bound_reaches_every_reader.py +0 -0
  172. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_plan_ranks_only_when_told_how.py +0 -0
  173. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_posterior_is_arithmetic_not_assumption.py +0 -0
  174. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_prediction_ledger_outlives_the_process.py +0 -0
  175. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_projection_declines_rather_than_guessing.py +0 -0
  176. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_reading_can_be_impossible_without_being_extreme.py +0 -0
  177. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_rollout_steps_the_model_forward.py +0 -0
  178. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_set_aside_forecast_says_who_set_it_aside.py +0 -0
  179. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_starved_join_says_which_operand_starved.py +0 -0
  180. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_warning_is_a_finding_on_every_surface.py +0 -0
  181. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_window_cannot_see_past_the_frozen_clock.py +0 -0
  182. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_withdrawn_check_is_not_silent.py +0 -0
  183. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_a_zero_allowance_still_reports.py +0 -0
  184. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_absent_data_regressions.py +0 -0
  185. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_agreement_declines_what_it_used_to_guess.py +0 -0
  186. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_an_imagined_finding_is_not_a_live_one.py +0 -0
  187. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_an_undeclared_transition_projects_nothing.py +0 -0
  188. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_closed_reader.py +0 -0
  189. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_connectivity_required_property.py +0 -0
  190. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_conservation_absent_output.py +0 -0
  191. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_cross_signal_consistency.py +0 -0
  192. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_decline_contract.py +0 -0
  193. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_did_you_mean_is_case_insensitive.py +0 -0
  194. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_discovery_proposes_and_never_promotes.py +0 -0
  195. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_documented_paths_the_suite_never_ran.py +0 -0
  196. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_entailment_derives_and_refuses.py +0 -0
  197. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_envelope_schema.py +0 -0
  198. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_every_decline_reason_has_a_producer.py +0 -0
  199. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_every_forecast_gets_a_yardstick.py +0 -0
  200. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_every_reader_takes_the_same_history.py +0 -0
  201. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_every_shipped_example_actually_runs.py +0 -0
  202. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_every_simulation_decline_has_an_input.py +0 -0
  203. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_gated_cell_declines.py +0 -0
  204. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_history_outlives_the_process_and_the_weekend.py +0 -0
  205. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_homeostasis_setpoint.py +0 -0
  206. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_lower_bounds.py +0 -0
  207. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_mcp_feeders.py +0 -0
  208. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_mcp_roundtrip.py +0 -0
  209. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_monotonicity_reversals.py +0 -0
  210. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_no_axiom_retires_a_check.py +0 -0
  211. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_no_cell_is_judged_twice.py +0 -0
  212. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_no_identifier_names_a_private_record.py +0 -0
  213. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_one_set_of_names_the_model_reads.py +0 -0
  214. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_role_comes_from_the_model.py +0 -0
  215. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_slow_oscillation.py +0 -0
  216. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_the_axioms_run_over_the_forecast_itself.py +0 -0
  217. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_the_clock_can_be_moved.py +0 -0
  218. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_the_config_blocks_are_documented.py +0 -0
  219. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_the_documented_priorities_are_the_computed_ones.py +0 -0
  220. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_the_engine_invents_no_indicators.py +0 -0
  221. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_the_engines_own_forecast_is_not_a_producers.py +0 -0
  222. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_the_envelope_legs_are_documented.py +0 -0
  223. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_the_forecasts_leg_says_how_many_were_expected.py +0 -0
  224. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_the_indicator_keys_are_documented.py +0 -0
  225. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_the_legal_files_ship_together.py +0 -0
  226. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_the_question_ranking_is_one_scale.py +0 -0
  227. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_the_rate_arm_declines_what_it_used_to_guess.py +0 -0
  228. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_the_readme_decline_count_is_derived.py +0 -0
  229. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_the_readme_name_count_is_derived.py +0 -0
  230. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_the_rename_table_names_real_things.py +0 -0
  231. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_the_sample_floor_says_whether_it_is_reachable.py +0 -0
  232. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_the_session_keeps_its_own_ledger.py +0 -0
  233. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_threshold_overrides.py +0 -0
  234. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_timestamped_ingestion.py +0 -0
  235. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_traverse_vocabularies.py +0 -0
  236. {arbiter_engine-0.2.3 → arbiter_engine-0.2.4}/tests/test_unread_properties.py +0 -0
@@ -24,14 +24,40 @@ Nothing yet.
24
24
 
25
25
  ---
26
26
 
27
+ ## [0.2.4] — 2026-09-18
28
+
29
+ ### Fixed
30
+
31
+ - **The MCP server raised at construction whenever the SDK was installed.**
32
+ `rollout` and `plan` were added to `TOOL_SPECS` and to `_HANDLERS` in 0.2.3
33
+ and not to the wrapper table, so `build_server()` hit its own guard —
34
+ *TOOL_SPECS declares ['plan', 'rollout'] with no wrapper to register* — and
35
+ the `mcp` extra was unusable for the whole of 0.2.3. `dispatch` served both
36
+ verbs correctly the entire time; only the transport could not.
37
+
38
+ **The guard was right and fired too late.** Constructing a server needs the
39
+ optional SDK, so the only lane that could reach it was the one installing the
40
+ extra: every other lane skipped the transport test and reported green. 0.2.3
41
+ was verified locally at 1660 passed / 14 skipped and was red in CI at 1668
42
+ passed / 5 skipped. The skip COUNT was the only available signal and nothing
43
+ compares it across lanes.
44
+
45
+ `test_every_declared_tool_has_a_wrapper.py` now reads the wrapper table with
46
+ the AST instead of importing it, so a declared tool with no wrapper fails on
47
+ EVERY lane without the SDK present. Installing the extra everywhere would
48
+ have made an optional dependency required in all but name, which is the
49
+ measured two-dependency claim this package keeps.
50
+
51
+ ---
52
+
27
53
  ## [0.2.3] — 2026-09-18
28
54
 
29
55
  **The first MINOR, and it is not numbered 0.2.0.** `arbiter-engine` stayed on
30
56
  `0.1.x` by decision through eighteen patch releases; `rollout` and `plan` are
31
57
  new verbs on `api`, and COMPATIBILITY.md has always said that is a minor.
32
58
 
33
- **0.2.0 AND 0.2.1 were both skipped because both are unavailable**, not because
34
- anything was wrong with either — see
59
+ **0.2.0, 0.2.1, 0.2.2 and 0.3.0 were all skipped because all four are
60
+ unavailable**, not because anything was wrong with any of them — see
35
61
  [Version numbers that do not exist](#version-numbers-that-do-not-exist). PyPI
36
62
  permanently reserves any filename it has ever served and had deleted, including
37
63
  under an earlier owner of the name, so an upload returns `400 This filename was
@@ -40,10 +66,12 @@ sequence runs 0.1.1 to 0.1.4.
40
66
 
41
67
  That section predicted this release and named the wrong number: it said *the
42
68
  version that first breaks compatibility cannot BE 0.2.0. so it will be
43
- 0.2.1.* 0.2.1 was an INFERENCE from three measured numbers, and it was wrong.
44
- An upload is the only oracle — a 404 does not mean a filename is free — so the
45
- prediction could not have been checked when it was written, and it is corrected
46
- here by having been run.
69
+ 0.2.1.* 0.2.1 was an INFERENCE from three measured numbers, and it was wrong —
70
+ as were 0.2.2 and 0.3.0 after it. Three uploads were refused before one landed,
71
+ and the reserved set turned out NOT to be contiguous: 0.3.0 is taken and 0.2.3
72
+ was free. An upload is the only oracle — a 404 does not mean a filename is
73
+ free — so no amount of reading could have ordered these, and nothing shorter
74
+ than trying them would have found it.
47
75
 
48
76
  Every consumer pinning `<0.2` must move its ceiling to `<0.3` to see this —
49
77
  that is the ceiling doing its job, not breaking.
@@ -2229,16 +2257,17 @@ topology traversal, an MCP transport, a YAML domain-model loader; `numpy` and
2229
2257
 
2230
2258
  ## Version numbers that do not exist
2231
2259
 
2232
- **0.1.2, 0.1.3, 0.2.0 and 0.2.1 are permanently unavailable** and were never
2233
- published by this project. PyPI reserves any filename that has ever been used and
2260
+ **0.1.2, 0.1.3, 0.2.0, 0.2.1, 0.2.2 and 0.3.0 are permanently unavailable** and
2261
+ were never published by this project. The set is NOT a contiguous range and
2262
+ cannot be extrapolated: 0.2.3 was free while 0.3.0 was not. PyPI reserves any filename that has ever been used and
2234
2263
  deleted, including from an earlier owner of the name, so an upload under those
2235
2264
  numbers returns `400 This filename was previously used by a file that has since
2236
- been deleted`. The sequence runs 0.1.1 to 0.1.4, and 0.1.18 to 0.2.2, for that
2265
+ been deleted`. The sequence runs 0.1.1 to 0.1.4, and 0.1.18 to 0.2.3, for that
2237
2266
  reason and no other.
2238
2267
 
2239
- **0.2.1 was added to this list by trying it**, and that is the point worth
2240
- keeping. Until 2026-09-18 this paragraph named three numbers and then predicted a
2241
- fourth: *the version that first breaks compatibility cannot BE 0.2.0 — the number
2268
+ **0.2.1, 0.2.2 and 0.3.0 were added to this list by trying them**, and that is
2269
+ the point worth keeping. Until 2026-09-18 this paragraph named three numbers and
2270
+ then predicted a fourth: *the version that first breaks compatibility cannot BE 0.2.0 — the number
2242
2271
  is unavailable — so it will be 0.2.1.* The three were measured; the fourth was an
2243
2272
  inference from them, and the release that needed it found it false at the upload.
2244
2273
 
@@ -2246,7 +2275,7 @@ inference from them, and the release that needed it found it false at the upload
2246
2275
  free, the JSON and `/simple/` surfaces list only what is live, and a deleted
2247
2276
  release leaves no trace either serves. So a number in this list was measured and a
2248
2277
  number predicted from it was a guess wearing the same sentence — which is why the
2249
- prediction is gone rather than re-pointed at 0.2.2.
2278
+ prediction is gone rather than re-pointed at the next number.
2250
2279
 
2251
2280
  **This matters to anyone pinning `<0.2`.** That ceiling stops at 0.1.18 and does
2252
2281
  not resolve the 0.2 series at all. Move it to `<0.3` deliberately; a tool or a
@@ -9,7 +9,7 @@ authors:
9
9
  alias: "james-sheen"
10
10
  - name: "The Arbiter Project Authors"
11
11
  license: Apache-2.0
12
- version: "0.2.3"
12
+ version: "0.2.4"
13
13
  date-released: "2026-09-18"
14
14
  repository-code: "https://github.com/james-sheen/arbiter"
15
15
  url: "https://github.com/james-sheen/arbiter"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: arbiter-engine
3
- Version: 0.2.3
3
+ Version: 0.2.4
4
4
  Summary: A detection engine that reports what it did not check.
5
5
  Project-URL: Homepage, https://github.com/james-sheen/arbiter
6
6
  Project-URL: Source, https://github.com/james-sheen/arbiter
@@ -534,6 +534,29 @@ def build_server(session: EngineSession | None = None):
534
534
  "overrides": overrides,
535
535
  })
536
536
 
537
+ async def rollout_tool(
538
+ actions: List[Dict[str, Any]] | None = None,
539
+ horizon_s: float = 3600.0,
540
+ step_s: float = 300.0,
541
+ seed_mode: str = "current",
542
+ max_transitions: int = 100_000,
543
+ ) -> str:
544
+ return _emit("rollout", {
545
+ "actions": actions, "horizon_s": horizon_s, "step_s": step_s,
546
+ "seed_mode": seed_mode, "max_transitions": max_transitions,
547
+ })
548
+
549
+ async def plan_tool(
550
+ candidates: List[Dict[str, Any]] | None = None,
551
+ horizon_s: float = 3600.0,
552
+ step_s: float = 300.0,
553
+ max_transitions: int = 100_000,
554
+ ) -> str:
555
+ return _emit("plan", {
556
+ "candidates": candidates, "horizon_s": horizon_s,
557
+ "step_s": step_s, "max_transitions": max_transitions,
558
+ })
559
+
537
560
  async def gaps_tool(start_node: str | None = None) -> str:
538
561
  return _emit("gaps", {"start_node": start_node})
539
562
 
@@ -610,6 +633,15 @@ def build_server(session: EngineSession | None = None):
610
633
  "load_model": load_model_tool,
611
634
  "add_entity": add_entity_tool,
612
635
  "add_observations": add_observations_tool,
636
+ # The SAME omission the comment above records, made again by
637
+ # the world-model arc and caught by the same guard -- at construction,
638
+ # on the one lane that installs the `mcp` extra, AFTER 0.2.3 shipped.
639
+ # Every local lane skips the transport test because the SDK is absent,
640
+ # so 1660 local passes and 14 skips read as green while CI read 1668
641
+ # passes and 5 skips. The skip count is the tell, and nothing compares
642
+ # the two.
643
+ "rollout": rollout_tool,
644
+ "plan": plan_tool,
613
645
  }
614
646
  missing = {spec["name"] for spec in TOOL_SPECS} - set(wrappers)
615
647
  if missing:
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "arbiter-engine"
7
- version = "0.2.3"
7
+ version = "0.2.4"
8
8
  description = "A detection engine that reports what it did not check."
9
9
  requires-python = ">=3.10"
10
10
  license = "Apache-2.0"
@@ -34,11 +34,12 @@ def _examples_dir() -> pathlib.Path:
34
34
  """Whichever copy this tree has: the built package ships `examples/` at its
35
35
  root, the source tree keeps them under the publication docs.
36
36
 
37
- - this was a path assembled from the SOURCE repository's own name,
38
- which is two defects at once. It named a private tree in a file that ships,
39
- and it could only ever resolve in the tree it was written in, so the shipped
40
- copy of this test would have failed at import on a reader's machine. The
41
- resolver here is the one `test_every_shipped_example_actually_runs.py`
37
+ - this was a hard-coded path into a directory that does not exist
38
+ in the published package, so the shipped copy of this test could only ever
39
+ fail at import on a reader's machine. It was written where it happened to
40
+ resolve and nothing between there and the wheel disagreed.
41
+
42
+ The resolver here is the one `test_every_shipped_example_actually_runs.py`
42
43
  already uses; copying its shape rather than inventing a second one is the
43
44
  point, since two resolvers for one fact are what drift.
44
45
  """
@@ -0,0 +1,110 @@
1
+ """Every name in ``TOOL_SPECS`` has a wrapper, checked without the SDK.
2
+
3
+ THE GUARD THAT EXISTS ALREADY RUNS TOO LATE AND ON TOO FEW LANES.
4
+ `build_server()` raises `RuntimeError: TOOL_SPECS declares [...] with no wrapper
5
+ to register` at construction, which is the right behaviour and the right
6
+ message. But constructing the server needs the `mcp` SDK, so the only lane that
7
+ can reach it is the one installing the extra -- and every other lane SKIPS the
8
+ transport test and reports green.
9
+
10
+ That is not hypothetical. The four disciplines went in without wrappers once,
11
+ and `server.py` carries a comment about it. The world-model arc then did the
12
+ same thing with `rollout` and `plan`, and it shipped: 0.2.3 went to the index
13
+ with an MCP server that raised on construction for anyone who had the SDK
14
+ installed. Locally the suite was 1660 passed / 14 skipped; in CI it was 1668
15
+ passed / 5 skipped and red. The skip COUNT was the only local signal, and
16
+ nothing compares it across lanes.
17
+
18
+ SO THIS READS THE SOURCE INSTEAD OF IMPORTING IT. The wrapper table is a dict
19
+ literal inside `build_server`, so its keys are visible to the AST without the
20
+ function ever running and without the SDK being present. A name in `TOOL_SPECS`
21
+ and not in that dict fails here on EVERY lane, at collection speed.
22
+
23
+ WHY NOT JUST INSTALL THE SDK IN EVERY LANE. Because the dependency is optional
24
+ by decision -- the README's two-dependency claim is measured, and the transport
25
+ is behind an extra. A guard that requires the optional thing in order to check
26
+ the required thing has made it required in all but name.
27
+ """
28
+
29
+ from __future__ import annotations
30
+
31
+ import ast
32
+ import pathlib
33
+
34
+ import pytest
35
+
36
+ # DOTTED, and that is not a style choice. `build-engine.sh` rewrites absolute
37
+ # imports with a regex anchored on `arbiter_engine\.` -- a DOT is required --
38
+ # so `from arbiter_engine import arbiter_mcp` passes through unrewritten and
39
+ # the scrub then refuses the built tree for naming the source package. Measured:
40
+ # that exact line refused the 0.2.4 build.
41
+ from arbiter_engine.mcp import server as _server
42
+ from arbiter_engine.mcp.server import TOOL_SPECS
43
+
44
+ SERVER = pathlib.Path(_server.__file__)
45
+
46
+ #: The dict whose keys are the wrappers. Named here so a rename of the local
47
+ #: variable fails loudly rather than silently emptying this test.
48
+ WRAPPER_TABLE = "wrappers"
49
+
50
+
51
+ def _wrapper_names() -> set:
52
+ """Keys of the `wrappers = {...}` literal, read with the AST.
53
+
54
+ Assigned inside `build_server`, so the walk is over the whole module rather
55
+ than the module body -- and the assignment is found by TARGET NAME, not by
56
+ position, because a literal found by position is one an edit above it
57
+ silently redefines.
58
+ """
59
+ tree = ast.parse(SERVER.read_text(encoding="utf-8"))
60
+ for node in ast.walk(tree):
61
+ if not isinstance(node, ast.Assign) or not isinstance(node.value, ast.Dict):
62
+ continue
63
+ if not any(isinstance(t, ast.Name) and t.id == WRAPPER_TABLE
64
+ for t in node.targets):
65
+ continue
66
+ return {k.value for k in node.value.keys
67
+ if isinstance(k, ast.Constant) and isinstance(k.value, str)}
68
+ raise AssertionError(
69
+ f"no `{WRAPPER_TABLE} = {{...}}` dict literal in {SERVER.name}; this "
70
+ f"test reads that table and cannot see a renamed or restructured one")
71
+
72
+
73
+ def test_the_wrapper_table_is_readable():
74
+ """Guards the guard. A resolver that returned an empty set would make the
75
+ comparison below vacuously pass for a table that lost every entry."""
76
+ names = _wrapper_names()
77
+ assert len(names) >= 12, sorted(names)
78
+
79
+
80
+ def test_there_are_specs_to_check():
81
+ assert len(TOOL_SPECS) >= 12
82
+
83
+
84
+ def test_every_declared_tool_has_a_wrapper():
85
+ """The one that would have caught `rollout` and `plan` before the release."""
86
+ declared = {spec["name"] for spec in TOOL_SPECS}
87
+ missing = sorted(declared - _wrapper_names())
88
+ assert not missing, (
89
+ f"{missing} are in TOOL_SPECS with no entry in the wrapper table, so "
90
+ f"the server would advertise a tool it cannot serve and `build_server` "
91
+ f"would raise at construction -- but only on a lane that installs the "
92
+ f"`mcp` extra")
93
+
94
+
95
+ def test_no_wrapper_is_registered_for_an_undeclared_tool():
96
+ """The other direction. A wrapper with no spec is dead code that reads as
97
+ a served tool, and `build_server` iterates TOOL_SPECS so it would never be
98
+ registered at all."""
99
+ stray = sorted(_wrapper_names() - {spec["name"] for spec in TOOL_SPECS})
100
+ assert not stray, f"{stray} have wrappers and no TOOL_SPECS entry"
101
+
102
+
103
+ def test_the_two_new_verbs_are_among_them():
104
+ """Named explicitly, because a set-comparison test stays green if BOTH
105
+ sides lose a member together -- which is exactly how the pair went missing
106
+ from the dict while remaining in `_HANDLERS`."""
107
+ declared = {spec["name"] for spec in TOOL_SPECS}
108
+ for verb in ("rollout", "plan"):
109
+ assert verb in declared, f"{verb} left TOOL_SPECS"
110
+ assert verb in _wrapper_names(), f"{verb} has no wrapper"
File without changes
File without changes
File without changes