mostlyright-data 0.9.0__py3-none-any.whl
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.
- mostlyright/data_harness/__init__.py +158 -0
- mostlyright/data_harness/acquisition/__init__.py +55 -0
- mostlyright/data_harness/acquisition/http.py +2773 -0
- mostlyright/data_harness/acquisition/parsing.py +809 -0
- mostlyright/data_harness/acquisition/ranges.py +495 -0
- mostlyright/data_harness/acquisition/result_download.py +360 -0
- mostlyright/data_harness/acquisition/retention_admission.py +248 -0
- mostlyright/data_harness/acquisition/sandbox.py +4888 -0
- mostlyright/data_harness/acquisition/url_policy.py +530 -0
- mostlyright/data_harness/agent_runtime.py +2743 -0
- mostlyright/data_harness/assets/logo-ink.svg +31 -0
- mostlyright/data_harness/backends/__init__.py +28 -0
- mostlyright/data_harness/backends/pandas_backend.py +350 -0
- mostlyright/data_harness/backends/polars_backend.py +366 -0
- mostlyright/data_harness/backends/protocol.py +124 -0
- mostlyright/data_harness/backends/reference.py +83 -0
- mostlyright/data_harness/backends/registry.py +55 -0
- mostlyright/data_harness/backends/restrictions.py +126 -0
- mostlyright/data_harness/canonical.py +333 -0
- mostlyright/data_harness/catalog_job.py +625 -0
- mostlyright/data_harness/cli.py +5398 -0
- mostlyright/data_harness/contracts.py +53 -0
- mostlyright/data_harness/coordinator.py +1307 -0
- mostlyright/data_harness/deploy.py +924 -0
- mostlyright/data_harness/deploy_target.py +312 -0
- mostlyright/data_harness/deployment_evidence.py +1067 -0
- mostlyright/data_harness/event_presentation.py +576 -0
- mostlyright/data_harness/events.py +2152 -0
- mostlyright/data_harness/fast_delimited.py +239 -0
- mostlyright/data_harness/fleet.py +237 -0
- mostlyright/data_harness/formats.py +236 -0
- mostlyright/data_harness/governors.py +1163 -0
- mostlyright/data_harness/hosted_bootstrap.py +972 -0
- mostlyright/data_harness/hosted_crawler.py +1115 -0
- mostlyright/data_harness/hosted_crawler_container_smoke.py +351 -0
- mostlyright/data_harness/hosted_crawler_fetch.py +423 -0
- mostlyright/data_harness/hosted_crawler_job.py +1277 -0
- mostlyright/data_harness/hosted_crawler_protocol.py +676 -0
- mostlyright/data_harness/hosted_dataset.py +1500 -0
- mostlyright/data_harness/hosted_deploy.py +3037 -0
- mostlyright/data_harness/hosted_handoff.py +62 -0
- mostlyright/data_harness/hosted_ingestion_contract.py +504 -0
- mostlyright/data_harness/hosted_ingestion_job.py +356 -0
- mostlyright/data_harness/hosted_ingestion_job_smoke.py +40 -0
- mostlyright/data_harness/hosted_session_container_smoke.py +194 -0
- mostlyright/data_harness/hosted_session_worker.py +3554 -0
- mostlyright/data_harness/hosted_session_worker_job_smoke.py +46 -0
- mostlyright/data_harness/hosted_worker.py +6784 -0
- mostlyright/data_harness/ingestion/__init__.py +56 -0
- mostlyright/data_harness/ingestion/contracts.py +461 -0
- mostlyright/data_harness/ingestion/faults.py +42 -0
- mostlyright/data_harness/ingestion/gcs_store.py +1162 -0
- mostlyright/data_harness/ingestion/spool.py +130 -0
- mostlyright/data_harness/ingestion/store.py +885 -0
- mostlyright/data_harness/key_seam.py +434 -0
- mostlyright/data_harness/linux_process_boundary.py +262 -0
- mostlyright/data_harness/local_contracts.py +2880 -0
- mostlyright/data_harness/local_search/__init__.py +5 -0
- mostlyright/data_harness/local_search/build_index.py +1087 -0
- mostlyright/data_harness/local_search/contracts.py +920 -0
- mostlyright/data_harness/local_search/query_trace.py +266 -0
- mostlyright/data_harness/local_search/retrieval.py +700 -0
- mostlyright/data_harness/local_search/sealed.py +474 -0
- mostlyright/data_harness/local_search/service.py +784 -0
- mostlyright/data_harness/nbrender/CONTRACT.md +212 -0
- mostlyright/data_harness/nbrender/__init__.py +12 -0
- mostlyright/data_harness/nbrender/chrome.py +359 -0
- mostlyright/data_harness/nbrender/code_body.py +266 -0
- mostlyright/data_harness/nbrender/document.py +407 -0
- mostlyright/data_harness/nbrender/frame.py +275 -0
- mostlyright/data_harness/nbrender/interactive.py +337 -0
- mostlyright/data_harness/nbrender/markdown_body.py +477 -0
- mostlyright/data_harness/nbrender/mr_components.py +134 -0
- mostlyright/data_harness/nbrender/outputs_data.py +595 -0
- mostlyright/data_harness/nbrender/outputs_rich.py +906 -0
- mostlyright/data_harness/nbrender/outputs_source.py +260 -0
- mostlyright/data_harness/nbrender/outputs_stage.py +176 -0
- mostlyright/data_harness/nbrender/outputs_text.py +400 -0
- mostlyright/data_harness/nbrender/parse.py +394 -0
- mostlyright/data_harness/nbrender/status.py +40 -0
- mostlyright/data_harness/nbrender/tokens.py +1295 -0
- mostlyright/data_harness/notebook.py +1710 -0
- mostlyright/data_harness/offline.py +2049 -0
- mostlyright/data_harness/operation_registry.py +1007 -0
- mostlyright/data_harness/operator_setup.py +239 -0
- mostlyright/data_harness/pipeline.py +6428 -0
- mostlyright/data_harness/plan_graph.py +2026 -0
- mostlyright/data_harness/preparation/__init__.py +104 -0
- mostlyright/data_harness/preparation/contracts.py +1017 -0
- mostlyright/data_harness/preparation/engine.py +221 -0
- mostlyright/data_harness/preparation/errors.py +14 -0
- mostlyright/data_harness/preparation/gates.py +751 -0
- mostlyright/data_harness/preparation/joins.py +574 -0
- mostlyright/data_harness/preparation/profile.py +384 -0
- mostlyright/data_harness/preparation/table.py +217 -0
- mostlyright/data_harness/preparation/transforms.py +568 -0
- mostlyright/data_harness/progress_events.py +534 -0
- mostlyright/data_harness/readers/__init__.py +46 -0
- mostlyright/data_harness/readers/containers.py +963 -0
- mostlyright/data_harness/readers/contracts.py +542 -0
- mostlyright/data_harness/readers/delimited.py +257 -0
- mostlyright/data_harness/readers/grib2/__init__.py +33 -0
- mostlyright/data_harness/readers/grib2/admission.py +722 -0
- mostlyright/data_harness/readers/grib2/decode.py +1009 -0
- mostlyright/data_harness/readers/grib2/geometry.py +1133 -0
- mostlyright/data_harness/readers/grib2/portable_math.py +501 -0
- mostlyright/data_harness/readers/json_tabular.py +485 -0
- mostlyright/data_harness/readers/registry.py +514 -0
- mostlyright/data_harness/readers/samples/README.md +110 -0
- mostlyright/data_harness/readers/samples/archive.gzip/1.0.0/cities_one_stream/cities.csv.gz +0 -0
- mostlyright/data_harness/readers/samples/archive.gzip/1.0.0/cities_one_stream/expected.json +24 -0
- mostlyright/data_harness/readers/samples/archive.gzip/1.1.0/cities_one_stream/cities.csv.gz +0 -0
- mostlyright/data_harness/readers/samples/archive.gzip/1.1.0/cities_one_stream/expected.json +24 -0
- mostlyright/data_harness/readers/samples/archive.tar/1.0.0/cities_beside_a_directory_entry/cities.tar +0 -0
- mostlyright/data_harness/readers/samples/archive.tar/1.0.0/cities_beside_a_directory_entry/expected.json +24 -0
- mostlyright/data_harness/readers/samples/archive.tar/1.1.0/cities_beside_a_directory_entry/cities.tar +0 -0
- mostlyright/data_harness/readers/samples/archive.tar/1.1.0/cities_beside_a_directory_entry/expected.json +24 -0
- mostlyright/data_harness/readers/samples/archive.zip/1.0.0/cities_beside_a_second_member/cities.zip +0 -0
- mostlyright/data_harness/readers/samples/archive.zip/1.0.0/cities_beside_a_second_member/expected.json +25 -0
- mostlyright/data_harness/readers/samples/archive.zip/1.1.0/dwd_semicolon_station_member/dwd-station.zip +0 -0
- mostlyright/data_harness/readers/samples/archive.zip/1.1.0/dwd_semicolon_station_member/expected.json +25 -0
- mostlyright/data_harness/readers/samples/archive.zip/1.2.0/dwd_semicolon_station_member/dwd-station.zip +0 -0
- mostlyright/data_harness/readers/samples/archive.zip/1.2.0/dwd_semicolon_station_member/expected.json +25 -0
- mostlyright/data_harness/readers/samples/delimited_text/1.0.0/an_ordinary_comma_separated_table/cities.csv +3 -0
- mostlyright/data_harness/readers/samples/delimited_text/1.0.0/an_ordinary_comma_separated_table/expected.json +23 -0
- mostlyright/data_harness/readers/samples/delimited_text/1.0.0/quoted_fields_holding_the_delimiter/cities.tsv +5 -0
- mostlyright/data_harness/readers/samples/delimited_text/1.0.0/quoted_fields_holding_the_delimiter/expected.json +25 -0
- mostlyright/data_harness/readers/samples/delimited_text/1.1.0/an_hourly_observation_table_served_as_plain_text/expected.json +30 -0
- mostlyright/data_harness/readers/samples/delimited_text/1.1.0/an_hourly_observation_table_served_as_plain_text/observations.csv +5 -0
- mostlyright/data_harness/readers/samples/json.tabular/1.0.0/nested_hourly_observations/expected.json +44 -0
- mostlyright/data_harness/readers/samples/json.tabular/1.0.0/nested_hourly_observations/stations.json +1 -0
- mostlyright/data_harness/readers/samples/json.tabular/1.1.0/an_observation_stream_served_as_plain_text/expected.json +48 -0
- mostlyright/data_harness/readers/samples/json.tabular/1.1.0/an_observation_stream_served_as_plain_text/observations.ndjson +4 -0
- mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/an_ordinary_table_beside_a_second_sheet/cities.xlsx +0 -0
- mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/an_ordinary_table_beside_a_second_sheet/expected.json +24 -0
- mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/shares_the_workbook_had_already_computed/expected.json +27 -0
- mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/shares_the_workbook_had_already_computed/shares.xlsx +0 -0
- mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.1.0/shares_the_workbook_had_already_computed/expected.json +27 -0
- mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.1.0/shares_the_workbook_had_already_computed/shares.xlsx +0 -0
- mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/README.md +20 -0
- mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/gfs_2m_temperature/expected.json +55 -0
- mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/gfs_2m_temperature/gfs-2m-temperature.grib2 +0 -0
- mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_2m_temperature/expected.json +54 -0
- mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_2m_temperature/hrrr-2m-temperature.grib2 +0 -0
- mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_categorical_rain/expected.json +54 -0
- mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_categorical_rain/hrrr-categorical-rain.grib2 +0 -0
- mostlyright/data_harness/readers/samples/weather.grib2/2.0.0/hrrr_2m_temperature/expected.json +54 -0
- mostlyright/data_harness/readers/samples/weather.grib2/2.0.0/hrrr_2m_temperature/hrrr-2m-temperature.grib2 +0 -0
- mostlyright/data_harness/readers/samples.py +582 -0
- mostlyright/data_harness/readers/spreadsheet.py +803 -0
- mostlyright/data_harness/readers/tabular.py +510 -0
- mostlyright/data_harness/recipe.py +5321 -0
- mostlyright/data_harness/repair/__init__.py +78 -0
- mostlyright/data_harness/repair/adapters.py +274 -0
- mostlyright/data_harness/repair/contracts.py +872 -0
- mostlyright/data_harness/repair/coordinator.py +1099 -0
- mostlyright/data_harness/repair/errors.py +16 -0
- mostlyright/data_harness/review.py +2533 -0
- mostlyright/data_harness/rowset.py +283 -0
- mostlyright/data_harness/serving.py +1975 -0
- mostlyright/data_harness/serving_edge.py +590 -0
- mostlyright/data_harness/serving_http.py +1031 -0
- mostlyright/data_harness/session_probes.py +759 -0
- mostlyright/data_harness/signing.py +101 -0
- mostlyright/data_harness/source_discovery.py +898 -0
- mostlyright/data_harness/sources/__init__.py +209 -0
- mostlyright/data_harness/sources/_adapter_steps.py +213 -0
- mostlyright/data_harness/sources/adapters.py +1214 -0
- mostlyright/data_harness/sources/cadence.py +1428 -0
- mostlyright/data_harness/sources/cadence_emission.py +453 -0
- mostlyright/data_harness/sources/cadence_history.py +546 -0
- mostlyright/data_harness/sources/catalog/__init__.py +17 -0
- mostlyright/data_harness/sources/catalog/admission.py +477 -0
- mostlyright/data_harness/sources/catalog/authoring.py +1701 -0
- mostlyright/data_harness/sources/catalog/authoring_policy.py +701 -0
- mostlyright/data_harness/sources/catalog/authoring_shards.py +1217 -0
- mostlyright/data_harness/sources/catalog/bounded_io.py +231 -0
- mostlyright/data_harness/sources/catalog/channel.py +523 -0
- mostlyright/data_harness/sources/catalog/channel_client.py +296 -0
- mostlyright/data_harness/sources/catalog/contracts.py +825 -0
- mostlyright/data_harness/sources/catalog/coverage.py +137 -0
- mostlyright/data_harness/sources/catalog/delta.py +1340 -0
- mostlyright/data_harness/sources/catalog/embedding.py +532 -0
- mostlyright/data_harness/sources/catalog/entry_v2.py +1182 -0
- mostlyright/data_harness/sources/catalog/fill.py +3889 -0
- mostlyright/data_harness/sources/catalog/fill_partitions.py +459 -0
- mostlyright/data_harness/sources/catalog/fill_staging.py +1105 -0
- mostlyright/data_harness/sources/catalog/gating.py +374 -0
- mostlyright/data_harness/sources/catalog/generation_receipt.py +1607 -0
- mostlyright/data_harness/sources/catalog/harvest/__init__.py +7 -0
- mostlyright/data_harness/sources/catalog/harvest/ckan.py +384 -0
- mostlyright/data_harness/sources/catalog/harvest/datagov_v4.py +798 -0
- mostlyright/data_harness/sources/catalog/harvest/protocol.py +964 -0
- mostlyright/data_harness/sources/catalog/harvest/sdmx.py +445 -0
- mostlyright/data_harness/sources/catalog/harvest/stac.py +384 -0
- mostlyright/data_harness/sources/catalog/health.py +447 -0
- mostlyright/data_harness/sources/catalog/hosted_catalog.py +105 -0
- mostlyright/data_harness/sources/catalog/identity_history.py +1549 -0
- mostlyright/data_harness/sources/catalog/neural.py +1618 -0
- mostlyright/data_harness/sources/catalog/packed_catalog.py +2345 -0
- mostlyright/data_harness/sources/catalog/packed_retrieval.py +1517 -0
- mostlyright/data_harness/sources/catalog/packed_writer.py +2802 -0
- mostlyright/data_harness/sources/catalog/query_trace.py +1037 -0
- mostlyright/data_harness/sources/catalog/recommend.py +171 -0
- mostlyright/data_harness/sources/catalog/retrieval.py +230 -0
- mostlyright/data_harness/sources/catalog/retrieval_manifest.py +995 -0
- mostlyright/data_harness/sources/catalog/rights_decisions.py +254 -0
- mostlyright/data_harness/sources/catalog/sealed.py +560 -0
- mostlyright/data_harness/sources/catalog/search.py +230 -0
- mostlyright/data_harness/sources/catalog/streaming_delta.py +1097 -0
- mostlyright/data_harness/sources/catalog/update.py +891 -0
- mostlyright/data_harness/sources/collections.py +815 -0
- mostlyright/data_harness/sources/contracts.py +2223 -0
- mostlyright/data_harness/sources/deletion.py +761 -0
- mostlyright/data_harness/sources/fitness.py +162 -0
- mostlyright/data_harness/sources/governance.py +163 -0
- mostlyright/data_harness/sources/hosted.py +173 -0
- mostlyright/data_harness/sources/integration.py +218 -0
- mostlyright/data_harness/sources/range_reader.py +418 -0
- mostlyright/data_harness/sources/registry.py +514 -0
- mostlyright/data_harness/sources/rights_rule.py +59 -0
- mostlyright/data_harness/sources/source_cadence_vectors.v1.json +1 -0
- mostlyright/data_harness/sources/sports.py +521 -0
- mostlyright/data_harness/sources/stream.py +524 -0
- mostlyright/data_harness/sources/stream_connector.py +418 -0
- mostlyright/data_harness/sources/stream_recorder.py +1404 -0
- mostlyright/data_harness/studio_boundary.py +2019 -0
- mostlyright/data_harness/thin/__init__.py +37 -0
- mostlyright/data_harness/thin/acquire.py +1137 -0
- mostlyright/data_harness/thin/acquire_cancel.py +579 -0
- mostlyright/data_harness/thin/approvals.py +617 -0
- mostlyright/data_harness/thin/commands.py +406 -0
- mostlyright/data_harness/thin/download.py +194 -0
- mostlyright/data_harness/thin/narrative.py +589 -0
- mostlyright/data_harness/thin/parity.py +1070 -0
- mostlyright/data_harness/thin/propose.py +2759 -0
- mostlyright/data_harness/thin/research.py +1663 -0
- mostlyright/data_harness/thin/router.py +924 -0
- mostlyright/data_harness/thin/runs.py +519 -0
- mostlyright/data_harness/thin/session.py +281 -0
- mostlyright/data_harness/thin/stream.py +501 -0
- mostlyright/data_harness/thin/transport.py +187 -0
- mostlyright/data_harness/thin/vocabulary.py +368 -0
- mostlyright/data_harness/thin/workers.py +164 -0
- mostlyright/data_harness/ucum/TABLE-PIN.json +40 -0
- mostlyright/data_harness/ucum/ucum-subset.v1.json +632 -0
- mostlyright/data_harness/unit_flow.py +927 -0
- mostlyright/data_harness/units.py +572 -0
- mostlyright/data_harness/ux/__init__.py +9 -0
- mostlyright/data_harness/ux/approve.py +485 -0
- mostlyright/data_harness/ux/author_yaml.py +597 -0
- mostlyright/data_harness/ux/cloud_auth.py +447 -0
- mostlyright/data_harness/ux/commands/__init__.py +260 -0
- mostlyright/data_harness/ux/commands/approve.py +136 -0
- mostlyright/data_harness/ux/commands/auth.py +744 -0
- mostlyright/data_harness/ux/commands/author.py +79 -0
- mostlyright/data_harness/ux/commands/catalog_author.py +403 -0
- mostlyright/data_harness/ux/commands/catalog_fill.py +523 -0
- mostlyright/data_harness/ux/commands/catalog_harvest.py +545 -0
- mostlyright/data_harness/ux/commands/catalog_publish.py +1838 -0
- mostlyright/data_harness/ux/commands/catalog_search.py +71 -0
- mostlyright/data_harness/ux/commands/catalog_update.py +437 -0
- mostlyright/data_harness/ux/commands/deploy.py +134 -0
- mostlyright/data_harness/ux/commands/deploy_dataset.py +98 -0
- mostlyright/data_harness/ux/commands/deploy_plan.py +105 -0
- mostlyright/data_harness/ux/commands/deploy_status.py +104 -0
- mostlyright/data_harness/ux/commands/diff.py +74 -0
- mostlyright/data_harness/ux/commands/index.py +84 -0
- mostlyright/data_harness/ux/commands/inventory.py +47 -0
- mostlyright/data_harness/ux/commands/list_builds.py +143 -0
- mostlyright/data_harness/ux/commands/login.py +63 -0
- mostlyright/data_harness/ux/commands/peek.py +236 -0
- mostlyright/data_harness/ux/commands/plan_check.py +90 -0
- mostlyright/data_harness/ux/commands/preflight.py +97 -0
- mostlyright/data_harness/ux/commands/record.py +107 -0
- mostlyright/data_harness/ux/commands/review_setup.py +47 -0
- mostlyright/data_harness/ux/commands/search.py +440 -0
- mostlyright/data_harness/ux/commands/show.py +61 -0
- mostlyright/data_harness/ux/commands/whoami.py +37 -0
- mostlyright/data_harness/ux/credential_native.py +551 -0
- mostlyright/data_harness/ux/credential_store.py +1055 -0
- mostlyright/data_harness/ux/credentials.py +631 -0
- mostlyright/data_harness/ux/diffing.py +444 -0
- mostlyright/data_harness/ux/headline.py +671 -0
- mostlyright/data_harness/ux/hosted_acquisition.py +974 -0
- mostlyright/data_harness/ux/hosted_run_status.py +619 -0
- mostlyright/data_harness/ux/inventory.py +427 -0
- mostlyright/data_harness/ux/local_review.py +375 -0
- mostlyright/data_harness/ux/login.py +691 -0
- mostlyright/data_harness/ux/path_kind.py +147 -0
- mostlyright/data_harness/ux/peek.py +1000 -0
- mostlyright/data_harness/ux/plain_file.py +178 -0
- mostlyright/data_harness/ux/plan_check.py +311 -0
- mostlyright/data_harness/ux/preflight.py +918 -0
- mostlyright/data_harness/ux/readers.py +1124 -0
- mostlyright/data_harness/ux/remediation.py +2195 -0
- mostlyright/data_harness/ux/render.py +657 -0
- mostlyright/data_harness/ux/workload.py +1077 -0
- mostlyright/data_harness/viewer.py +3713 -0
- mostlyright/data_harness/visual_run/__init__.py +83 -0
- mostlyright/data_harness/visual_run/authoring.py +235 -0
- mostlyright/data_harness/visual_run/contracts.py +673 -0
- mostlyright/data_harness/visual_run/materialize.py +486 -0
- mostlyright/data_harness/visual_run/observations.py +874 -0
- mostlyright/data_harness/visual_run/query.py +259 -0
- mostlyright/data_harness/visual_run/reducer.py +280 -0
- mostlyright/data_harness/visual_run/sdk.py +892 -0
- mostlyright/data_harness/visual_run/store.py +584 -0
- mostlyright/data_harness/visual_run/transport.py +239 -0
- mostlyright/data_harness/watch.py +2999 -0
- mostlyright_data-0.9.0.dist-info/METADATA +607 -0
- mostlyright_data-0.9.0.dist-info/RECORD +314 -0
- mostlyright_data-0.9.0.dist-info/WHEEL +4 -0
- mostlyright_data-0.9.0.dist-info/entry_points.txt +12 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Immutable, bounded repair-successor coordination.
|
|
2
|
+
|
|
3
|
+
A repair never edits a sealed candidate. It builds a successor: a new plan derived from the
|
|
4
|
+
predecessor by a bounded set of actions, re-executed through
|
|
5
|
+
``preparation.execute_preparation``, and closed out by independent review.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from mostlyright.data_harness.repair.adapters import (
|
|
9
|
+
candidate_digest,
|
|
10
|
+
input_set_digest,
|
|
11
|
+
join_digest,
|
|
12
|
+
operation_digest,
|
|
13
|
+
output_columns_digest,
|
|
14
|
+
plan_digest,
|
|
15
|
+
validation_policy_digest,
|
|
16
|
+
)
|
|
17
|
+
from mostlyright.data_harness.repair.contracts import (
|
|
18
|
+
ALL_QUALITY_CHECK_IDS,
|
|
19
|
+
BLOCKING_SEVERITIES,
|
|
20
|
+
MAX_FAILED_CANDIDATES,
|
|
21
|
+
REQUIRED_CLOSURE_LENSES,
|
|
22
|
+
CandidateReference,
|
|
23
|
+
ClosureDecision,
|
|
24
|
+
ClosureReviewReport,
|
|
25
|
+
ClosureReviewScope,
|
|
26
|
+
CycleAnchor,
|
|
27
|
+
FindingInventory,
|
|
28
|
+
RepairAction,
|
|
29
|
+
RepairAssignment,
|
|
30
|
+
RepairFinding,
|
|
31
|
+
RepairSuccessor,
|
|
32
|
+
ResolutionEvidence,
|
|
33
|
+
ReviewerEnrollment,
|
|
34
|
+
load_public_key,
|
|
35
|
+
public_key_text,
|
|
36
|
+
)
|
|
37
|
+
from mostlyright.data_harness.repair.coordinator import (
|
|
38
|
+
ImmutableRepairCoordinator,
|
|
39
|
+
RepairExecution,
|
|
40
|
+
TrustedCycleAnchorStore,
|
|
41
|
+
bind_candidate,
|
|
42
|
+
make_closure_report,
|
|
43
|
+
)
|
|
44
|
+
from mostlyright.data_harness.repair.errors import RepairError
|
|
45
|
+
|
|
46
|
+
__all__ = [
|
|
47
|
+
"ALL_QUALITY_CHECK_IDS",
|
|
48
|
+
"BLOCKING_SEVERITIES",
|
|
49
|
+
"MAX_FAILED_CANDIDATES",
|
|
50
|
+
"REQUIRED_CLOSURE_LENSES",
|
|
51
|
+
"CandidateReference",
|
|
52
|
+
"ClosureDecision",
|
|
53
|
+
"ClosureReviewReport",
|
|
54
|
+
"ClosureReviewScope",
|
|
55
|
+
"CycleAnchor",
|
|
56
|
+
"FindingInventory",
|
|
57
|
+
"ImmutableRepairCoordinator",
|
|
58
|
+
"RepairAction",
|
|
59
|
+
"RepairAssignment",
|
|
60
|
+
"RepairError",
|
|
61
|
+
"RepairExecution",
|
|
62
|
+
"RepairFinding",
|
|
63
|
+
"RepairSuccessor",
|
|
64
|
+
"ResolutionEvidence",
|
|
65
|
+
"ReviewerEnrollment",
|
|
66
|
+
"TrustedCycleAnchorStore",
|
|
67
|
+
"bind_candidate",
|
|
68
|
+
"candidate_digest",
|
|
69
|
+
"input_set_digest",
|
|
70
|
+
"join_digest",
|
|
71
|
+
"load_public_key",
|
|
72
|
+
"make_closure_report",
|
|
73
|
+
"operation_digest",
|
|
74
|
+
"output_columns_digest",
|
|
75
|
+
"plan_digest",
|
|
76
|
+
"public_key_text",
|
|
77
|
+
"validation_policy_digest",
|
|
78
|
+
]
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
"""Narrow immutable adapters over the preparation engine."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Mapping
|
|
6
|
+
from dataclasses import fields, is_dataclass, replace
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from mostlyright.data_harness.canonical import canonical_sha256
|
|
10
|
+
from mostlyright.data_harness.preparation.contracts import (
|
|
11
|
+
AsOfJoinSpec,
|
|
12
|
+
EqualityJoinSpec,
|
|
13
|
+
OperationSpec,
|
|
14
|
+
PreparationPlan,
|
|
15
|
+
)
|
|
16
|
+
from mostlyright.data_harness.preparation.engine import PreparationResult
|
|
17
|
+
from mostlyright.data_harness.preparation.table import TableState
|
|
18
|
+
from mostlyright.data_harness.repair.errors import RepairError
|
|
19
|
+
|
|
20
|
+
# Re-declared locally rather than imported; ``preparation.contracts`` exports an identical
|
|
21
|
+
# ``JoinSpec`` alias.
|
|
22
|
+
JoinSpec = EqualityJoinSpec | AsOfJoinSpec
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def preparation_value(value: Any) -> Any:
|
|
26
|
+
"""Convert frozen preparation objects to their complete canonical value."""
|
|
27
|
+
|
|
28
|
+
if is_dataclass(value) and not isinstance(value, type):
|
|
29
|
+
return {
|
|
30
|
+
field.name: preparation_value(getattr(value, field.name)) for field in fields(value)
|
|
31
|
+
}
|
|
32
|
+
if isinstance(value, tuple):
|
|
33
|
+
return [preparation_value(item) for item in value]
|
|
34
|
+
if isinstance(value, list):
|
|
35
|
+
return [preparation_value(item) for item in value]
|
|
36
|
+
if isinstance(value, dict):
|
|
37
|
+
return {key: preparation_value(item) for key, item in value.items()}
|
|
38
|
+
return value
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def plan_digest(plan: PreparationPlan) -> str:
|
|
42
|
+
"""Hash a plan's raw dataclass fields, as encoded by ``preparation_value``.
|
|
43
|
+
|
|
44
|
+
This is not ``PreparationPlan.digest``. The two hash different encodings of the same
|
|
45
|
+
object and are deliberately distinct values: ``PreparationPlan.digest`` hashes
|
|
46
|
+
``plan.to_dict()``, which adds a ``kind`` discriminator to each join and turns each
|
|
47
|
+
operation's ``parameters`` pair-tuple into a mapping, while this function hashes the
|
|
48
|
+
fields as declared. Repair digests recorded by this module must always be compared
|
|
49
|
+
against this function; comparing one against ``PreparationPlan.digest`` mismatches
|
|
50
|
+
even for an identical plan.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
if not isinstance(plan, PreparationPlan):
|
|
54
|
+
raise RepairError("REPAIR_PLAN_TYPE", "plan", "must be a PreparationPlan")
|
|
55
|
+
return canonical_sha256(preparation_value(plan))
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def validation_policy_digest(plan: PreparationPlan) -> str:
|
|
59
|
+
if not isinstance(plan, PreparationPlan):
|
|
60
|
+
raise RepairError("REPAIR_PLAN_TYPE", "plan", "must be a PreparationPlan")
|
|
61
|
+
return canonical_sha256(
|
|
62
|
+
{
|
|
63
|
+
"quality": preparation_value(plan.quality),
|
|
64
|
+
"temporal_policy": preparation_value(plan.temporal_policy),
|
|
65
|
+
"target_policy": plan.target_policy,
|
|
66
|
+
"target": preparation_value(plan.target),
|
|
67
|
+
}
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def operation_digest(operation: OperationSpec) -> str:
|
|
72
|
+
if not isinstance(operation, OperationSpec):
|
|
73
|
+
raise RepairError("REPAIR_OPERATION_TYPE", "operation", "must be an OperationSpec")
|
|
74
|
+
return canonical_sha256(preparation_value(operation))
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def join_digest(join: JoinSpec) -> str:
|
|
78
|
+
if not isinstance(join, (EqualityJoinSpec, AsOfJoinSpec)):
|
|
79
|
+
raise RepairError("REPAIR_JOIN_TYPE", "join", "must be a supported join")
|
|
80
|
+
return canonical_sha256(preparation_value(join))
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def output_columns_digest(columns: tuple[str, ...]) -> str:
|
|
84
|
+
return canonical_sha256(list(columns))
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def table_value(state: TableState) -> dict[str, Any]:
|
|
88
|
+
"""Encode every cell without depending on locale or JSON floating numbers."""
|
|
89
|
+
|
|
90
|
+
if not isinstance(state, TableState):
|
|
91
|
+
raise RepairError("REPAIR_TABLE_TYPE", "state", "must be a TableState")
|
|
92
|
+
encoded_rows: list[list[dict[str, Any]]] = []
|
|
93
|
+
for row in state.rows:
|
|
94
|
+
encoded_row: list[dict[str, Any]] = []
|
|
95
|
+
for field, value in zip(state.fields, row, strict=True):
|
|
96
|
+
if value is None:
|
|
97
|
+
encoded = {"type": field.logical_type, "value": None}
|
|
98
|
+
elif field.logical_type == "float64":
|
|
99
|
+
encoded = {"type": "float64", "value": float(value).hex()}
|
|
100
|
+
elif field.logical_type == "boolean":
|
|
101
|
+
encoded = {"type": "boolean", "value": value}
|
|
102
|
+
elif field.logical_type == "int64":
|
|
103
|
+
encoded = {"type": "int64", "value": value}
|
|
104
|
+
else:
|
|
105
|
+
encoded = {"type": field.logical_type, "value": value}
|
|
106
|
+
encoded_row.append(encoded)
|
|
107
|
+
encoded_rows.append(encoded_row)
|
|
108
|
+
return {
|
|
109
|
+
"table_id": state.table_id,
|
|
110
|
+
"snapshot_digests": list(state.snapshot_digests),
|
|
111
|
+
"fields": [preparation_value(field) for field in state.fields],
|
|
112
|
+
"rows": encoded_rows,
|
|
113
|
+
"lineage": [preparation_value(item) for item in state.lineage],
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def input_set_digest(inputs: Mapping[str, TableState]) -> str:
|
|
118
|
+
"""Bind every exact pre-preparation input table and cell."""
|
|
119
|
+
|
|
120
|
+
if not isinstance(inputs, Mapping) or not inputs:
|
|
121
|
+
raise RepairError(
|
|
122
|
+
"REPAIR_INPUT_SET",
|
|
123
|
+
"inputs",
|
|
124
|
+
"must be a non-empty source mapping",
|
|
125
|
+
)
|
|
126
|
+
if any(
|
|
127
|
+
not isinstance(key, str) or not isinstance(value, TableState)
|
|
128
|
+
for key, value in inputs.items()
|
|
129
|
+
):
|
|
130
|
+
raise RepairError(
|
|
131
|
+
"REPAIR_INPUT_SET",
|
|
132
|
+
"inputs",
|
|
133
|
+
"must map source identifiers to TableState values",
|
|
134
|
+
)
|
|
135
|
+
if any(key != value.table_id for key, value in inputs.items()):
|
|
136
|
+
raise RepairError(
|
|
137
|
+
"REPAIR_INPUT_SET",
|
|
138
|
+
"inputs",
|
|
139
|
+
"mapping keys must equal table IDs",
|
|
140
|
+
)
|
|
141
|
+
return canonical_sha256(
|
|
142
|
+
[
|
|
143
|
+
{"source_id": source_id, "table": table_value(inputs[source_id])}
|
|
144
|
+
for source_id in sorted(inputs)
|
|
145
|
+
]
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def candidate_digest(
|
|
150
|
+
plan: PreparationPlan,
|
|
151
|
+
result: PreparationResult,
|
|
152
|
+
inputs: Mapping[str, TableState],
|
|
153
|
+
) -> str:
|
|
154
|
+
if not isinstance(result, PreparationResult):
|
|
155
|
+
raise RepairError("REPAIR_RESULT_TYPE", "result", "must be a PreparationResult")
|
|
156
|
+
return canonical_sha256(
|
|
157
|
+
{
|
|
158
|
+
"plan_digest": plan_digest(plan),
|
|
159
|
+
"validation_policy_digest": validation_policy_digest(plan),
|
|
160
|
+
"input_set_digest": input_set_digest(inputs),
|
|
161
|
+
"evidence_digest": result.evidence_digest,
|
|
162
|
+
"output": table_value(result.output),
|
|
163
|
+
}
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def replace_operation(
|
|
168
|
+
plan: PreparationPlan,
|
|
169
|
+
*,
|
|
170
|
+
target_id: str,
|
|
171
|
+
expected_digest: str,
|
|
172
|
+
replacement: OperationSpec | None,
|
|
173
|
+
) -> PreparationPlan:
|
|
174
|
+
indexes = [
|
|
175
|
+
index
|
|
176
|
+
for index, operation in enumerate(plan.operations)
|
|
177
|
+
if operation.operation_id == target_id
|
|
178
|
+
]
|
|
179
|
+
if len(indexes) != 1:
|
|
180
|
+
raise RepairError(
|
|
181
|
+
"REPAIR_TARGET",
|
|
182
|
+
target_id,
|
|
183
|
+
"operation target must exist exactly once",
|
|
184
|
+
)
|
|
185
|
+
index = indexes[0]
|
|
186
|
+
current = plan.operations[index]
|
|
187
|
+
if operation_digest(current) != expected_digest:
|
|
188
|
+
raise RepairError(
|
|
189
|
+
"REPAIR_STALE_ACTION",
|
|
190
|
+
target_id,
|
|
191
|
+
"operation digest differs from the assigned predecessor",
|
|
192
|
+
)
|
|
193
|
+
updated = list(plan.operations)
|
|
194
|
+
if replacement is None:
|
|
195
|
+
del updated[index]
|
|
196
|
+
else:
|
|
197
|
+
if replacement.operation_id != target_id:
|
|
198
|
+
raise RepairError(
|
|
199
|
+
"REPAIR_TARGET",
|
|
200
|
+
target_id,
|
|
201
|
+
"replacement operation ID must remain stable",
|
|
202
|
+
)
|
|
203
|
+
updated[index] = replacement
|
|
204
|
+
return replace(plan, operations=tuple(updated))
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def append_operation(plan: PreparationPlan, replacement: OperationSpec) -> PreparationPlan:
|
|
208
|
+
if any(item.operation_id == replacement.operation_id for item in plan.operations):
|
|
209
|
+
raise RepairError(
|
|
210
|
+
"REPAIR_TARGET",
|
|
211
|
+
replacement.operation_id,
|
|
212
|
+
"appended operation ID already exists",
|
|
213
|
+
)
|
|
214
|
+
return replace(plan, operations=(*plan.operations, replacement))
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def replace_join(
|
|
218
|
+
plan: PreparationPlan,
|
|
219
|
+
*,
|
|
220
|
+
target_id: str,
|
|
221
|
+
expected_digest: str,
|
|
222
|
+
replacement: JoinSpec | None,
|
|
223
|
+
) -> PreparationPlan:
|
|
224
|
+
indexes = [index for index, join in enumerate(plan.joins) if join.join_id == target_id]
|
|
225
|
+
if len(indexes) != 1:
|
|
226
|
+
raise RepairError("REPAIR_TARGET", target_id, "join target must exist exactly once")
|
|
227
|
+
index = indexes[0]
|
|
228
|
+
current = plan.joins[index]
|
|
229
|
+
if join_digest(current) != expected_digest:
|
|
230
|
+
raise RepairError(
|
|
231
|
+
"REPAIR_STALE_ACTION",
|
|
232
|
+
target_id,
|
|
233
|
+
"join digest differs from the assigned predecessor",
|
|
234
|
+
)
|
|
235
|
+
updated = list(plan.joins)
|
|
236
|
+
if replacement is None:
|
|
237
|
+
del updated[index]
|
|
238
|
+
else:
|
|
239
|
+
if replacement.join_id != target_id:
|
|
240
|
+
raise RepairError(
|
|
241
|
+
"REPAIR_TARGET",
|
|
242
|
+
target_id,
|
|
243
|
+
"replacement join ID must remain stable",
|
|
244
|
+
)
|
|
245
|
+
updated[index] = replacement
|
|
246
|
+
return replace(plan, joins=tuple(updated))
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def append_join(plan: PreparationPlan, replacement: JoinSpec) -> PreparationPlan:
|
|
250
|
+
if any(item.join_id == replacement.join_id for item in plan.joins):
|
|
251
|
+
raise RepairError(
|
|
252
|
+
"REPAIR_TARGET",
|
|
253
|
+
replacement.join_id,
|
|
254
|
+
"appended join ID already exists",
|
|
255
|
+
)
|
|
256
|
+
return replace(plan, joins=(*plan.joins, replacement))
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
__all__ = [
|
|
260
|
+
"JoinSpec",
|
|
261
|
+
"append_join",
|
|
262
|
+
"append_operation",
|
|
263
|
+
"candidate_digest",
|
|
264
|
+
"input_set_digest",
|
|
265
|
+
"join_digest",
|
|
266
|
+
"operation_digest",
|
|
267
|
+
"output_columns_digest",
|
|
268
|
+
"plan_digest",
|
|
269
|
+
"preparation_value",
|
|
270
|
+
"replace_join",
|
|
271
|
+
"replace_operation",
|
|
272
|
+
"table_value",
|
|
273
|
+
"validation_policy_digest",
|
|
274
|
+
]
|