arbiter-engine 0.2.6__tar.gz → 0.2.8__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 (334) hide show
  1. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/.github/workflows/release.yml +26 -14
  2. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/CHANGELOG.md +75 -1
  3. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/CITATION.cff +2 -2
  4. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/MODELING.md +15 -2
  5. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/PKG-INFO +4 -4
  6. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/README.md +3 -3
  7. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/STANCE.md +22 -0
  8. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/api.py +114 -4
  9. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/assumptions.py +19 -1
  10. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/examples/water_tank.yaml +1 -1
  11. arbiter_engine-0.2.8/arbiter_engine/inference/hypothesis.py +203 -0
  12. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/inference/runner.py +79 -8
  13. arbiter_engine-0.2.8/arbiter_engine/producers/__init__.py +25 -0
  14. arbiter_engine-0.2.8/arbiter_engine/producers/baseline_learner.py +163 -0
  15. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/scripts/benchmark_check.py +1 -1
  16. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/surprises.py +100 -0
  17. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/transition_learner.py +7 -0
  18. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/traverser.py +1 -1
  19. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/evidence/alpha1_evidence_pack.md +2 -2
  20. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/evidence/l5_surprise_synthesis.md +3 -3
  21. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/examples/water_tank.yaml +1 -1
  22. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/pyproject.toml +1 -1
  23. arbiter_engine-0.2.8/tests/test_a_finding_says_where_to_look_next.py +160 -0
  24. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_forecaster_is_judged_by_the_same_eight_axioms.py +1 -1
  25. arbiter_engine-0.2.8/tests/test_a_posterior_says_which_reading_it_left_out.py +207 -0
  26. arbiter_engine-0.2.8/tests/test_a_proposal_says_what_adopting_it_would_have_caught.py +192 -0
  27. arbiter_engine-0.2.8/tests/test_a_vertical_may_adopt_and_this_engine_may_not.py +224 -0
  28. arbiter_engine-0.2.8/tests/test_the_alpha_figure_comes_from_the_record.py +108 -0
  29. arbiter_engine-0.2.8/tests/test_the_engine_ships_an_opponent_worth_beating.py +166 -0
  30. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_evidence_floor_is_declared_or_disclosed.py +23 -7
  31. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_stance_page_says_what_no_other_page_says.py +49 -49
  32. arbiter_engine-0.2.6/.github/PUBLISH_FROM_CI +0 -43
  33. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/.gitattributes +0 -0
  34. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  35. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  36. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/.github/workflows/tests.yml +0 -0
  37. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/.github/workflows/verify-published.yml +0 -0
  38. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/.github/workflows/verify-tag-artifact.yml +0 -0
  39. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/.gitignore +0 -0
  40. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/AI_ATTRIBUTION.md +0 -0
  41. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/AUTHORS.md +0 -0
  42. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/BRIDGES.md +0 -0
  43. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/CODE_OF_CONDUCT.md +0 -0
  44. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/COMPATIBILITY.md +0 -0
  45. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/CONTRIBUTING.md +0 -0
  46. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/LICENSE +0 -0
  47. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/NOTICE +0 -0
  48. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/PRIVACY.md +0 -0
  49. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/ROADMAP.md +0 -0
  50. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/SECURITY.md +0 -0
  51. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/SUPPORT.md +0 -0
  52. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/TRADEMARK.md +0 -0
  53. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/__init__.py +0 -0
  54. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/axiom_thresholds.py +0 -0
  55. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/causal/__init__.py +0 -0
  56. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/causal/discovery.py +0 -0
  57. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/causal/granger.py +0 -0
  58. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/causal/leadlag.py +0 -0
  59. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/clock.py +0 -0
  60. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/derived/__init__.py +0 -0
  61. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/derived/indicator.py +0 -0
  62. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/derived/parser.py +0 -0
  63. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/envelope.py +0 -0
  64. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/examples/battery_pack.yaml +0 -0
  65. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/examples/factory_line.yaml +0 -0
  66. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/examples/kubernetes_node.yaml +0 -0
  67. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/examples/margin_book.yaml +0 -0
  68. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/examples/pump_tank_dynamics.yaml +0 -0
  69. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/examples/pump_tank_planning.yaml +0 -0
  70. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/examples/substation_feeder.yaml +0 -0
  71. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/examples/substation_feeder_surprises.yaml +0 -0
  72. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/fire_frequency.py +0 -0
  73. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/forecast/__init__.py +0 -0
  74. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/forecast/contract.py +0 -0
  75. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/forecast/envelope.py +0 -0
  76. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/forecast/ingest.py +0 -0
  77. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/forecast/monitor.py +0 -0
  78. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/forecast/shadow.py +0 -0
  79. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/history/__init__.py +0 -0
  80. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/history/calendar.py +0 -0
  81. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/history/observation.py +0 -0
  82. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/history/observation_production.py +0 -0
  83. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/history/observation_source_wiring.py +0 -0
  84. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/history/readiness.py +0 -0
  85. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/history/sqlite_store.py +0 -0
  86. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/inference/__init__.py +0 -0
  87. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/inference/causal.py +0 -0
  88. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/inference/ve.py +0 -0
  89. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/interfaces.py +0 -0
  90. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/mcp/__init__.py +0 -0
  91. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/mcp/server.py +0 -0
  92. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/__init__.py +0 -0
  93. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axiom_verdicts_production.py +0 -0
  94. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axioms/__init__.py +0 -0
  95. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axioms/boundedness.py +0 -0
  96. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axioms/connectivity.py +0 -0
  97. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axioms/conservation.py +0 -0
  98. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axioms/consistency.py +0 -0
  99. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axioms/extensions.py +0 -0
  100. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axioms/homeostasis.py +0 -0
  101. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axioms/monotonicity.py +0 -0
  102. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axioms/peers.py +0 -0
  103. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axioms/responsiveness.py +0 -0
  104. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axioms/roles.py +0 -0
  105. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axioms/stability.py +0 -0
  106. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/domain_loader.py +0 -0
  107. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/entail.py +0 -0
  108. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/loader.py +0 -0
  109. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/prediction_production.py +0 -0
  110. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/reasoner.py +0 -0
  111. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/schemas/health_meta_ontology.ttl +0 -0
  112. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/projection/__init__.py +0 -0
  113. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/projection/projector.py +0 -0
  114. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/projection/runner.py +0 -0
  115. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/propagation/__init__.py +0 -0
  116. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/propagation/impact_estimator.py +0 -0
  117. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/propagation/lp_confidence.py +0 -0
  118. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/propagation/mcts_root_cause.py +0 -0
  119. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/propagation/root_cause.py +0 -0
  120. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/propagation/weight_learner.py +0 -0
  121. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/rca/__init__.py +0 -0
  122. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/rca/greedy_set_cover.py +0 -0
  123. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/replay.py +0 -0
  124. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/residual/__init__.py +0 -0
  125. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/residual/predict_vs_mirror.py +0 -0
  126. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/residual/sqlite_ledger.py +0 -0
  127. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/schema/envelope.schema.json +0 -0
  128. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/scripts/__init__.py +0 -0
  129. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/scripts/surprise_benchmark.py +0 -0
  130. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/subenvelope.py +0 -0
  131. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/temporal/__init__.py +0 -0
  132. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/temporal/temporal_edge.py +0 -0
  133. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/temporal/trend_projection.py +0 -0
  134. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/__init__.py +0 -0
  135. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/action_clears_problem.py +0 -0
  136. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/actions.py +0 -0
  137. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/builder.py +0 -0
  138. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/gap.py +0 -0
  139. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/hypothesis_generator.py +0 -0
  140. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/hypothesis_production.py +0 -0
  141. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/kernel_pipeline_executor.py +0 -0
  142. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/monte_carlo_predictor.py +0 -0
  143. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/optimization_production.py +0 -0
  144. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/pipeline_production.py +0 -0
  145. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/planner.py +0 -0
  146. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/rollout.py +0 -0
  147. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/topology.py +0 -0
  148. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/topology_optimizer.py +0 -0
  149. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/traverser_production.py +0 -0
  150. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/types.py +0 -0
  151. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/evidence/README.md +0 -0
  152. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/evidence/customer_deployment_runbook.md +0 -0
  153. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/evidence/extended_fault_scenarios.md +0 -0
  154. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/evidence/observability_handoff_guide.md +0 -0
  155. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/evidence/tech_brief.md +0 -0
  156. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/evidence/use-case-catalogue.md +0 -0
  157. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/examples/battery_pack.yaml +0 -0
  158. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/examples/factory_line.yaml +0 -0
  159. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/examples/kubernetes_node.yaml +0 -0
  160. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/examples/margin_book.yaml +0 -0
  161. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/examples/pump_tank_dynamics.yaml +0 -0
  162. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/examples/pump_tank_planning.yaml +0 -0
  163. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/examples/substation_feeder.yaml +0 -0
  164. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/examples/substation_feeder_surprises.yaml +0 -0
  165. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/schema/envelope.schema.json +0 -0
  166. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/conftest.py +0 -0
  167. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_balance_may_cross_an_entity_boundary.py +0 -0
  168. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_bound_can_belong_to_one_instance.py +0 -0
  169. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_calibration_figure_names_its_population.py +0 -0
  170. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_calibration_says_how_many_trajectories_it_saw.py +0 -0
  171. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_chain_of_lags_says_how_it_was_composed.py +0 -0
  172. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_changelog_section_says_whether_you_can_install_it.py +0 -0
  173. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_check_that_cannot_run_says_so.py +0 -0
  174. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_check_that_declines_is_heard.py +0 -0
  175. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_checker_asks_no_entity_type.py +0 -0
  176. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_clean_rollout_still_counts_what_it_evaluated.py +0 -0
  177. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_companion_beside_the_models_is_not_one.py +0 -0
  178. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_correct_gain_is_not_contradicted_by_a_lagged_series.py +0 -0
  179. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_coupling_block_is_checked_too.py +0 -0
  180. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_coupling_is_graded_on_its_own_projections.py +0 -0
  181. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_coupling_learns_how_its_projections_fared.py +0 -0
  182. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_declared_bad_state_is_not_silent.py +0 -0
  183. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_declared_calendar_is_actually_read.py +0 -0
  184. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_declared_edge_reaches_the_published_surface.py +0 -0
  185. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_declared_floor_is_checked_on_every_path.py +0 -0
  186. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_declared_gain_moves_the_downstream_value.py +0 -0
  187. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_declared_number_is_the_first_breach.py +0 -0
  188. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_declared_offset_waits_for_the_delay.py +0 -0
  189. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_declared_source_matches_the_guide.py +0 -0
  190. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_declared_spread_reaches_the_value.py +0 -0
  191. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_decline_states_the_number_it_computed.py +0 -0
  192. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_derived_indicator_is_computed_not_fed.py +0 -0
  193. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_discipline_reports_its_own_denominator.py +0 -0
  194. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_dropped_declaration_is_not_silent.py +0 -0
  195. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_filed_source_says_who_is_not_a_producer.py +0 -0
  196. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_forecast_batch_is_filed_or_accounted_for.py +0 -0
  197. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_forecast_check_that_refused_says_so_out_loud.py +0 -0
  198. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_forecast_is_graded_at_its_horizon.py +0 -0
  199. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_forecast_is_measured_against_a_random_walk.py +0 -0
  200. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_forecast_is_scored_not_just_stored.py +0 -0
  201. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_forecast_keeps_its_doubt.py +0 -0
  202. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_forecast_keeps_its_doubt_when_its_median_stands_still.py +0 -0
  203. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_forecast_states_its_own_distribution.py +0 -0
  204. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_forecast_widens_and_says_what_it_assumed.py +0 -0
  205. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_freeze_is_found_inside_its_window.py +0 -0
  206. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_latency_without_a_threshold_says_so.py +0 -0
  207. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_lazy_import_did_not_move_a_name.py +0 -0
  208. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_lead_lag_p_value_means_what_it_says.py +0 -0
  209. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_learned_gain_is_a_proposal.py +0 -0
  210. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_margin_is_measured_against_every_line.py +0 -0
  211. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_nested_block_is_checked_too.py +0 -0
  212. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_pair_can_beat_the_best_single_action.py +0 -0
  213. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_per_instance_bound_reaches_every_reader.py +0 -0
  214. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_plan_files_the_row_that_is_a_forecast.py +0 -0
  215. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_plan_ranks_only_when_told_how.py +0 -0
  216. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_posterior_is_arithmetic_not_assumption.py +0 -0
  217. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_prediction_ledger_outlives_the_process.py +0 -0
  218. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_projection_declines_rather_than_guessing.py +0 -0
  219. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_proposed_spread_says_what_it_assumed.py +0 -0
  220. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_ranking_says_how_close_the_call_was.py +0 -0
  221. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_reading_can_be_impossible_without_being_extreme.py +0 -0
  222. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_refused_block_says_which_rule_it_was_on.py +0 -0
  223. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_refused_coupling_is_a_question_not_a_silence.py +0 -0
  224. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_response_model_nobody_recognises_is_not_exponential.py +0 -0
  225. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_rollout_can_be_graded_later.py +0 -0
  226. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_rollout_carries_a_transient_past_the_action_step.py +0 -0
  227. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_rollout_steps_the_model_forward.py +0 -0
  228. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_second_action_on_a_moved_property_superposes.py +0 -0
  229. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_sentence_the_changelog_closed_is_gone.py +0 -0
  230. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_set_aside_forecast_says_who_set_it_aside.py +0 -0
  231. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_source_pinned_at_zero_passes_no_doubt_on.py +0 -0
  232. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_spread_nobody_declared_is_not_a_declared_zero.py +0 -0
  233. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_starved_join_says_which_operand_starved.py +0 -0
  234. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_surprise_the_store_never_saw_is_not_a_miss.py +0 -0
  235. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_tie_break_knows_which_side_of_the_line.py +0 -0
  236. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_tie_is_broken_by_the_declared_margin.py +0 -0
  237. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_transition_into_an_acted_property_still_arrives.py +0 -0
  238. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_two_stage_chain_composes_exactly.py +0 -0
  239. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_value_is_final_before_anything_reads_it.py +0 -0
  240. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_warning_is_a_finding_on_every_surface.py +0 -0
  241. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_what_if_is_evaluated_at_the_horizon_it_asked_for.py +0 -0
  242. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_window_cannot_see_past_the_frozen_clock.py +0 -0
  243. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_withdrawn_check_is_not_silent.py +0 -0
  244. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_zero_allowance_still_reports.py +0 -0
  245. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_absent_data_regressions.py +0 -0
  246. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_agreement_declines_what_it_used_to_guess.py +0 -0
  247. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_an_action_may_arrive_as_a_mapping.py +0 -0
  248. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_an_action_on_a_coupled_property_reads_the_value_it_has.py +0 -0
  249. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_an_action_outlives_the_forecast_it_overrides.py +0 -0
  250. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_an_action_that_never_runs_says_so.py +0 -0
  251. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_an_imagined_breach_is_not_a_live_one_in_the_telemetry.py +0 -0
  252. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_an_imagined_finding_is_not_a_live_one.py +0 -0
  253. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_an_invented_time_course_says_so.py +0 -0
  254. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_an_undeclared_transition_projects_nothing.py +0 -0
  255. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_closed_reader.py +0 -0
  256. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_connectivity_required_property.py +0 -0
  257. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_conservation_absent_output.py +0 -0
  258. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_cross_signal_consistency.py +0 -0
  259. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_decline_contract.py +0 -0
  260. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_did_you_mean_is_case_insensitive.py +0 -0
  261. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_discovery_proposes_and_never_promotes.py +0 -0
  262. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_documented_paths_the_suite_never_ran.py +0 -0
  263. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_entailment_derives_and_refuses.py +0 -0
  264. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_envelope_schema.py +0 -0
  265. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_every_assumption_stamp_has_one_name.py +0 -0
  266. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_every_declared_tool_has_a_wrapper.py +0 -0
  267. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_every_decline_reason_has_a_producer.py +0 -0
  268. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_every_discipline_decline_has_one_name.py +0 -0
  269. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_every_forecast_gets_a_yardstick.py +0 -0
  270. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_every_reader_takes_the_same_history.py +0 -0
  271. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_every_shipped_example_actually_runs.py +0 -0
  272. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_every_simulation_decline_has_an_input.py +0 -0
  273. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_gated_cell_declines.py +0 -0
  274. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_history_outlives_the_process_and_the_weekend.py +0 -0
  275. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_homeostasis_setpoint.py +0 -0
  276. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_importing_the_package_does_not_pull_an_optional_extra.py +0 -0
  277. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_lower_bounds.py +0 -0
  278. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_mcp_feeders.py +0 -0
  279. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_mcp_roundtrip.py +0 -0
  280. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_monotonicity_reversals.py +0 -0
  281. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_no_axiom_retires_a_check.py +0 -0
  282. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_no_cell_is_judged_twice.py +0 -0
  283. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_no_identifier_names_a_private_record.py +0 -0
  284. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_no_test_anchors_time_at_import.py +0 -0
  285. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_one_declared_spread_is_counted_once.py +0 -0
  286. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_one_question_gets_one_projection.py +0 -0
  287. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_one_set_of_names_the_model_reads.py +0 -0
  288. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_role_comes_from_the_model.py +0 -0
  289. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_slow_oscillation.py +0 -0
  290. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_axioms_run_over_the_forecast_itself.py +0 -0
  291. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_causal_verb_has_a_model_to_run_against.py +0 -0
  292. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_clock_can_be_moved.py +0 -0
  293. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_config_blocks_are_documented.py +0 -0
  294. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_documented_priorities_are_the_computed_ones.py +0 -0
  295. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_engine_declares_no_domain_it_does_not_serve.py +0 -0
  296. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_engine_invents_no_indicators.py +0 -0
  297. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_engine_races_its_own_forecasts.py +0 -0
  298. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_engine_says_what_its_approximation_cost.py +0 -0
  299. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_engine_scores_its_own_declared_spread.py +0 -0
  300. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_engines_own_forecast_is_not_a_producers.py +0 -0
  301. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_envelope_legs_are_documented.py +0 -0
  302. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_forecasts_leg_says_how_many_were_expected.py +0 -0
  303. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_indicator_keys_are_documented.py +0 -0
  304. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_ingest_tag_names_the_caller_not_the_funnel.py +0 -0
  305. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_lane_cleans_up_after_itself.py +0 -0
  306. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_ledger_is_reachable_without_a_deep_import.py +0 -0
  307. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_legal_files_ship_together.py +0 -0
  308. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_namespaces_point_at_a_graph_that_ships.py +0 -0
  309. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_policy_document_and_the_changelog_agree.py +0 -0
  310. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_published_cascade_formula_is_the_one_that_runs.py +0 -0
  311. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_question_ranking_is_one_scale.py +0 -0
  312. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_rate_arm_declines_what_it_used_to_guess.py +0 -0
  313. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_readme_decline_count_is_derived.py +0 -0
  314. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_readme_name_count_is_derived.py +0 -0
  315. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_readme_names_the_forms_load_model_takes.py +0 -0
  316. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_rename_table_names_real_things.py +0 -0
  317. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_sample_floor_says_whether_it_is_reachable.py +0 -0
  318. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_schema_names_every_sub_envelope.py +0 -0
  319. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_schema_names_what_a_sub_envelope_carries.py +0 -0
  320. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_session_keeps_its_own_ledger.py +0 -0
  321. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_verb_that_used_the_number_names_it.py +0 -0
  322. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_world_model_can_be_exercised_over_mcp.py +0 -0
  323. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_threshold_overrides.py +0 -0
  324. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_timestamped_ingestion.py +0 -0
  325. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_traverse_vocabularies.py +0 -0
  326. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_trend_widens_and_does_not_point.py +0 -0
  327. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_two_actions_at_two_instants_are_not_one.py +0 -0
  328. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_two_bare_series_are_joinable.py +0 -0
  329. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_two_claims_on_one_edge_are_two_questions.py +0 -0
  330. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_two_offset_couplings_from_one_source_are_both_charged.py +0 -0
  331. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_two_plans_that_cost_the_same_compare_equal.py +0 -0
  332. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_two_rules_can_close_a_loop_neither_closes_alone.py +0 -0
  333. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_two_settings_of_one_property_do_not_add.py +0 -0
  334. {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_unread_properties.py +0 -0
@@ -109,15 +109,26 @@ jobs:
109
109
  GH_TOKEN: ${{ github.token }}
110
110
  run: gh release upload "$GITHUB_REF_NAME" dist/* --clobber
111
111
 
112
- # PUBLISHING IS OFF UNTIL THE INDEX SIDE EXISTS, and the marker is a file
113
- # rather than a setting so the change that turns it on is reviewable.
112
+ # PUBLISHING IS DONE BY HAND, BY RULING, and the marker is a file rather
113
+ # than a setting so the change that turns it back on is reviewable.
114
114
  #
115
- # Trusted Publishing needs a publisher registered on PyPI naming this
116
- # repository, this workflow file and this environment. Until that is
117
- # registered, minting fails -- and a job that is red on every release day
118
- # is one people learn to skip, which is the argument `verify-published.yml`
119
- # already makes about itself. So: build and attach always, publish only
120
- # when the marker says the other side is ready.
115
+ # It was ON from 2026-09-03 to 2026-09-25 and never published a file. The
116
+ # job below runs on the TAG; the release runbook uploads BEFORE the tag,
117
+ # so the repository never advertises a version the index does not serve.
118
+ # For a release made that way the publish job can only ever meet a version
119
+ # already on the index, so approving it could only fail -- and fourteen tag
120
+ # runs, v0.1.11 through v0.2.7, sat waiting with no conclusion instead.
121
+ # That is the two paths being mutually exclusive, not somebody forgetting
122
+ # to click.
123
+ #
124
+ # BOTH SETTINGS IT NEEDS STILL EXIST, and settings do not show in a diff,
125
+ # so they are stated here rather than lost with the marker. A `pypi`
126
+ # environment with a required reviewer (measured 2026-09-25), and a PyPI
127
+ # trusted publisher naming this repository, this workflow and that
128
+ # environment (verified at registration on 2026-09-03; no upload has ever
129
+ # used it). Turning publishing back on is a change to the UPLOAD ORDER
130
+ # first -- tag, then publish -- and the marker second. The marker alone
131
+ # restores exactly the waits described above.
121
132
  - name: Is publishing from CI enabled?
122
133
  id: gate
123
134
  run: |
@@ -126,12 +137,13 @@ jobs:
126
137
  else
127
138
  echo "enabled=false" >> "$GITHUB_OUTPUT"
128
139
  echo "::notice::CI built these artifacts from the tag and attached them" \
129
- "to the Release. Publishing to the index is still done by hand." \
130
- "To hand it over: create the 'pypi' environment in this" \
131
- "repository's settings, register a PyPI trusted publisher naming" \
132
- "this repository, release.yml and that environment, then add" \
133
- ".github/PUBLISH_FROM_CI. The publish job stays behind the" \
134
- "environment's approval either way."
140
+ "to the Release. Publishing to the index is done by hand, before" \
141
+ "the tag, so this repository never advertises a version the index" \
142
+ "does not serve. The 'pypi' environment and the PyPI trusted" \
143
+ "publisher both still exist. To hand publishing to CI, change the" \
144
+ "release order to tag-then-publish FIRST, then add" \
145
+ ".github/PUBLISH_FROM_CI: the marker alone brings back a publish" \
146
+ "job that can only meet a version already on the index."
135
147
  fi
136
148
 
137
149
  # The bytes that were attached, kept for the publish job. NOT a rebuild
@@ -34,7 +34,81 @@ useful-looking document and the less trustworthy one.
34
34
 
35
35
  ## [Unreleased]
36
36
 
37
- _Nothing yet._
37
+ ## [0.2.8] — 2026-09-25
38
+
39
+ ### Added
40
+
41
+ - **`target_reading_set_aside` (`TARGET_READING_SET_ASIDE`), a stamp on every
42
+ `inference` answer whose target had a reading of its own.** `infer` answers whether everything ELSE implicates
43
+ the target, so the target's own reading is left out -- and nothing said so. A
44
+ supply at 9.0 kV, below its own critical floor, got the posterior it gets at a
45
+ healthy 11.0 kV. `checked.target_reading` now carries what the reading would
46
+ have set (`faulty` or `clean`) and the target's own worst severity at any
47
+ level. No posterior changes.
48
+ - **Each `hypothesize` candidate carries `own_reading`**, the same row for that
49
+ candidate: `None` when it was unread, which is the case `evidence_needed` is
50
+ written for. Measured before it: a feeder read CLEAN ranked first at 0.962
51
+ with its own current named as the evidence needed.
52
+
53
+ ### Fixed
54
+
55
+ - **`hypothesize` carries the stamps of the inferences behind its ranking.** It
56
+ dropped all of them, so a ranking computed against this engine's default
57
+ evidence floor arrived without `evidence_severity_not_declared`, while the
58
+ verb's own docstring told the reader to check for that stamp.
59
+ - **An intervention on the target answers exactly.** `infer(t, do={t: v})`
60
+ returned the same posterior for `v = 0` and `v = 1` (0.984981 on the
61
+ specimen), because the forced value was set aside with the reading. It
62
+ returns `v` now, with method `intervention`, and files nothing.
63
+ - **Twelve published sentences that read as broken English.** Seven docstrings
64
+ and comments (`Until this returned two values`, `the ONLY rule until, and`)
65
+ and five lines of `evidence/` (`the recursive-examination framework
66
+ framework`) came out of the step that removes internal references. They now
67
+ read as sentences. No behaviour changes.
68
+
69
+ ### Changed
70
+
71
+ - **Releases are uploaded to the index by hand, and `.github/PUBLISH_FROM_CI` is
72
+ retired.** The CI publish job it enabled runs on the tag, after the upload the
73
+ release procedure makes first, so it never published a file. CI still builds
74
+ each release from its tag and attaches the files to the GitHub Release.
75
+
76
+ ## [0.2.7] — 2026-09-25
77
+
78
+ ### Added
79
+
80
+ - **Every fitted transition proposal now carries a `replay`**: what adopting it
81
+ would have caught, as counts against the corpus that recorded what happened.
82
+ `n` and `r_squared` say how well a gain fits the data it was fitted on, which
83
+ is a different question.
84
+ - **`replay_unavailable` (`REPLAY_UNAVAILABLE`) is the answer when no corpus was
85
+ supplied.** It carries its reason and no counts: a proposal nobody could test
86
+ is not a proposal that failed, and a zero cannot tell those apart. No rate is
87
+ reported, for the reason the surprise score reports none.
88
+ - **`hypothesize(session, entity_id)` — what could explain a finding, ranked.**
89
+ The inverse of `gaps`: that verb says what the model does not declare, this
90
+ says what the world might be doing given what it does. Each candidate is a
91
+ DECLARED causal ancestor, scored by the same inference `infer` runs, carrying
92
+ the reading that would discriminate it and the declared action that could test
93
+ it. `MAX_HOPS` bounds the walk. It ranks nothing the author did not connect.
94
+ - **`arbiter_engine.producers.baseline_learner`, a reference producer.** A
95
+ damped-trend exponential smoother, shipped because the engine's own baseline
96
+ is a random walk and a random walk is the right floor and a poor opponent. It
97
+ gets no privilege: it reads a session through `reading_history()` and files
98
+ through `ingest_forecasts` like any outside forecaster. `MINIMUM_POINTS` is
99
+ the series length below which it returns nothing rather than a fitted number.
100
+ - **`model_describe(session, surprises=...)`** takes the corpus to replay
101
+ against. The model is restored afterwards whether or not the replay ran --
102
+ deriving and adopting stay separate.
103
+
104
+ ### Changed
105
+
106
+ - **The proposal surface now records WHO may write a fitted gain down, and it
107
+ is not this package.** A tool downstream -- a separate distribution, a
108
+ separate command, a proposal named by a person, a basis recorded in the file
109
+ -- may adopt one into a model it owns. Nothing here opens a model for
110
+ writing, and a test compares the file's bytes rather than reading this source
111
+ for a call. The first such writer is `bmc-sensor-audit adopt`.
38
112
 
39
113
  ## [0.2.6] — 2026-09-24
40
114
 
@@ -9,8 +9,8 @@ authors:
9
9
  alias: "james-sheen"
10
10
  - name: "The Arbiter Project Authors"
11
11
  license: Apache-2.0
12
- version: "0.2.6"
13
- date-released: "2026-09-24"
12
+ version: "0.2.8"
13
+ date-released: "2026-09-25"
14
14
  repository-code: "https://github.com/james-sheen/arbiter"
15
15
  url: "https://github.com/james-sheen/arbiter"
16
16
  keywords:
@@ -1105,7 +1105,18 @@ this is a verb rather than a filter over `traverse`. On the shipped specimen,
1105
1105
  asking about the supply with the feeder OBSERVED faulty gives 0.679054 and with
1106
1106
  the feeder FORCED faulty gives 0.05 -- the same node in the same state, a factor
1107
1107
  of thirteen apart. Seeing a thing fail is evidence about what feeds it; breaking
1108
- it yourself is not.
1108
+ it yourself is not. Forcing the TARGET itself answers exactly: `do={t: v}`
1109
+ returns `v`, method `intervention`.
1110
+
1111
+ **The target's own reading is not evidence about the target.** `infer` asks
1112
+ whether everything ELSE implicates it, because conditioning on its own state
1113
+ would answer 1 or 0 by construction. So a supply in critical breach and the
1114
+ same supply healthy get one posterior between them -- correct for that
1115
+ question, and the answer says so: `target_reading_set_aside` is stamped whenever
1116
+ the target had a reading, and `checked.target_reading` names the state it would
1117
+ have set and the target's own worst severity. `hypothesize` carries the same
1118
+ row per candidate as `own_reading`, so a candidate the graph implicates can be
1119
+ read beside what its own meter already said.
1109
1120
 
1110
1121
  ### What counts as faulty evidence: `causal.evidence_severity`
1111
1122
 
@@ -1249,7 +1260,8 @@ which number to distrust.
1249
1260
  They arrive in an `assumptions` list on the `simulation` and `plan`
1250
1261
  sub-envelopes, and on each `plan` candidate where the candidates differ. An
1251
1262
  EMPTY list means the engine made none of them, which is a different claim from
1252
- the key being absent.
1263
+ the key being absent. The `inference` sub-envelope -- what `infer` and
1264
+ `hypothesize` return -- carries the list only when it has something in it.
1253
1265
 
1254
1266
  | stamp | what it discloses |
1255
1267
  |---|---|
@@ -1257,6 +1269,7 @@ the key being absent.
1257
1269
  | `time_course_not_declared` | the time course crossed was not declared; this engine supplied a delay or a time constant, or both |
1258
1270
  | `evidence_severity_not_declared` | `infer` read the last check against THIS engine's severity floor, because the model declared none. Declare `causal.evidence_severity:` to choose it |
1259
1271
  | `evidence_severity_unusable` | the model DID declare `causal.evidence_severity:` and this engine could not use it, so the floor above was its own. Carried beside the stamp above, never instead of it; `model_describe` names the value that was refused |
1272
+ | `target_reading_set_aside` | the queried entity had a reading of its own and the posterior was computed without it -- the question answered is whether everything else implicates it. `checked.target_reading` says what the reading would have set, and the target's own worst severity |
1260
1273
  | `steady_state_reached` | the horizon outlasted the transient, so the value reported is the settled one |
1261
1274
  | `series_edges_composed_exactly` | two couplings in series were composed by the exact cascade response |
1262
1275
  | `series_edges_compose_by_product` | two couplings in series were composed by multiplying response fractions, which is an approximation |
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: arbiter-engine
3
- Version: 0.2.6
3
+ Version: 0.2.8
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
@@ -514,7 +514,7 @@ The engine is open. The knowledge and the operations are not.
514
514
 
515
515
  ## Status
516
516
 
517
- **v0.2.** 95 Python files, 93 modules importing on the declared dependencies alone, 15 supported
517
+ **v0.2.** 98 Python files, 96 modules importing on the declared dependencies alone, 15 supported
518
518
  names — **counted in this repository**, which is the package you are holding.
519
519
 
520
520
  That basis is stated because it is easy to get wrong in a way nobody notices. The build adds one
@@ -523,7 +523,7 @@ are holding — and this line published the smaller figure until 2026-08-12, whe
523
523
  falsify it with `find . -name '*.py' | wc -l`. A checkable false claim, in the Status section of a
524
524
  project whose subject is checkable claims. Count the artifact, never an earlier stage of it.
525
525
 
526
- The import figure carries the same hazard one layer down, and it depends on what you have installed. Sweeping the package where `scipy` happens to be present imports 94; on the declared dependencies alone it is the 93 above, because `propagation.lp_confidence` is the one module that needs `scipy` and it is a deep path outside the supported surface. Count the artifact **in the state the reader will have it**, not in the state the person measuring happens to be standing in — this line quoted the with-`scipy` figure until 2026-08-12, which no reader installing normally could reproduce.
526
+ The import figure carries the same hazard one layer down, and it depends on what you have installed. Sweeping the package where `scipy` happens to be present imports 97; on the declared dependencies alone it is the 96 above, because `propagation.lp_confidence` is the one module that needs `scipy` and it is a deep path outside the supported surface. Count the artifact **in the state the reader will have it**, not in the state the person measuring happens to be standing in — this line quoted the with-`scipy` figure until 2026-08-12, which no reader installing normally could reproduce.
527
527
 
528
528
  **The supported-name count went stale in exactly the way this section warns about.** It read
529
529
  three short for the release that added `SqliteObservationHistory`, `SessionCalendar` and
@@ -540,7 +540,7 @@ committed by the paragraph. The figures are described here now rather than quote
540
540
  rule the changelog states for its own errata: a correction that reproduces the string it corrects
541
541
  is that string to a checker.
542
542
 
543
- **And the count is of SUBMODULES: the root package is not one of them.** Walking `arbiter_engine` for what it contains gives 93; adding the package you imported to reach them gives 94. Both are honest and they are answers to different questions, so a reader who recounts and gets one more has not found a defect — they have used the other convention. Stated because someone did exactly that from outside, and a number published without its predicate can only be agreed with or disagreed with, never checked. **Every figure in this paragraph moved by one when `assumptions` landed, and nothing went red for two rounds** -- the guard that compares them to the artifact only runs when a built tree exists, so it is silent in every session that does not build one. A check conditioned on an artifact is not a check that runs.
543
+ **And the count is of SUBMODULES: the root package is not one of them.** Walking `arbiter_engine` for what it contains gives 96; adding the package you imported to reach them gives 97. Both are honest and they are answers to different questions, so a reader who recounts and gets one more has not found a defect — they have used the other convention. Stated because someone did exactly that from outside, and a number published without its predicate can only be agreed with or disagreed with, never checked. **Every figure in this paragraph moved by TWO when the reference producer landed, and by one when `assumptions` did, and that earlier move went unnoticed for two rounds** -- the guard that compares them to the artifact only runs when a built tree exists, so it is silent in every session that does not build one. A check conditioned on an artifact is not a check that runs.
544
544
 
545
545
  Honest boundaries, stated because you would otherwise find them yourself:
546
546
 
@@ -476,7 +476,7 @@ The engine is open. The knowledge and the operations are not.
476
476
 
477
477
  ## Status
478
478
 
479
- **v0.2.** 95 Python files, 93 modules importing on the declared dependencies alone, 15 supported
479
+ **v0.2.** 98 Python files, 96 modules importing on the declared dependencies alone, 15 supported
480
480
  names — **counted in this repository**, which is the package you are holding.
481
481
 
482
482
  That basis is stated because it is easy to get wrong in a way nobody notices. The build adds one
@@ -485,7 +485,7 @@ are holding — and this line published the smaller figure until 2026-08-12, whe
485
485
  falsify it with `find . -name '*.py' | wc -l`. A checkable false claim, in the Status section of a
486
486
  project whose subject is checkable claims. Count the artifact, never an earlier stage of it.
487
487
 
488
- The import figure carries the same hazard one layer down, and it depends on what you have installed. Sweeping the package where `scipy` happens to be present imports 94; on the declared dependencies alone it is the 93 above, because `propagation.lp_confidence` is the one module that needs `scipy` and it is a deep path outside the supported surface. Count the artifact **in the state the reader will have it**, not in the state the person measuring happens to be standing in — this line quoted the with-`scipy` figure until 2026-08-12, which no reader installing normally could reproduce.
488
+ The import figure carries the same hazard one layer down, and it depends on what you have installed. Sweeping the package where `scipy` happens to be present imports 97; on the declared dependencies alone it is the 96 above, because `propagation.lp_confidence` is the one module that needs `scipy` and it is a deep path outside the supported surface. Count the artifact **in the state the reader will have it**, not in the state the person measuring happens to be standing in — this line quoted the with-`scipy` figure until 2026-08-12, which no reader installing normally could reproduce.
489
489
 
490
490
  **The supported-name count went stale in exactly the way this section warns about.** It read
491
491
  three short for the release that added `SqliteObservationHistory`, `SessionCalendar` and
@@ -502,7 +502,7 @@ committed by the paragraph. The figures are described here now rather than quote
502
502
  rule the changelog states for its own errata: a correction that reproduces the string it corrects
503
503
  is that string to a checker.
504
504
 
505
- **And the count is of SUBMODULES: the root package is not one of them.** Walking `arbiter_engine` for what it contains gives 93; adding the package you imported to reach them gives 94. Both are honest and they are answers to different questions, so a reader who recounts and gets one more has not found a defect — they have used the other convention. Stated because someone did exactly that from outside, and a number published without its predicate can only be agreed with or disagreed with, never checked. **Every figure in this paragraph moved by one when `assumptions` landed, and nothing went red for two rounds** -- the guard that compares them to the artifact only runs when a built tree exists, so it is silent in every session that does not build one. A check conditioned on an artifact is not a check that runs.
505
+ **And the count is of SUBMODULES: the root package is not one of them.** Walking `arbiter_engine` for what it contains gives 96; adding the package you imported to reach them gives 97. Both are honest and they are answers to different questions, so a reader who recounts and gets one more has not found a defect — they have used the other convention. Stated because someone did exactly that from outside, and a number published without its predicate can only be agreed with or disagreed with, never checked. **Every figure in this paragraph moved by TWO when the reference producer landed, and by one when `assumptions` did, and that earlier move went unnoticed for two rounds** -- the guard that compares them to the artifact only runs when a built tree exists, so it is silent in every session that does not build one. A check conditioned on an artifact is not a check that runs.
506
506
 
507
507
  Honest boundaries, stated because you would otherwise find them yourself:
508
508
 
@@ -79,6 +79,28 @@ declaration.
79
79
  its own stated spread. It does not order producers, recommend one, or carry a
80
80
  reputation between sessions.
81
81
 
82
+ ## The reference producer, which gets none of the above either
83
+
84
+ The package ships one: `arbiter_engine.producers.baseline_learner`, a
85
+ damped-trend exponential smoother. It exists because the engine's own baseline
86
+ is a **random walk** — it predicts the last value and widens with the horizon —
87
+ and a random walk is the right floor and a poor opponent. Anything that notices
88
+ a series is going somewhere beats it, so *beats the baseline* against a random
89
+ walk alone says almost nothing.
90
+
91
+ **It is a producer, not a feature.** It reads a session through
92
+ `reading_history()`, the accessor this engine tells every reader to use, and
93
+ files ordinary records through `ingest_forecasts`. It imports no checker, is
94
+ handed no privilege an outside forecaster would be refused, and is scored by
95
+ exactly the rules above — including `not_a_producers_submission` if its records
96
+ carry a `source`. A baseline with access the competition lacks is not a
97
+ baseline, and the suite asserts its import surface as well as its score.
98
+
99
+ **It refuses rather than guessing.** A series shorter than its minimum gets no
100
+ forecast, and one whose points are not ordered in time is refused rather than
101
+ sorted — re-ordering a series nobody gave you that way is how a producer comes
102
+ to score well on data it invented.
103
+
82
104
  ## Why the engine sets its own records aside
83
105
 
84
106
  The engine is a producer too. `rollout` files what it projected; every
@@ -754,7 +754,16 @@ _FEEDERS_ON_THE_SUPPORTED_SURFACE = (
754
754
  )
755
755
 
756
756
 
757
- def _proposed_transitions(session: EngineSession) -> Dict[str, Any]:
757
+ def _replay_proposal(session: EngineSession, proposal: Any,
758
+ surprises: Any) -> Dict[str, Any]:
759
+ """One proposal's replay, or the refusal that stands in for it."""
760
+ from arbiter_engine.surprises import replay_proposal
761
+
762
+ return replay_proposal(session, proposal, surprises)
763
+
764
+
765
+ def _proposed_transitions(session: EngineSession,
766
+ surprises: Any = None) -> Dict[str, Any]:
758
767
  """Fitted gains, their support, and any that contradict a declaration.
759
768
 
760
769
  Reported from `model_describe` rather than from a verb of its
@@ -767,6 +776,32 @@ def _proposed_transitions(session: EngineSession) -> Dict[str, Any]:
767
776
  author's claim about the system, and an engine that silently replaced it
768
777
  with a fitted number would leave nobody able to say what the model
769
778
  asserts -- the file would no longer be the model.
779
+
780
+ RULED 2026-09-25, A VERTICAL MAY WRITE ONE DOWN; THIS ENGINE
781
+ STILL MAY NOT. The phase plan asked for an `adopt <proposal_id>` verb,
782
+ and this package had refused one twice -- here and in
783
+ `causal/discovery.py`. The ruling separates the two things that question
784
+ runs together. What is refused above is an ENGINE acting on its own
785
+ measurement: a process handed a file to read, rewriting it, on a number
786
+ nobody asked it for. What is now permitted is a tool DOWNSTREAM of this
787
+ one, whose own author maintains the file, invoked by a person who typed
788
+ the proposal's name, writing the number with a basis beside it saying
789
+ where it came from. The file still says what the model asserts. It now
790
+ says the author chose to assert a fitted number, and says so in the file.
791
+
792
+ THE DISTANCE IS THE WHOLE OF THE RULING, AND NONE OF IT IS HERE: a
793
+ separate distribution, a separate command, a named proposal, a recorded
794
+ basis, and a gate that refuses a number which would have caught nothing.
795
+ Take any one of those away and what is left is the thing refused above.
796
+
797
+ So nothing in this package opens a model for writing, and the shipped
798
+ suite holds that by RUNNING this surface -- the replay included, which
799
+ substitutes a proposal to measure it -- and comparing the model file's
800
+ bytes, size and modification time afterwards. Not by reading this source
801
+ for a `write` call, which is a check on text about a claim concerning
802
+ behaviour. The first downstream writer is `bmc-sensor-audit adopt`, which
803
+ writes a fitted `gain` and its `gain_basis` into the supplemental file that
804
+ vertical's operator already maintains by hand.
770
805
  """
771
806
  from arbiter_engine.twin.transition_learner import (
772
807
  MINIMUM_PAIRED_SAMPLES, learn_transitions,
@@ -816,7 +851,14 @@ def _proposed_transitions(session: EngineSession) -> Dict[str, Any]:
816
851
  # author's behalf is the one thing this surface does not do.
817
852
  "residual_autocorrelation": p.residual_autocorrelation,
818
853
  "gain_sigma_assumes_independent_residuals":
819
- p.standard_error_assumes_independence}
854
+ p.standard_error_assumes_independence,
855
+ # WOULD ADOPTING THIS HAVE CAUGHT MORE. A proposal is a
856
+ # number somebody has to decide about, and `n` and `r_squared`
857
+ # answer how well it fits the data it was fitted on, which is not
858
+ # the same question. Without a corpus this is a REFUSAL carrying
859
+ # its reason, never a zero: a proposal nobody could test is not a
860
+ # proposal that failed.
861
+ "replay": _replay_proposal(session, p, surprises)}
820
862
  for p in proposals],
821
863
  "not_fitted": [
822
864
  {"edge": r.location, "reason": r.reason, "detail": r.detail}
@@ -1051,7 +1093,8 @@ def _transition_coverage(model, session: Optional[EngineSession] = None
1051
1093
  }
1052
1094
 
1053
1095
 
1054
- def model_describe(session: EngineSession) -> Envelope:
1096
+ def model_describe(session: EngineSession,
1097
+ surprises: Any = None) -> Envelope:
1055
1098
  """What domain is loaded: entity types, indicators, declared axioms.
1056
1099
 
1057
1100
  This is the grounding tool. An agent calls it before reasoning so it
@@ -1150,7 +1193,7 @@ def model_describe(session: EngineSession) -> Envelope:
1150
1193
  # ones the author declared. Proposals: nothing here has changed the
1151
1194
  # model, and a `gain: estimate` transition projects no value until a
1152
1195
  # number is adopted into the YAML.
1153
- "proposed_transitions": _proposed_transitions(session),
1196
+ "proposed_transitions": _proposed_transitions(session, surprises),
1154
1197
  # the list, mounted where a MODEL fact belongs. `check` has
1155
1198
  # carried it since it was added; this verb, whose whole question is
1156
1199
  # *did my model load the way I wrote it*, did not -- so a reader
@@ -2461,6 +2504,61 @@ def entail(session: EngineSession, adopt: bool = False) -> Envelope:
2461
2504
  return _WithPayload(envelope, payload)
2462
2505
 
2463
2506
 
2507
+ def hypothesize(session: EngineSession, entity_id: str,
2508
+ report_above: Optional[float] = None) -> Envelope:
2509
+ """What could explain a finding on `entity_id`, ranked, with what to read next.
2510
+
2511
+ THE INVERSE OF `gaps`. That verb says what the MODEL does not declare; this
2512
+ says what the WORLD might be doing given what it does — the same question
2513
+ turned around, and the one an operator has after a finding names an entity
2514
+ that is wrong.
2515
+
2516
+ Each candidate is a DECLARED causal ancestor, scored by the same inference
2517
+ `infer` runs, and carries the reading that would discriminate it and the
2518
+ declared action that could test it. Nothing here searches for a cause
2519
+ outside the graph: an engine proposing causes nobody declared would be doing
2520
+ the inference this project removed from `role:` and from flow direction.
2521
+
2522
+ **It is only as good as the evidence severity.** With every breach at
2523
+ `warning` and no `causal.evidence_severity:` declared, no finding counts as
2524
+ evidence, every posterior sits at its prior, and the ranking is an ordering
2525
+ of priors rather than of explanations. Measured on the shipped substation
2526
+ specimen: with both panels in the warning band the supply outranks the
2527
+ feeder 0.0104 to 0.0018, and with both below critical the feeder ranks first
2528
+ at 0.962. Same topology, same question, opposite answers — so read the
2529
+ `evidence_severity_not_declared` stamp before reading this ranking. Since
2530
+ the ranking carries it: every stamp an inference behind a candidate
2531
+ applied rides on `hypothesis.assumptions`. Before that the verb dropped
2532
+ them, and this paragraph told the reader to look for a stamp that was never
2533
+ there.
2534
+
2535
+ **A candidate's own reading is not part of its score.** Each posterior
2536
+ answers whether the REST of the graph implicates that candidate, and
2537
+ `own_reading` says what the candidate's own meter already said -- `None`
2538
+ when unread, which is the case `evidence_needed` is for. Measured: a feeder
2539
+ read clean at 300 A ranked first at 0.962 with its own current named as the
2540
+ evidence needed. The ranking is right about the graph; the row now shows
2541
+ the reading beside it.
2542
+ """
2543
+ from arbiter_engine.inference.hypothesis import (
2544
+ hypothesize as _hypothesize)
2545
+
2546
+ if session.model is None:
2547
+ return unavailable_envelope("no domain model loaded")
2548
+ try:
2549
+ sub, ranked = _hypothesize(session, entity_id, report_above=report_above)
2550
+ except Exception as exc: # noqa: BLE001 - see `_raised`
2551
+ sub, ranked = _raised("inference", exc, {"candidates": 0}), []
2552
+
2553
+ envelope = Envelope(
2554
+ checked=CheckedSummary(invariants=0, entities=len(session.entities)),
2555
+ findings=list(sub.findings), questions=[_q(q) for q in sub.questions])
2556
+ payload = envelope.to_dict()
2557
+ payload["hypothesis"] = sub.to_dict()
2558
+ payload["hypothesis"]["candidates"] = ranked
2559
+ return _WithPayload(envelope, payload)
2560
+
2561
+
2464
2562
  def infer(session: EngineSession, target: str,
2465
2563
  do: Optional[Dict[str, int]] = None,
2466
2564
  report_above: Optional[float] = None) -> Envelope:
@@ -2500,6 +2598,18 @@ def infer(session: EngineSession, target: str,
2500
2598
  Without `report_above` there is no finding, on the same rule as `project`
2501
2599
  and `discover`: the posterior is computed and reported, and whether it is
2502
2600
  alarming is not the engine's to decide.
2601
+
2602
+ THE TARGET'S OWN READING IS NOT EVIDENCE. The question answered is whether
2603
+ everything ELSE implicates the target -- conditioning on its own state would
2604
+ return 1 or 0 by construction. When the target had a reading, the answer is
2605
+ stamped `target_reading_set_aside` and `checked.target_reading` says what
2606
+ the reading would have set (`faulty` or `clean`) and the target's own worst
2607
+ severity at any level. A supply in critical breach and the same supply
2608
+ healthy get one posterior between them; that is correct for the question,
2609
+ and until a later change nothing on the answer said which question it was.
2610
+
2611
+ An intervention on the target itself answers exactly: `do={t: v}` returns
2612
+ `v`, method `intervention`, and files nothing.
2503
2613
  """
2504
2614
  if session.model is None:
2505
2615
  return unavailable_envelope("no domain model loaded")
@@ -6,7 +6,7 @@ not a warning and not a finding: it is the engine saying which of its own
6
6
  choices the value in front of you depends on, so that a reader who disagrees
7
7
  with the choice knows which number to distrust.
8
8
 
9
- WHY THEY LIVE HERE. Until they lived as bare string literals at twenty
9
+ WHY THEY LIVE HERE. Until a later change they lived as bare string literals at twenty
10
10
  sites across four modules, and nothing anywhere held the list. The cost was not
11
11
  hypothetical. An outside comparison of this engine reproduced all three of its
12
12
  ENUMERATED vocabularies exactly -- the fourteen decline reasons, the six gap
@@ -85,6 +85,23 @@ EVIDENCE_SEVERITY_NOT_DECLARED = "evidence_severity_not_declared"
85
85
  #: duplicate what is there.
86
86
  EVIDENCE_SEVERITY_UNUSABLE = "evidence_severity_unusable"
87
87
 
88
+ #: The queried entity had a reading of its own, and the posterior was computed
89
+ #: WITHOUT it. `infer` answers *does the rest of the graph implicate this
90
+ #: entity*, which is the informative question -- conditioning on the target's
91
+ #: own state would answer 1 or 0 by construction -- and the engine chose that
92
+ #: question on the caller's behalf. What the reading said is on the answer as
93
+ #: `checked.target_reading`: the state it would have set, and the target's own
94
+ #: worst severity at any level.
95
+ #:
96
+ #:, and it went unsaid for as long as the verb has existed. Measured on
97
+ #: the substation specimen with the feeder unread: the supply at 9.0 kV, below
98
+ #: its own critical floor, gets exactly the posterior it gets at a healthy
99
+ #: 11.0 kV, 0.670634 both times, because the one reading that would have
100
+ #: settled the question was the one left out. The other direction is worse. A feeder READ CLEAN is ranked
101
+ #: first by `hypothesize` at 0.962 with its own meter named as the evidence
102
+ #: needed -- the reading it had already taken and set aside.
103
+ TARGET_READING_SET_ASIDE = "target_reading_set_aside"
104
+
88
105
  #: The horizon was long enough that the transient had finished, so the value
89
106
  #: reported is the steady state rather than a point on the way to it.
90
107
  STEADY_STATE_REACHED = "steady_state_reached"
@@ -239,6 +256,7 @@ ASSUMPTION_STAMPS: Tuple[str, ...] = (
239
256
  TIME_COURSE_NOT_DECLARED,
240
257
  EVIDENCE_SEVERITY_NOT_DECLARED,
241
258
  EVIDENCE_SEVERITY_UNUSABLE,
259
+ TARGET_READING_SET_ASIDE,
242
260
  STEADY_STATE_REACHED,
243
261
  SERIES_EDGES_COMPOSED_EXACTLY,
244
262
  SERIES_EDGES_COMPOSE_BY_PRODUCT,
@@ -75,7 +75,7 @@ domain:
75
75
  #
76
76
  # The role rule is single-value: `role: percentage` range-checks this
77
77
  # reading against 0-100 and would behave identically if `level_pct` were
78
- # deleted from the model. That was the ONLY rule until, and this
78
+ # deleted from the model. That was the ONLY rule until a later change, and this
79
79
  # comment said `two independent readings that should agree` until
80
80
  # 2026-08-16 -- the reading the use-case catalogue carried in eleven
81
81
  # places, and the reason both were reported from outside on the same day.