arbiter-engine 0.2.3__tar.gz → 0.2.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/.github/workflows/release.yml +3 -3
- arbiter_engine-0.2.6/.github/workflows/tests.yml +292 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/BRIDGES.md +68 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/CHANGELOG.md +1383 -14
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/CITATION.cff +2 -2
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/COMPATIBILITY.md +84 -12
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/MODELING.md +506 -12
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/PKG-INFO +175 -33
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/README.md +174 -32
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/ROADMAP.md +26 -1
- arbiter_engine-0.2.6/STANCE.md +115 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/__init__.py +2 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/api.py +657 -45
- arbiter_engine-0.2.6/arbiter_engine/assumptions.py +282 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/axiom_thresholds.py +1 -1
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/causal/leadlag.py +21 -5
- arbiter_engine-0.2.6/arbiter_engine/examples/pump_tank_dynamics.yaml +132 -0
- arbiter_engine-0.2.6/arbiter_engine/examples/pump_tank_planning.yaml +162 -0
- arbiter_engine-0.2.6/arbiter_engine/examples/substation_feeder.yaml +138 -0
- arbiter_engine-0.2.6/arbiter_engine/examples/substation_feeder_surprises.yaml +120 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/fire_frequency.py +33 -5
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/forecast/contract.py +2 -1
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/forecast/shadow.py +8 -6
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/history/observation_production.py +21 -2
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/inference/runner.py +74 -13
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/interfaces.py +4 -4
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/mcp/server.py +106 -37
- arbiter_engine-0.2.6/arbiter_engine/ontology/__init__.py +72 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/ontology/axioms/homeostasis.py +9 -1
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/ontology/domain_loader.py +382 -16
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/ontology/entail.py +103 -5
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/ontology/loader.py +179 -30
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/ontology/reasoner.py +7 -4
- arbiter_engine-0.2.6/arbiter_engine/ontology/schemas/health_meta_ontology.ttl +260 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/projection/projector.py +12 -1
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/projection/runner.py +41 -4
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/propagation/impact_estimator.py +1 -1
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/residual/predict_vs_mirror.py +490 -82
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6/arbiter_engine}/schema/envelope.schema.json +230 -2
- arbiter_engine-0.2.6/arbiter_engine/scripts/surprise_benchmark.py +167 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/subenvelope.py +107 -31
- arbiter_engine-0.2.6/arbiter_engine/surprises.py +578 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/temporal/temporal_edge.py +56 -6
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/twin/action_clears_problem.py +1 -1
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/twin/actions.py +56 -5
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/twin/builder.py +150 -16
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/twin/hypothesis_generator.py +1 -1
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/twin/hypothesis_production.py +2 -2
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/twin/kernel_pipeline_executor.py +1 -1
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/twin/monte_carlo_predictor.py +33 -50
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/twin/optimization_production.py +2 -2
- arbiter_engine-0.2.6/arbiter_engine/twin/planner.py +850 -0
- arbiter_engine-0.2.6/arbiter_engine/twin/rollout.py +1571 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/twin/topology.py +285 -4
- arbiter_engine-0.2.6/arbiter_engine/twin/transition_learner.py +439 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/twin/traverser.py +840 -57
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/twin/traverser_production.py +2 -2
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/types.py +64 -1
- arbiter_engine-0.2.6/examples/pump_tank_dynamics.yaml +132 -0
- arbiter_engine-0.2.6/examples/pump_tank_planning.yaml +162 -0
- arbiter_engine-0.2.6/examples/substation_feeder.yaml +138 -0
- arbiter_engine-0.2.6/examples/substation_feeder_surprises.yaml +120 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/pyproject.toml +1 -1
- {arbiter_engine-0.2.3/arbiter_engine → arbiter_engine-0.2.6}/schema/envelope.schema.json +230 -2
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/conftest.py +41 -0
- arbiter_engine-0.2.6/tests/test_a_calibration_says_how_many_trajectories_it_saw.py +217 -0
- arbiter_engine-0.2.6/tests/test_a_chain_of_lags_says_how_it_was_composed.py +200 -0
- arbiter_engine-0.2.6/tests/test_a_changelog_section_says_whether_you_can_install_it.py +135 -0
- arbiter_engine-0.2.6/tests/test_a_clean_rollout_still_counts_what_it_evaluated.py +133 -0
- arbiter_engine-0.2.6/tests/test_a_companion_beside_the_models_is_not_one.py +159 -0
- arbiter_engine-0.2.6/tests/test_a_correct_gain_is_not_contradicted_by_a_lagged_series.py +198 -0
- arbiter_engine-0.2.6/tests/test_a_coupling_block_is_checked_too.py +315 -0
- arbiter_engine-0.2.6/tests/test_a_coupling_is_graded_on_its_own_projections.py +249 -0
- arbiter_engine-0.2.6/tests/test_a_coupling_learns_how_its_projections_fared.py +227 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_declared_floor_is_checked_on_every_path.py +6 -5
- arbiter_engine-0.2.6/tests/test_a_declared_offset_waits_for_the_delay.py +125 -0
- arbiter_engine-0.2.6/tests/test_a_declared_source_matches_the_guide.py +81 -0
- arbiter_engine-0.2.6/tests/test_a_declared_spread_reaches_the_value.py +178 -0
- arbiter_engine-0.2.6/tests/test_a_decline_states_the_number_it_computed.py +142 -0
- arbiter_engine-0.2.6/tests/test_a_forecast_is_graded_at_its_horizon.py +180 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_forecast_is_measured_against_a_random_walk.py +10 -2
- arbiter_engine-0.2.6/tests/test_a_forecast_keeps_its_doubt.py +175 -0
- arbiter_engine-0.2.6/tests/test_a_forecast_keeps_its_doubt_when_its_median_stands_still.py +179 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_forecaster_is_judged_by_the_same_eight_axioms.py +31 -20
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_freeze_is_found_inside_its_window.py +18 -3
- arbiter_engine-0.2.6/tests/test_a_lazy_import_did_not_move_a_name.py +257 -0
- arbiter_engine-0.2.6/tests/test_a_margin_is_measured_against_every_line.py +168 -0
- arbiter_engine-0.2.6/tests/test_a_pair_can_beat_the_best_single_action.py +228 -0
- arbiter_engine-0.2.6/tests/test_a_plan_files_the_row_that_is_a_forecast.py +229 -0
- arbiter_engine-0.2.6/tests/test_a_proposed_spread_says_what_it_assumed.py +183 -0
- arbiter_engine-0.2.6/tests/test_a_ranking_says_how_close_the_call_was.py +181 -0
- arbiter_engine-0.2.6/tests/test_a_refused_block_says_which_rule_it_was_on.py +119 -0
- arbiter_engine-0.2.6/tests/test_a_refused_coupling_is_a_question_not_a_silence.py +311 -0
- arbiter_engine-0.2.6/tests/test_a_response_model_nobody_recognises_is_not_exponential.py +220 -0
- arbiter_engine-0.2.6/tests/test_a_rollout_can_be_graded_later.py +269 -0
- arbiter_engine-0.2.6/tests/test_a_rollout_carries_a_transient_past_the_action_step.py +260 -0
- arbiter_engine-0.2.6/tests/test_a_second_action_on_a_moved_property_superposes.py +182 -0
- arbiter_engine-0.2.6/tests/test_a_sentence_the_changelog_closed_is_gone.py +111 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_set_aside_forecast_says_who_set_it_aside.py +3 -3
- arbiter_engine-0.2.6/tests/test_a_source_pinned_at_zero_passes_no_doubt_on.py +101 -0
- arbiter_engine-0.2.6/tests/test_a_spread_nobody_declared_is_not_a_declared_zero.py +137 -0
- arbiter_engine-0.2.6/tests/test_a_surprise_the_store_never_saw_is_not_a_miss.py +411 -0
- arbiter_engine-0.2.6/tests/test_a_tie_break_knows_which_side_of_the_line.py +178 -0
- arbiter_engine-0.2.6/tests/test_a_tie_is_broken_by_the_declared_margin.py +189 -0
- arbiter_engine-0.2.6/tests/test_a_transition_into_an_acted_property_still_arrives.py +184 -0
- arbiter_engine-0.2.6/tests/test_a_two_stage_chain_composes_exactly.py +196 -0
- arbiter_engine-0.2.6/tests/test_a_value_is_final_before_anything_reads_it.py +178 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_warning_is_a_finding_on_every_surface.py +1 -1
- arbiter_engine-0.2.6/tests/test_a_what_if_is_evaluated_at_the_horizon_it_asked_for.py +131 -0
- arbiter_engine-0.2.6/tests/test_an_action_may_arrive_as_a_mapping.py +134 -0
- arbiter_engine-0.2.6/tests/test_an_action_on_a_coupled_property_reads_the_value_it_has.py +285 -0
- arbiter_engine-0.2.6/tests/test_an_action_outlives_the_forecast_it_overrides.py +223 -0
- arbiter_engine-0.2.6/tests/test_an_action_that_never_runs_says_so.py +326 -0
- arbiter_engine-0.2.6/tests/test_an_imagined_breach_is_not_a_live_one_in_the_telemetry.py +113 -0
- arbiter_engine-0.2.6/tests/test_an_invented_time_course_says_so.py +252 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_an_undeclared_transition_projects_nothing.py +13 -3
- arbiter_engine-0.2.6/tests/test_every_assumption_stamp_has_one_name.py +210 -0
- arbiter_engine-0.2.6/tests/test_every_declared_tool_has_a_wrapper.py +117 -0
- arbiter_engine-0.2.6/tests/test_every_discipline_decline_has_one_name.py +168 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_every_shipped_example_actually_runs.py +99 -2
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_every_simulation_decline_has_an_input.py +277 -2
- arbiter_engine-0.2.6/tests/test_importing_the_package_does_not_pull_an_optional_extra.py +185 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_mcp_roundtrip.py +15 -1
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_no_cell_is_judged_twice.py +2 -1
- arbiter_engine-0.2.6/tests/test_no_test_anchors_time_at_import.py +132 -0
- arbiter_engine-0.2.6/tests/test_one_declared_spread_is_counted_once.py +470 -0
- arbiter_engine-0.2.6/tests/test_one_question_gets_one_projection.py +168 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_role_comes_from_the_model.py +1 -1
- arbiter_engine-0.2.6/tests/test_the_causal_verb_has_a_model_to_run_against.py +187 -0
- arbiter_engine-0.2.6/tests/test_the_engine_declares_no_domain_it_does_not_serve.py +114 -0
- arbiter_engine-0.2.6/tests/test_the_engine_races_its_own_forecasts.py +263 -0
- arbiter_engine-0.2.6/tests/test_the_engine_says_what_its_approximation_cost.py +267 -0
- arbiter_engine-0.2.6/tests/test_the_engine_scores_its_own_declared_spread.py +281 -0
- arbiter_engine-0.2.6/tests/test_the_evidence_floor_is_declared_or_disclosed.py +289 -0
- arbiter_engine-0.2.6/tests/test_the_ingest_tag_names_the_caller_not_the_funnel.py +158 -0
- arbiter_engine-0.2.6/tests/test_the_lane_cleans_up_after_itself.py +103 -0
- arbiter_engine-0.2.6/tests/test_the_ledger_is_reachable_without_a_deep_import.py +171 -0
- arbiter_engine-0.2.6/tests/test_the_namespaces_point_at_a_graph_that_ships.py +232 -0
- arbiter_engine-0.2.6/tests/test_the_policy_document_and_the_changelog_agree.py +134 -0
- arbiter_engine-0.2.6/tests/test_the_published_cascade_formula_is_the_one_that_runs.py +184 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_the_rate_arm_declines_what_it_used_to_guess.py +15 -2
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_the_readme_name_count_is_derived.py +19 -11
- arbiter_engine-0.2.6/tests/test_the_readme_names_the_forms_load_model_takes.py +115 -0
- arbiter_engine-0.2.6/tests/test_the_schema_names_every_sub_envelope.py +123 -0
- arbiter_engine-0.2.6/tests/test_the_schema_names_what_a_sub_envelope_carries.py +195 -0
- arbiter_engine-0.2.6/tests/test_the_stance_page_says_what_no_other_page_says.py +284 -0
- arbiter_engine-0.2.6/tests/test_the_verb_that_used_the_number_names_it.py +182 -0
- arbiter_engine-0.2.6/tests/test_the_world_model_can_be_exercised_over_mcp.py +237 -0
- arbiter_engine-0.2.6/tests/test_trend_widens_and_does_not_point.py +145 -0
- arbiter_engine-0.2.6/tests/test_two_actions_at_two_instants_are_not_one.py +233 -0
- arbiter_engine-0.2.6/tests/test_two_bare_series_are_joinable.py +170 -0
- arbiter_engine-0.2.6/tests/test_two_claims_on_one_edge_are_two_questions.py +149 -0
- arbiter_engine-0.2.6/tests/test_two_offset_couplings_from_one_source_are_both_charged.py +213 -0
- arbiter_engine-0.2.6/tests/test_two_plans_that_cost_the_same_compare_equal.py +172 -0
- arbiter_engine-0.2.6/tests/test_two_rules_can_close_a_loop_neither_closes_alone.py +166 -0
- arbiter_engine-0.2.6/tests/test_two_settings_of_one_property_do_not_add.py +262 -0
- arbiter_engine-0.2.3/.github/workflows/tests.yml +0 -116
- arbiter_engine-0.2.3/arbiter_engine/ontology/__init__.py +0 -18
- arbiter_engine-0.2.3/arbiter_engine/twin/planner.py +0 -420
- arbiter_engine-0.2.3/arbiter_engine/twin/rollout.py +0 -426
- arbiter_engine-0.2.3/arbiter_engine/twin/transition_learner.py +0 -223
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/.gitattributes +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/.github/PUBLISH_FROM_CI +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/.github/workflows/verify-published.yml +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/.github/workflows/verify-tag-artifact.yml +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/.gitignore +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/AI_ATTRIBUTION.md +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/AUTHORS.md +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/CODE_OF_CONDUCT.md +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/CONTRIBUTING.md +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/LICENSE +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/NOTICE +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/PRIVACY.md +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/SECURITY.md +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/SUPPORT.md +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/TRADEMARK.md +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/causal/__init__.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/causal/discovery.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/causal/granger.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/clock.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/derived/__init__.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/derived/indicator.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/derived/parser.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/envelope.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/examples/battery_pack.yaml +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/examples/factory_line.yaml +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/examples/kubernetes_node.yaml +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/examples/margin_book.yaml +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/examples/water_tank.yaml +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/forecast/__init__.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/forecast/envelope.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/forecast/ingest.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/forecast/monitor.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/history/__init__.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/history/calendar.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/history/observation.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/history/observation_source_wiring.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/history/readiness.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/history/sqlite_store.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/inference/__init__.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/inference/causal.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/inference/ve.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/mcp/__init__.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/ontology/axiom_verdicts_production.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/ontology/axioms/__init__.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/ontology/axioms/boundedness.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/ontology/axioms/connectivity.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/ontology/axioms/conservation.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/ontology/axioms/consistency.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/ontology/axioms/extensions.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/ontology/axioms/monotonicity.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/ontology/axioms/peers.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/ontology/axioms/responsiveness.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/ontology/axioms/roles.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/ontology/axioms/stability.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/ontology/prediction_production.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/projection/__init__.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/propagation/__init__.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/propagation/lp_confidence.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/propagation/mcts_root_cause.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/propagation/root_cause.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/propagation/weight_learner.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/rca/__init__.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/rca/greedy_set_cover.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/replay.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/residual/__init__.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/residual/sqlite_ledger.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/scripts/__init__.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/scripts/benchmark_check.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/temporal/__init__.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/temporal/trend_projection.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/twin/__init__.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/twin/gap.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/twin/pipeline_production.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/arbiter_engine/twin/topology_optimizer.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/evidence/README.md +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/evidence/alpha1_evidence_pack.md +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/evidence/customer_deployment_runbook.md +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/evidence/extended_fault_scenarios.md +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/evidence/l5_surprise_synthesis.md +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/evidence/observability_handoff_guide.md +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/evidence/tech_brief.md +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/evidence/use-case-catalogue.md +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/examples/battery_pack.yaml +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/examples/factory_line.yaml +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/examples/kubernetes_node.yaml +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/examples/margin_book.yaml +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/examples/water_tank.yaml +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_balance_may_cross_an_entity_boundary.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_bound_can_belong_to_one_instance.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_calibration_figure_names_its_population.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_check_that_cannot_run_says_so.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_check_that_declines_is_heard.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_checker_asks_no_entity_type.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_declared_bad_state_is_not_silent.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_declared_calendar_is_actually_read.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_declared_edge_reaches_the_published_surface.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_declared_gain_moves_the_downstream_value.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_declared_number_is_the_first_breach.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_derived_indicator_is_computed_not_fed.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_discipline_reports_its_own_denominator.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_dropped_declaration_is_not_silent.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_filed_source_says_who_is_not_a_producer.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_forecast_batch_is_filed_or_accounted_for.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_forecast_check_that_refused_says_so_out_loud.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_forecast_is_scored_not_just_stored.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_forecast_states_its_own_distribution.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_forecast_widens_and_says_what_it_assumed.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_latency_without_a_threshold_says_so.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_lead_lag_p_value_means_what_it_says.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_learned_gain_is_a_proposal.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_nested_block_is_checked_too.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_per_instance_bound_reaches_every_reader.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_plan_ranks_only_when_told_how.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_posterior_is_arithmetic_not_assumption.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_prediction_ledger_outlives_the_process.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_projection_declines_rather_than_guessing.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_reading_can_be_impossible_without_being_extreme.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_rollout_steps_the_model_forward.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_starved_join_says_which_operand_starved.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_window_cannot_see_past_the_frozen_clock.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_withdrawn_check_is_not_silent.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_a_zero_allowance_still_reports.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_absent_data_regressions.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_agreement_declines_what_it_used_to_guess.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_an_imagined_finding_is_not_a_live_one.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_closed_reader.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_connectivity_required_property.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_conservation_absent_output.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_cross_signal_consistency.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_decline_contract.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_did_you_mean_is_case_insensitive.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_discovery_proposes_and_never_promotes.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_documented_paths_the_suite_never_ran.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_entailment_derives_and_refuses.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_envelope_schema.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_every_decline_reason_has_a_producer.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_every_forecast_gets_a_yardstick.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_every_reader_takes_the_same_history.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_gated_cell_declines.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_history_outlives_the_process_and_the_weekend.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_homeostasis_setpoint.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_lower_bounds.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_mcp_feeders.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_monotonicity_reversals.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_no_axiom_retires_a_check.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_no_identifier_names_a_private_record.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_one_set_of_names_the_model_reads.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_slow_oscillation.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_the_axioms_run_over_the_forecast_itself.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_the_clock_can_be_moved.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_the_config_blocks_are_documented.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_the_documented_priorities_are_the_computed_ones.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_the_engine_invents_no_indicators.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_the_engines_own_forecast_is_not_a_producers.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_the_envelope_legs_are_documented.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_the_forecasts_leg_says_how_many_were_expected.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_the_indicator_keys_are_documented.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_the_legal_files_ship_together.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_the_question_ranking_is_one_scale.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_the_readme_decline_count_is_derived.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_the_rename_table_names_real_things.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_the_sample_floor_says_whether_it_is_reachable.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_the_session_keeps_its_own_ledger.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_threshold_overrides.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_timestamped_ingestion.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_traverse_vocabularies.py +0 -0
- {arbiter_engine-0.2.3 → arbiter_engine-0.2.6}/tests/test_unread_properties.py +0 -0
|
@@ -154,9 +154,9 @@ jobs:
|
|
|
154
154
|
# upload is the one that cannot be taken back, and a version number on this
|
|
155
155
|
# index can never be reused.
|
|
156
156
|
#
|
|
157
|
-
# That division is the repository's own
|
|
158
|
-
# words: it builds and verifies, it does not
|
|
159
|
-
# step stays with the operator. Automating the upload would have removed that
|
|
157
|
+
# That division is the repository's own, and the tooling that derives this
|
|
158
|
+
# package says it in as many words: it builds and verifies, it does not
|
|
159
|
+
# push, because the irreversible step stays with the operator. Automating the upload would have removed that
|
|
160
160
|
# division; the approval gate is what puts it back.
|
|
161
161
|
# -------------------------------------------------------------------------
|
|
162
162
|
publish:
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
# The engine's own suite, on every change.
|
|
2
|
+
#
|
|
3
|
+
# The sibling workflow verifies the PUBLISHED package on a schedule; this one
|
|
4
|
+
# is the gate on the way in. Until it existed the package shipped no tests at
|
|
5
|
+
# all, and every regression guard it had lived in a downstream consumer's
|
|
6
|
+
# integration suite -- which meant the engine's protection depended on somebody
|
|
7
|
+
# else's project continuing to exist, and a defect reached six releases and
|
|
8
|
+
# seven issues before anybody upstream could have seen it.
|
|
9
|
+
#
|
|
10
|
+
# THREE LESSONS ARE PRE-APPLIED HERE, each of which cost a real defect in a
|
|
11
|
+
# project that consumes this one. They are the reason this file is longer than
|
|
12
|
+
# `run pytest`.
|
|
13
|
+
#
|
|
14
|
+
# NOTE ON FORMATTING: no hanging indents in these comments. The publication
|
|
15
|
+
# path collapses leading whitespace inside a config-file comment, so an
|
|
16
|
+
# indented continuation would arrive here looking different from how it was
|
|
17
|
+
# written -- and the check that compares the two is worth more than the
|
|
18
|
+
# indent.
|
|
19
|
+
#
|
|
20
|
+
# 1. pytest is installed EXPLICITLY. A CI step that installs nothing runs a
|
|
21
|
+
# bare interpreter. The consuming project's checks job was red on every push
|
|
22
|
+
# for months of subjective time because the runner had no pytest, so no test
|
|
23
|
+
# ever ran server-side -- and nobody reads a job that has never been green.
|
|
24
|
+
#
|
|
25
|
+
# 2. EXIT CODE 5 FAILS. pytest exits 5 when it collects nothing, and a module
|
|
26
|
+
# that skips at import collects nothing. That is the permissive value, and
|
|
27
|
+
# leaving it permissive is how a canary job stayed green for four runs having
|
|
28
|
+
# executed zero tests. "No tests ran" is precisely the hole this workflow
|
|
29
|
+
# exists to close, so it is spelled as a failure below rather than left to a
|
|
30
|
+
# shell's default.
|
|
31
|
+
#
|
|
32
|
+
# 3. THE MATRIX REACHES 3.12. `datetime.utcnow()` gained its DeprecationWarning
|
|
33
|
+
# in 3.12, and `filterwarnings = error::DeprecationWarning` in pyproject.toml
|
|
34
|
+
# is inert below it. A green run on the 3.10 floor proves nothing about that
|
|
35
|
+
# gate; a run that never left 3.10 would report a passing check for a rule that
|
|
36
|
+
# had not been evaluated. 3.10 is here because it is the declared floor, not
|
|
37
|
+
# because it tests the warning.
|
|
38
|
+
|
|
39
|
+
name: tests
|
|
40
|
+
|
|
41
|
+
# NO BRANCH FILTER, and that is the fix rather than the shortcut. The first
|
|
42
|
+
# version read `branches: [main]` and this repository publishes on `master`, so
|
|
43
|
+
# the job was registered, valid, and unable to fire on a push -- zero runs,
|
|
44
|
+
# nothing red, nothing to read. This file's own header argues that a job nobody
|
|
45
|
+
# reads is worse than none; a job that cannot run is worse still, because it
|
|
46
|
+
# looks like coverage from every angle except the one that counts.
|
|
47
|
+
#
|
|
48
|
+
# A branch name here would be a second copy of a fact that lives in the
|
|
49
|
+
# publishing procedure, and the two would drift exactly once, silently. There
|
|
50
|
+
# is one branch; matching every push cannot be wrong about which.
|
|
51
|
+
on:
|
|
52
|
+
push:
|
|
53
|
+
pull_request:
|
|
54
|
+
workflow_dispatch:
|
|
55
|
+
|
|
56
|
+
permissions:
|
|
57
|
+
contents: read
|
|
58
|
+
|
|
59
|
+
jobs:
|
|
60
|
+
suite:
|
|
61
|
+
runs-on: ubuntu-latest
|
|
62
|
+
strategy:
|
|
63
|
+
fail-fast: false
|
|
64
|
+
matrix:
|
|
65
|
+
python-version: ['3.10', '3.12', '3.13']
|
|
66
|
+
|
|
67
|
+
steps:
|
|
68
|
+
- uses: actions/checkout@v4
|
|
69
|
+
|
|
70
|
+
- uses: actions/setup-python@v5
|
|
71
|
+
with:
|
|
72
|
+
python-version: ${{ matrix.python-version }}
|
|
73
|
+
|
|
74
|
+
# The package, not the working tree. `pytest` resolves `arbiter_engine`
|
|
75
|
+
# from site-packages, so this exercises what a user installs -- a module
|
|
76
|
+
# left out of the wheel fails here rather than in their traceback.
|
|
77
|
+
#
|
|
78
|
+
# The `mcp` extra is installed deliberately. The transport binding is
|
|
79
|
+
# skipped without it, and a component whose only test is skipped
|
|
80
|
+
# everywhere wears the same green as one that is covered. That shim
|
|
81
|
+
# already shipped once having never been executed.
|
|
82
|
+
#
|
|
83
|
+
# `jsonschema` is installed for the same reason, and it took an
|
|
84
|
+
# outside reader to notice that the paragraph above stopped one line
|
|
85
|
+
# short of it. TEN tests gate on that import, and until now no lane
|
|
86
|
+
# installed it: this job ran `.[mcp]` and pytest, and the reproduction
|
|
87
|
+
# our own documents imply runs numpy, pyyaml and pytest. So the
|
|
88
|
+
# machine-readable contract that `meta.schema_version` advertises had
|
|
89
|
+
# never been put in front of a validator here -- including the single
|
|
90
|
+
# check that `schema/envelope.schema.json` parses as a 2020-12 schema at
|
|
91
|
+
# all, which has no derivation-based substitute and skipped in silence
|
|
92
|
+
# through every release. It is a TEST requirement and not a dependency:
|
|
93
|
+
# the engine still runs on numpy and pyyaml, and the pin below is what
|
|
94
|
+
# keeps that true.
|
|
95
|
+
#
|
|
96
|
+
# `rdf` joined `mcp` on 2026-09-23, for the same reason `jsonschema` is on
|
|
97
|
+
# the line below it. The extra is ADVERTISED in `pyproject.toml`, so
|
|
98
|
+
# `pip install arbiter-engine[rdf]` is a supported install -- and no lane
|
|
99
|
+
# had ever installed it, so the whole RDF path ran nowhere and the one
|
|
100
|
+
# graph the loader's namespaces refer to was never loaded by anything.
|
|
101
|
+
# That is the same defect this step already carries a paragraph about:
|
|
102
|
+
# a dependency a caller is invited to install, exercised on no lane.
|
|
103
|
+
#
|
|
104
|
+
# 4. pytest IS RANGE-PINNED, and the range is a claim this lane has
|
|
105
|
+
# tested. It was unpinned until 2026-09-24, so a fresh runner resolved
|
|
106
|
+
# whatever was newest that morning. pytest 9.1 deprecated a class-scoped
|
|
107
|
+
# fixture written as an instance method; `filterwarnings =
|
|
108
|
+
# error:DeprecationWarning` in pyproject.toml turns that into an ERROR;
|
|
109
|
+
# and one file in this suite used the pattern. The three together made
|
|
110
|
+
# the published lane go red with nothing in the tree having changed --
|
|
111
|
+
# green on a runner with an older cached pytest, red on a fresh one. The
|
|
112
|
+
# same *true where I stood, false where it is read* shape the release
|
|
113
|
+
# checks already close on the tree, arriving on the test RUNNER instead.
|
|
114
|
+
# The floor is where the suite is verified; the ceiling is the next
|
|
115
|
+
# major, which the canary job below reaches on purpose.
|
|
116
|
+
- name: Install the package and the suite's requirements
|
|
117
|
+
run: |
|
|
118
|
+
python -m pip install --upgrade pip
|
|
119
|
+
python -m pip install .[mcp,rdf]
|
|
120
|
+
python -m pip install 'pytest>=8,<10' jsonschema
|
|
121
|
+
|
|
122
|
+
# NAMES THE VERSION IT MEASURED. A range says what is allowed; the log
|
|
123
|
+
# has to say what actually ran, or a reader of a green check cannot tell
|
|
124
|
+
# which end of the range produced it.
|
|
125
|
+
- name: Say which pytest this run used
|
|
126
|
+
run: python -m pytest --version
|
|
127
|
+
|
|
128
|
+
# `set +e` is load-bearing, not tidiness. GitHub runs `run:` steps under
|
|
129
|
+
# `bash -e`, so a failing pytest would end the step at that line and the
|
|
130
|
+
# exit-5 branch below would never execute -- a handler that reads
|
|
131
|
+
# correctly and cannot run. Verified by running it, because reading it
|
|
132
|
+
# was how it looked fine.
|
|
133
|
+
#
|
|
134
|
+
# `-rs` prints the reason for every skip, and the output is
|
|
135
|
+
# TEE'd so the step after can read this run's summary instead of
|
|
136
|
+
# producing another one. Two reasons, and the second is the real one:
|
|
137
|
+
# a second run costs twenty seconds per matrix entry, and it grades a
|
|
138
|
+
# DIFFERENT EXECUTION than the one this job just accepted.
|
|
139
|
+
#
|
|
140
|
+
# `${PIPESTATUS[0]}`, not `$?`. Through a pipe, `$?` is tee's status --
|
|
141
|
+
# tee succeeds when pytest fails, so the naive form turns every red
|
|
142
|
+
# suite green and the exit-5 branch below never fires.
|
|
143
|
+
- name: Run the suite, and fail if it ran nothing
|
|
144
|
+
run: |
|
|
145
|
+
set +e
|
|
146
|
+
pytest -q -rs --tb=short | tee "${RUNNER_TEMP:-/tmp}/pytest-summary.txt"
|
|
147
|
+
rc=${PIPESTATUS[0]}
|
|
148
|
+
if [ "$rc" -eq 5 ]; then
|
|
149
|
+
echo "::error::pytest exited 5 -- it collected no tests. A suite that runs nothing reports the same green as one that passes."
|
|
150
|
+
exit 1
|
|
151
|
+
fi
|
|
152
|
+
exit "$rc"
|
|
153
|
+
|
|
154
|
+
# Asserts the outcome, not the mechanism. The step above could pass with
|
|
155
|
+
# a handful of tests if collection silently narrowed, so the count is
|
|
156
|
+
# read back and held against a floor. A bare count would be a number to
|
|
157
|
+
# maintain; a floor only ever goes red when coverage SHRINKS.
|
|
158
|
+
- name: The suite is not quietly shrinking
|
|
159
|
+
run: |
|
|
160
|
+
set +e
|
|
161
|
+
COLLECTED=$(pytest --collect-only -q 2>/dev/null | tail -1 | grep -oE '^[0-9]+')
|
|
162
|
+
echo "collected: $COLLECTED"
|
|
163
|
+
if [ -z "$COLLECTED" ] || [ "$COLLECTED" -lt 60 ]; then
|
|
164
|
+
echo "::error::collected ${COLLECTED:-0} tests; the suite has lost coverage"
|
|
165
|
+
exit 1
|
|
166
|
+
fi
|
|
167
|
+
|
|
168
|
+
# and the mirror image of the step above. A floor on COLLECTED
|
|
169
|
+
# catches a suite that shrinks; nothing caught a suite that goes QUIET,
|
|
170
|
+
# and going quiet is what actually happened -- ten tests turned into
|
|
171
|
+
# skips when an optional import went missing, and the pass count moved
|
|
172
|
+
# by ten in a number nobody reads to the digit.
|
|
173
|
+
#
|
|
174
|
+
# THE CEILING IS MEASURED, not chosen. With the package installed, the
|
|
175
|
+
# skips that remain are structural: three axioms declare a floor of one
|
|
176
|
+
# and have no below-the-floor case to construct, and two parametrized
|
|
177
|
+
# tests receive an empty axiom set. That is five. Without the package
|
|
178
|
+
# installed four more appear, which is nine, and nine is the ceiling so
|
|
179
|
+
# that a job on a runner that resolves the install differently does not
|
|
180
|
+
# go red for a reason that is not this one.
|
|
181
|
+
#
|
|
182
|
+
# WHAT IT CANNOT SEE: one test going quiet. A tier is what this catches
|
|
183
|
+
# -- losing `jsonschema` again puts the count at fifteen. Losing the
|
|
184
|
+
# `mcp` binding puts it at six and passes here, which is why that extra
|
|
185
|
+
# is pinned in the install rather than watched from here.
|
|
186
|
+
#
|
|
187
|
+
# It reads the GRADED run's summary rather than running the
|
|
188
|
+
# suite again. The first version ran it a second time, which measured
|
|
189
|
+
# twenty seconds per matrix entry and, worse, asked its question of an
|
|
190
|
+
# execution this job had never accepted.
|
|
191
|
+
#
|
|
192
|
+
# AND IT REFUSES WHEN IT CANNOT ANSWER. A missing or unrecognisable
|
|
193
|
+
# summary used to leave `SKIPPED` defaulting to zero, which is the
|
|
194
|
+
# failure mode this whole step exists to catch, one level up: a check
|
|
195
|
+
# that cannot see anything reporting the same green as one that looked.
|
|
196
|
+
- name: The suite is not quietly going skipped
|
|
197
|
+
run: |
|
|
198
|
+
set +e
|
|
199
|
+
SUMMARY=$(tail -1 "${RUNNER_TEMP:-/tmp}/pytest-summary.txt" 2>/dev/null)
|
|
200
|
+
if ! echo "$SUMMARY" | grep -qE '[0-9]+ (passed|failed|error)'; then
|
|
201
|
+
echo "::error::no pytest summary from the graded run, so this check cannot answer -- and a check that cannot answer must not pass."
|
|
202
|
+
exit 1
|
|
203
|
+
fi
|
|
204
|
+
echo "summary: $SUMMARY"
|
|
205
|
+
SKIPPED=$(echo "$SUMMARY" | grep -oE '[0-9]+ skipped' | grep -oE '^[0-9]+')
|
|
206
|
+
SKIPPED=${SKIPPED:-0}
|
|
207
|
+
echo "skipped: $SKIPPED"
|
|
208
|
+
if [ "$SKIPPED" -gt 9 ]; then
|
|
209
|
+
echo "::error::$SKIPPED tests skipped; a tier of the suite has gone quiet. The reasons are in the run step above -- an optional import that stops resolving takes its whole tier with it and reports the same green."
|
|
210
|
+
exit 1
|
|
211
|
+
fi
|
|
212
|
+
|
|
213
|
+
# The step above COUNTS; this one NAMES. A ceiling cannot see a
|
|
214
|
+
# swap -- one test going quiet while another starts passing leaves the
|
|
215
|
+
# number exactly where it was -- and the comment above already says what a
|
|
216
|
+
# single quiet test costs here: losing the `mcp` binding puts the count at
|
|
217
|
+
# six and passes.
|
|
218
|
+
#
|
|
219
|
+
# An outside report then measured exactly six against this commit, on this
|
|
220
|
+
# install recipe, and nothing this project ships could say which test it
|
|
221
|
+
# was. The only SINGLE-test optional import in the suite is that binding:
|
|
222
|
+
# `jsonschema` gates ten and `yaml` gates whole modules, so six is not a
|
|
223
|
+
# number the other two can produce. The SDK binding had almost certainly
|
|
224
|
+
# gone unrun again -- and *almost certainly* is the wrong grade for a
|
|
225
|
+
# component that already shipped once having never been executed.
|
|
226
|
+
#
|
|
227
|
+
# KEYED ON THE FILE, not the line. Line numbers move whenever a file is
|
|
228
|
+
# edited, and a guard going red for an edit above the skip teaches people
|
|
229
|
+
# to update it without reading it. WHAT THAT COSTS, written down rather
|
|
230
|
+
# than left to be discovered: two tests trading places inside ONE file are
|
|
231
|
+
# invisible here. Anything arriving, leaving, or moving between files is
|
|
232
|
+
# named.
|
|
233
|
+
#
|
|
234
|
+
# It reads the GRADED run's summary, for the reason the step above gives.
|
|
235
|
+
- name: The skips are the ones we expect, by name
|
|
236
|
+
run: |
|
|
237
|
+
set +e
|
|
238
|
+
SUMMARY_FILE="${RUNNER_TEMP:-/tmp}/pytest-summary.txt"
|
|
239
|
+
if [ ! -s "$SUMMARY_FILE" ]; then
|
|
240
|
+
echo "::error::no summary from the graded run, so the skip set cannot be read -- and a check that cannot answer must not pass."
|
|
241
|
+
exit 1
|
|
242
|
+
fi
|
|
243
|
+
EXPECTED=$(printf '%s\n' \
|
|
244
|
+
"3 tests/test_absent_data_regressions.py" \
|
|
245
|
+
"2 tests/test_threshold_overrides.py")
|
|
246
|
+
ACTUAL=$(awk '/^SKIPPED \[[0-9]+\]/ {
|
|
247
|
+
n = $2; gsub(/[^0-9]/, "", n);
|
|
248
|
+
split($3, part, ":"); count[part[1]] += n
|
|
249
|
+
}
|
|
250
|
+
END { for (f in count) printf "%d %s\n", count[f], f }' \
|
|
251
|
+
"$SUMMARY_FILE" | sort -k2)
|
|
252
|
+
echo "expected skips:"; printf '%s\n' "$EXPECTED"
|
|
253
|
+
echo "actual skips:"; printf '%s\n' "$ACTUAL"
|
|
254
|
+
if [ "$EXPECTED" != "$ACTUAL" ]; then
|
|
255
|
+
echo "::error::the skip set moved. Lines with < are expected and absent; lines with > are skipping and were not expected to. A test that starts skipping stops being evidence while still counting as collected."
|
|
256
|
+
diff <(printf '%s\n' "$EXPECTED") <(printf '%s\n' "$ACTUAL")
|
|
257
|
+
exit 1
|
|
258
|
+
fi
|
|
259
|
+
|
|
260
|
+
# THE CEILING, REACHED ON PURPOSE RATHER THAN HIT BY SURPRISE.
|
|
261
|
+
#
|
|
262
|
+
# The job above pins pytest below the next major so the gate is a gate. That
|
|
263
|
+
# alone would reproduce the defect it was written for one major later: a
|
|
264
|
+
# lane that never sees a new pytest cannot tell you a new pytest breaks it,
|
|
265
|
+
# and the reason the 9.1 errors arrived unannounced is that nothing here had
|
|
266
|
+
# ever run anything but whatever was newest.
|
|
267
|
+
#
|
|
268
|
+
# So one job installs the newest, on one interpreter, and is ALLOWED TO
|
|
269
|
+
# FAIL. Its red is a notice, not a gate: it says the range in the job above
|
|
270
|
+
# is now a claim about the past, and somebody should widen it deliberately
|
|
271
|
+
# after reading what moved. A gate that goes red for a reason nobody chose
|
|
272
|
+
# gets switched off; a notice that does is doing its job.
|
|
273
|
+
newest-pytest:
|
|
274
|
+
runs-on: ubuntu-latest
|
|
275
|
+
continue-on-error: true
|
|
276
|
+
steps:
|
|
277
|
+
- uses: actions/checkout@v4
|
|
278
|
+
- uses: actions/setup-python@v5
|
|
279
|
+
with:
|
|
280
|
+
python-version: '3.13'
|
|
281
|
+
- run: |
|
|
282
|
+
python -m pip install --upgrade pip
|
|
283
|
+
python -m pip install .[mcp,rdf]
|
|
284
|
+
python -m pip install --upgrade pytest jsonschema
|
|
285
|
+
- name: Say which pytest this run used
|
|
286
|
+
run: python -m pytest --version
|
|
287
|
+
# No exit-5 handling and no skip-set comparison: this lane is not the
|
|
288
|
+
# grade. It answers one question -- does the suite still pass on a
|
|
289
|
+
# pytest the pinned range excludes -- and anything more would be a
|
|
290
|
+
# second copy of the job above, drifting from it.
|
|
291
|
+
- name: The suite, on a pytest the gate does not admit
|
|
292
|
+
run: python -m pytest tests/ -q
|
|
@@ -265,6 +265,74 @@ one is inferred from an unknown.
|
|
|
265
265
|
|
|
266
266
|
---
|
|
267
267
|
|
|
268
|
+
## 2a. The discipline vocabularies, which are not that one
|
|
269
|
+
|
|
270
|
+
Sec. 2 is titled *the decline vocabulary* and there are eight of them. The
|
|
271
|
+
fourteen above are the ones `check` uses to refuse an axiom evaluation. Each
|
|
272
|
+
sub-envelope -- `simulation`, `shadow`, `projection`, `discovery`,
|
|
273
|
+
`entailment`, `inference`, `forecasts` -- refuses out of its OWN closed set.
|
|
274
|
+
`COMPATIBILITY.md` says so, warns that reading a reason from one set against
|
|
275
|
+
another is how a closed enum stops being closed, and grants a patch release
|
|
276
|
+
permission to add a member to any of them.
|
|
277
|
+
|
|
278
|
+
**Until now no document said what they contain.** A reader told the sets are
|
|
279
|
+
separate, told not to mix them, and told they may grow had no way to see one,
|
|
280
|
+
and this guide -- the one that calls a decline vocabulary a requirements
|
|
281
|
+
document -- named only the fourteen.
|
|
282
|
+
|
|
283
|
+
What that costs is measurable. An outside comparison written in September 2026
|
|
284
|
+
reproduced every vocabulary this project had published -- the fourteen above,
|
|
285
|
+
the six gap types, the eight raced outcomes, the twenty assumption stamps -- by
|
|
286
|
+
exact membership. Its own table of *the closed vocabularies* then listed five
|
|
287
|
+
sets and none of these seven, and three members of the `simulation` set turned
|
|
288
|
+
up in its prose instead, beside a gap type, in a list read against the
|
|
289
|
+
fourteen. That is precisely the mistake `COMPATIBILITY.md` warns against, made
|
|
290
|
+
by a reader who got everything else exactly right, because what they needed in
|
|
291
|
+
order to avoid it was not published.
|
|
292
|
+
|
|
293
|
+
Ninety-three names across seven sets. Each row below is complete: what it folds
|
|
294
|
+
in, plus what is its own, is the whole set.
|
|
295
|
+
|
|
296
|
+
| sub-envelope | members | folds in | its own |
|
|
297
|
+
|---|---:|---|---|
|
|
298
|
+
| `simulation` | 39 | the fourteen, `projection` | `budget_exhausted`, `contradictory_actions`, `counterfactual_not_a_prediction`, `coupling_uninstantiated`, `cycle_unsupported`, `gain_not_adopted`, `malformed_action`, `malformed_request`, `missing_declaration`, `missing_dynamics`, `missing_entity`, `no_candidates`, `no_declared_tolerance`, `no_objective`, `settle_exceeds_step`, `unknown_action`, `unknown_parameter`, `wrong_entity_type` |
|
|
299
|
+
| `shadow` | 18 | the fourteen | `internal_error`, `no_report_probability`, `not_a_producers_submission`, `tail_not_declared` |
|
|
300
|
+
| `projection` | 9 | -- | `covariance_unbounded`, `insufficient_samples`, `internal_error`, `model_inconsistent`, `model_missing`, `no_lookback`, `no_report_probability`, `no_threshold`, `unidentifiable_parameter` |
|
|
301
|
+
| `discovery` | 8 | -- | `faithfulness_unverifiable`, `insufficient_samples`, `internal_error`, `latent_confounding_possible`, `no_significance_level`, `nonstationary_series`, `orientation_undetermined`, `untested_pair` |
|
|
302
|
+
| `entailment` | 7 | -- | `binding_budget_exhausted`, `depth_exceeded`, `internal_error`, `malformed_rule`, `open_world_undecidable`, `recursion_unsupported`, `rule_unreachable` |
|
|
303
|
+
| `inference` | 7 | -- | `cpt_missing`, `cycle_unsupported`, `evidence_conflict`, `internal_error`, `no_report_probability`, `not_identifiable`, `treewidth_exceeded` |
|
|
304
|
+
| `forecasts` | 5 | -- | `forecast_missing`, `internal_error`, `model_unknown`, `stale_forecast`, `ungradeable` |
|
|
305
|
+
|
|
306
|
+
Read every one of them three-valued, as `COMPATIBILITY.md` says: **a member you
|
|
307
|
+
do not recognise means this engine is newer than your reader**, not that the
|
|
308
|
+
record is malformed. A reader that switches exhaustively and raises on the
|
|
309
|
+
default will break, and the sets have each grown at least once.
|
|
310
|
+
|
|
311
|
+
Three things the shape of the table is telling you:
|
|
312
|
+
|
|
313
|
+
* **`simulation` is the large one because it inherits twice.** A rollout runs
|
|
314
|
+
the eight axioms over every imagined state, so every axiom decline can reach
|
|
315
|
+
it; and `seed_mode="projected"` runs the declared projector, so every
|
|
316
|
+
projection decline can too. Its eighteen own members are the ones about
|
|
317
|
+
actions, couplings and the walk itself.
|
|
318
|
+
* **A member appearing in two sets is the same word, not the same claim.**
|
|
319
|
+
`cycle_unsupported` in `simulation` is a topology the walk will not step;
|
|
320
|
+
in `inference` it is a graph the elimination order cannot handle.
|
|
321
|
+
`internal_error` is in six of the seven and means the same thing in all of
|
|
322
|
+
them, which is why it is not folded anywhere.
|
|
323
|
+
* **A withdrawn member is recorded, not deleted.** `forecasts` once held
|
|
324
|
+
`no_tolerance` and `entailment` two more; they were withdrawn when it was
|
|
325
|
+
shown no input could reach them, and the reasoning stays in
|
|
326
|
+
`subenvelope.py` beside the sets. A member nobody can construct an input for
|
|
327
|
+
makes the set a worse instrument.
|
|
328
|
+
|
|
329
|
+
This table is DERIVED from `subenvelope.py`, not transcribed beside it, and a
|
|
330
|
+
test fails when the two disagree. A table maintained by hand next to a
|
|
331
|
+
frozenset is a second copy of one closed set, which is the drift the module
|
|
332
|
+
itself refuses one level further in.
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
268
336
|
## 3. The read surface that is not `check`
|
|
269
337
|
|
|
270
338
|
The vocabulary above is everything the engine refuses to **judge**. It is not
|