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.
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/.github/workflows/release.yml +26 -14
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/CHANGELOG.md +75 -1
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/CITATION.cff +2 -2
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/MODELING.md +15 -2
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/PKG-INFO +4 -4
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/README.md +3 -3
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/STANCE.md +22 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/api.py +114 -4
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/assumptions.py +19 -1
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/examples/water_tank.yaml +1 -1
- arbiter_engine-0.2.8/arbiter_engine/inference/hypothesis.py +203 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/inference/runner.py +79 -8
- arbiter_engine-0.2.8/arbiter_engine/producers/__init__.py +25 -0
- arbiter_engine-0.2.8/arbiter_engine/producers/baseline_learner.py +163 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/scripts/benchmark_check.py +1 -1
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/surprises.py +100 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/transition_learner.py +7 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/traverser.py +1 -1
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/evidence/alpha1_evidence_pack.md +2 -2
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/evidence/l5_surprise_synthesis.md +3 -3
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/examples/water_tank.yaml +1 -1
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/pyproject.toml +1 -1
- arbiter_engine-0.2.8/tests/test_a_finding_says_where_to_look_next.py +160 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_forecaster_is_judged_by_the_same_eight_axioms.py +1 -1
- arbiter_engine-0.2.8/tests/test_a_posterior_says_which_reading_it_left_out.py +207 -0
- arbiter_engine-0.2.8/tests/test_a_proposal_says_what_adopting_it_would_have_caught.py +192 -0
- arbiter_engine-0.2.8/tests/test_a_vertical_may_adopt_and_this_engine_may_not.py +224 -0
- arbiter_engine-0.2.8/tests/test_the_alpha_figure_comes_from_the_record.py +108 -0
- arbiter_engine-0.2.8/tests/test_the_engine_ships_an_opponent_worth_beating.py +166 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_evidence_floor_is_declared_or_disclosed.py +23 -7
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_stance_page_says_what_no_other_page_says.py +49 -49
- arbiter_engine-0.2.6/.github/PUBLISH_FROM_CI +0 -43
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/.gitattributes +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/.github/workflows/tests.yml +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/.github/workflows/verify-published.yml +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/.github/workflows/verify-tag-artifact.yml +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/.gitignore +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/AI_ATTRIBUTION.md +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/AUTHORS.md +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/BRIDGES.md +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/CODE_OF_CONDUCT.md +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/COMPATIBILITY.md +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/CONTRIBUTING.md +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/LICENSE +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/NOTICE +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/PRIVACY.md +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/ROADMAP.md +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/SECURITY.md +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/SUPPORT.md +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/TRADEMARK.md +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/__init__.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/axiom_thresholds.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/causal/__init__.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/causal/discovery.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/causal/granger.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/causal/leadlag.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/clock.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/derived/__init__.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/derived/indicator.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/derived/parser.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/envelope.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/examples/battery_pack.yaml +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/examples/factory_line.yaml +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/examples/kubernetes_node.yaml +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/examples/margin_book.yaml +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/examples/pump_tank_dynamics.yaml +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/examples/pump_tank_planning.yaml +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/examples/substation_feeder.yaml +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/examples/substation_feeder_surprises.yaml +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/fire_frequency.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/forecast/__init__.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/forecast/contract.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/forecast/envelope.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/forecast/ingest.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/forecast/monitor.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/forecast/shadow.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/history/__init__.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/history/calendar.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/history/observation.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/history/observation_production.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/history/observation_source_wiring.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/history/readiness.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/history/sqlite_store.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/inference/__init__.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/inference/causal.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/inference/ve.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/interfaces.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/mcp/__init__.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/mcp/server.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/__init__.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axiom_verdicts_production.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axioms/__init__.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axioms/boundedness.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axioms/connectivity.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axioms/conservation.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axioms/consistency.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axioms/extensions.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axioms/homeostasis.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axioms/monotonicity.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axioms/peers.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axioms/responsiveness.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axioms/roles.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/axioms/stability.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/domain_loader.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/entail.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/loader.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/prediction_production.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/reasoner.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/ontology/schemas/health_meta_ontology.ttl +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/projection/__init__.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/projection/projector.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/projection/runner.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/propagation/__init__.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/propagation/impact_estimator.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/propagation/lp_confidence.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/propagation/mcts_root_cause.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/propagation/root_cause.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/propagation/weight_learner.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/rca/__init__.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/rca/greedy_set_cover.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/replay.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/residual/__init__.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/residual/predict_vs_mirror.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/residual/sqlite_ledger.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/schema/envelope.schema.json +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/scripts/__init__.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/scripts/surprise_benchmark.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/subenvelope.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/temporal/__init__.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/temporal/temporal_edge.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/temporal/trend_projection.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/__init__.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/action_clears_problem.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/actions.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/builder.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/gap.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/hypothesis_generator.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/hypothesis_production.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/kernel_pipeline_executor.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/monte_carlo_predictor.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/optimization_production.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/pipeline_production.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/planner.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/rollout.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/topology.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/topology_optimizer.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/twin/traverser_production.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/arbiter_engine/types.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/evidence/README.md +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/evidence/customer_deployment_runbook.md +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/evidence/extended_fault_scenarios.md +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/evidence/observability_handoff_guide.md +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/evidence/tech_brief.md +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/evidence/use-case-catalogue.md +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/examples/battery_pack.yaml +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/examples/factory_line.yaml +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/examples/kubernetes_node.yaml +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/examples/margin_book.yaml +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/examples/pump_tank_dynamics.yaml +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/examples/pump_tank_planning.yaml +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/examples/substation_feeder.yaml +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/examples/substation_feeder_surprises.yaml +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/schema/envelope.schema.json +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/conftest.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_balance_may_cross_an_entity_boundary.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_bound_can_belong_to_one_instance.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_calibration_figure_names_its_population.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_calibration_says_how_many_trajectories_it_saw.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_chain_of_lags_says_how_it_was_composed.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_changelog_section_says_whether_you_can_install_it.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_check_that_cannot_run_says_so.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_check_that_declines_is_heard.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_checker_asks_no_entity_type.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_clean_rollout_still_counts_what_it_evaluated.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_companion_beside_the_models_is_not_one.py +0 -0
- {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
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_coupling_block_is_checked_too.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_coupling_is_graded_on_its_own_projections.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_coupling_learns_how_its_projections_fared.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_declared_bad_state_is_not_silent.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_declared_calendar_is_actually_read.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_declared_edge_reaches_the_published_surface.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_declared_floor_is_checked_on_every_path.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_declared_gain_moves_the_downstream_value.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_declared_number_is_the_first_breach.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_declared_offset_waits_for_the_delay.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_declared_source_matches_the_guide.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_declared_spread_reaches_the_value.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_decline_states_the_number_it_computed.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_derived_indicator_is_computed_not_fed.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_discipline_reports_its_own_denominator.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_dropped_declaration_is_not_silent.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_filed_source_says_who_is_not_a_producer.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_forecast_batch_is_filed_or_accounted_for.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_forecast_check_that_refused_says_so_out_loud.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_forecast_is_graded_at_its_horizon.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_forecast_is_measured_against_a_random_walk.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_forecast_is_scored_not_just_stored.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_forecast_keeps_its_doubt.py +0 -0
- {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
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_forecast_states_its_own_distribution.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_forecast_widens_and_says_what_it_assumed.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_freeze_is_found_inside_its_window.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_latency_without_a_threshold_says_so.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_lazy_import_did_not_move_a_name.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_lead_lag_p_value_means_what_it_says.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_learned_gain_is_a_proposal.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_margin_is_measured_against_every_line.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_nested_block_is_checked_too.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_pair_can_beat_the_best_single_action.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_per_instance_bound_reaches_every_reader.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_plan_files_the_row_that_is_a_forecast.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_plan_ranks_only_when_told_how.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_posterior_is_arithmetic_not_assumption.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_prediction_ledger_outlives_the_process.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_projection_declines_rather_than_guessing.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_proposed_spread_says_what_it_assumed.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_ranking_says_how_close_the_call_was.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_reading_can_be_impossible_without_being_extreme.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_refused_block_says_which_rule_it_was_on.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_refused_coupling_is_a_question_not_a_silence.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_response_model_nobody_recognises_is_not_exponential.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_rollout_can_be_graded_later.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_rollout_carries_a_transient_past_the_action_step.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_rollout_steps_the_model_forward.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_second_action_on_a_moved_property_superposes.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_sentence_the_changelog_closed_is_gone.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_set_aside_forecast_says_who_set_it_aside.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_source_pinned_at_zero_passes_no_doubt_on.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_spread_nobody_declared_is_not_a_declared_zero.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_starved_join_says_which_operand_starved.py +0 -0
- {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
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_tie_break_knows_which_side_of_the_line.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_tie_is_broken_by_the_declared_margin.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_transition_into_an_acted_property_still_arrives.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_two_stage_chain_composes_exactly.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_value_is_final_before_anything_reads_it.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_warning_is_a_finding_on_every_surface.py +0 -0
- {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
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_window_cannot_see_past_the_frozen_clock.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_withdrawn_check_is_not_silent.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_a_zero_allowance_still_reports.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_absent_data_regressions.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_agreement_declines_what_it_used_to_guess.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_an_action_may_arrive_as_a_mapping.py +0 -0
- {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
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_an_action_outlives_the_forecast_it_overrides.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_an_action_that_never_runs_says_so.py +0 -0
- {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
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_an_imagined_finding_is_not_a_live_one.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_an_invented_time_course_says_so.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_an_undeclared_transition_projects_nothing.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_closed_reader.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_connectivity_required_property.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_conservation_absent_output.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_cross_signal_consistency.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_decline_contract.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_did_you_mean_is_case_insensitive.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_discovery_proposes_and_never_promotes.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_documented_paths_the_suite_never_ran.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_entailment_derives_and_refuses.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_envelope_schema.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_every_assumption_stamp_has_one_name.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_every_declared_tool_has_a_wrapper.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_every_decline_reason_has_a_producer.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_every_discipline_decline_has_one_name.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_every_forecast_gets_a_yardstick.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_every_reader_takes_the_same_history.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_every_shipped_example_actually_runs.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_every_simulation_decline_has_an_input.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_gated_cell_declines.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_history_outlives_the_process_and_the_weekend.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_homeostasis_setpoint.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_importing_the_package_does_not_pull_an_optional_extra.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_lower_bounds.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_mcp_feeders.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_mcp_roundtrip.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_monotonicity_reversals.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_no_axiom_retires_a_check.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_no_cell_is_judged_twice.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_no_identifier_names_a_private_record.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_no_test_anchors_time_at_import.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_one_declared_spread_is_counted_once.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_one_question_gets_one_projection.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_one_set_of_names_the_model_reads.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_role_comes_from_the_model.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_slow_oscillation.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_axioms_run_over_the_forecast_itself.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_causal_verb_has_a_model_to_run_against.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_clock_can_be_moved.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_config_blocks_are_documented.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_documented_priorities_are_the_computed_ones.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_engine_declares_no_domain_it_does_not_serve.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_engine_invents_no_indicators.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_engine_races_its_own_forecasts.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_engine_says_what_its_approximation_cost.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_engine_scores_its_own_declared_spread.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_engines_own_forecast_is_not_a_producers.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_envelope_legs_are_documented.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_forecasts_leg_says_how_many_were_expected.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_indicator_keys_are_documented.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_ingest_tag_names_the_caller_not_the_funnel.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_lane_cleans_up_after_itself.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_ledger_is_reachable_without_a_deep_import.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_legal_files_ship_together.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_namespaces_point_at_a_graph_that_ships.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_policy_document_and_the_changelog_agree.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_published_cascade_formula_is_the_one_that_runs.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_question_ranking_is_one_scale.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_rate_arm_declines_what_it_used_to_guess.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_readme_decline_count_is_derived.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_readme_name_count_is_derived.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_readme_names_the_forms_load_model_takes.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_rename_table_names_real_things.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_sample_floor_says_whether_it_is_reachable.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_schema_names_every_sub_envelope.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_schema_names_what_a_sub_envelope_carries.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_session_keeps_its_own_ledger.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_verb_that_used_the_number_names_it.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_the_world_model_can_be_exercised_over_mcp.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_threshold_overrides.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_timestamped_ingestion.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_traverse_vocabularies.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_trend_widens_and_does_not_point.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_two_actions_at_two_instants_are_not_one.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_two_bare_series_are_joinable.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_two_claims_on_one_edge_are_two_questions.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_two_offset_couplings_from_one_source_are_both_charged.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_two_plans_that_cost_the_same_compare_equal.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_two_rules_can_close_a_loop_neither_closes_alone.py +0 -0
- {arbiter_engine-0.2.6 → arbiter_engine-0.2.8}/tests/test_two_settings_of_one_property_do_not_add.py +0 -0
- {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
|
|
113
|
-
#
|
|
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
|
-
#
|
|
116
|
-
#
|
|
117
|
-
#
|
|
118
|
-
#
|
|
119
|
-
# already
|
|
120
|
-
#
|
|
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
|
|
130
|
-
"
|
|
131
|
-
"
|
|
132
|
-
"
|
|
133
|
-
"
|
|
134
|
-
"
|
|
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
|
-
|
|
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.
|
|
13
|
-
date-released: "2026-09-
|
|
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.
|
|
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.**
|
|
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
|
|
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
|
|
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.**
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|