mostlyright-data 0.9.6__tar.gz → 0.9.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.
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/PKG-INFO +8 -4
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/README.md +7 -3
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/pyproject.toml +5 -3
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/acquisition/sandbox.py +5 -1
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/acquisition/url_policy.py +27 -1
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/cli.py +31 -9
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/hosted_bootstrap.py +166 -25
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/hosted_crawler_fetch.py +9 -1
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/hosted_worker.py +511 -9
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/studio_boundary.py +1 -1
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/thin/propose.py +2 -2
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/thin/router.py +494 -51
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/hosted_acquisition.py +29 -4
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/remediation.py +1 -1
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/render.py +1 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/.gitignore +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/scripts/hatch_build.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/__init__.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/acquisition/__init__.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/acquisition/http.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/acquisition/parsing.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/acquisition/ranges.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/acquisition/result_download.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/acquisition/retention_admission.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/agent_runtime.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/assets/logo-ink.svg +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/backends/__init__.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/backends/pandas_backend.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/backends/polars_backend.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/backends/protocol.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/backends/reference.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/backends/registry.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/backends/restrictions.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/canonical.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/catalog_job.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/contracts.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/coordinator.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/deploy.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/deploy_target.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/deployment_evidence.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/event_presentation.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/events.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/fast_delimited.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/fleet.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/formats.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/governors.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/hosted_crawler.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/hosted_crawler_container_smoke.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/hosted_crawler_job.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/hosted_crawler_protocol.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/hosted_dataset.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/hosted_deploy.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/hosted_handoff.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/hosted_ingestion_contract.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/hosted_ingestion_job.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/hosted_ingestion_job_smoke.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/hosted_session_container_smoke.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/hosted_session_worker.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/hosted_session_worker_job_smoke.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ingestion/__init__.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ingestion/contracts.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ingestion/faults.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ingestion/gcs_store.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ingestion/spool.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ingestion/store.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/key_seam.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/linux_process_boundary.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/local_contracts.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/local_search/__init__.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/local_search/build_index.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/local_search/contracts.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/local_search/query_trace.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/local_search/retrieval.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/local_search/sealed.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/local_search/service.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/nbrender/CONTRACT.md +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/nbrender/__init__.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/nbrender/chrome.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/nbrender/code_body.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/nbrender/document.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/nbrender/frame.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/nbrender/interactive.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/nbrender/markdown_body.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/nbrender/mr_components.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/nbrender/outputs_data.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/nbrender/outputs_rich.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/nbrender/outputs_source.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/nbrender/outputs_stage.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/nbrender/outputs_text.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/nbrender/parse.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/nbrender/status.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/nbrender/tokens.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/notebook.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/offline.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/operation_registry.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/operator_setup.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/pipeline.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/plan_graph.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/preparation/__init__.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/preparation/contracts.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/preparation/engine.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/preparation/errors.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/preparation/gates.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/preparation/joins.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/preparation/profile.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/preparation/table.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/preparation/transforms.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/progress_events.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/__init__.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/containers.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/contracts.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/delimited.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/grib2/__init__.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/grib2/admission.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/grib2/decode.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/grib2/geometry.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/grib2/portable_math.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/json_tabular.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/parquet_tabular.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/registry.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/README.md +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/archive.gzip/1.0.0/cities_one_stream/cities.csv.gz +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/archive.gzip/1.0.0/cities_one_stream/expected.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/archive.gzip/1.1.0/cities_one_stream/cities.csv.gz +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/archive.gzip/1.1.0/cities_one_stream/expected.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/archive.tar/1.0.0/cities_beside_a_directory_entry/cities.tar +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/archive.tar/1.0.0/cities_beside_a_directory_entry/expected.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/archive.tar/1.1.0/cities_beside_a_directory_entry/cities.tar +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/archive.tar/1.1.0/cities_beside_a_directory_entry/expected.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/archive.zip/1.0.0/cities_beside_a_second_member/cities.zip +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/archive.zip/1.0.0/cities_beside_a_second_member/expected.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/archive.zip/1.1.0/dwd_semicolon_station_member/dwd-station.zip +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/archive.zip/1.1.0/dwd_semicolon_station_member/expected.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/archive.zip/1.2.0/dwd_semicolon_station_member/dwd-station.zip +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/archive.zip/1.2.0/dwd_semicolon_station_member/expected.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/delimited_text/1.0.0/an_ordinary_comma_separated_table/cities.csv +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/delimited_text/1.0.0/an_ordinary_comma_separated_table/expected.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/delimited_text/1.0.0/quoted_fields_holding_the_delimiter/cities.tsv +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/delimited_text/1.0.0/quoted_fields_holding_the_delimiter/expected.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/delimited_text/1.1.0/an_hourly_observation_table_served_as_plain_text/expected.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/delimited_text/1.1.0/an_hourly_observation_table_served_as_plain_text/observations.csv +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/json.tabular/1.0.0/nested_hourly_observations/expected.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/json.tabular/1.0.0/nested_hourly_observations/stations.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/json.tabular/1.1.0/an_observation_stream_served_as_plain_text/expected.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/json.tabular/1.1.0/an_observation_stream_served_as_plain_text/observations.ndjson +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/parquet.tabular/1.0.0/two_columns/expected.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/parquet.tabular/1.0.0/two_columns/prices.parquet +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/an_ordinary_table_beside_a_second_sheet/cities.xlsx +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/an_ordinary_table_beside_a_second_sheet/expected.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/shares_the_workbook_had_already_computed/expected.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/shares_the_workbook_had_already_computed/shares.xlsx +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.1.0/shares_the_workbook_had_already_computed/expected.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.1.0/shares_the_workbook_had_already_computed/shares.xlsx +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/README.md +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/gfs_2m_temperature/expected.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/gfs_2m_temperature/gfs-2m-temperature.grib2 +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_2m_temperature/expected.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_2m_temperature/hrrr-2m-temperature.grib2 +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_categorical_rain/expected.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_categorical_rain/hrrr-categorical-rain.grib2 +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/weather.grib2/2.0.0/hrrr_2m_temperature/expected.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples/weather.grib2/2.0.0/hrrr_2m_temperature/hrrr-2m-temperature.grib2 +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/samples.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/spreadsheet.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/readers/tabular.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/recipe.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/repair/__init__.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/repair/adapters.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/repair/contracts.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/repair/coordinator.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/repair/errors.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/review.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/rowset.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/serving.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/serving_edge.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/serving_http.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/session_probes.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/signing.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/source_discovery.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/__init__.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/_adapter_steps.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/adapters.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/authenticated_https.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/authenticated_https_v2.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/cadence.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/cadence_emission.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/cadence_history.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/__init__.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/admission.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/authoring.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/authoring_policy.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/authoring_shards.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/bounded_io.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/channel.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/channel_client.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/contracts.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/coverage.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/delta.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/embedding.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/entry_v2.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/fill.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/fill_partitions.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/fill_staging.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/gating.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/generation_receipt.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/harvest/__init__.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/harvest/ckan.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/harvest/datagov_v4.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/harvest/protocol.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/harvest/sdmx.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/harvest/stac.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/health.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/hosted_catalog.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/identity_history.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/neural.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/packed_catalog.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/packed_retrieval.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/packed_writer.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/query_trace.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/recommend.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/retrieval.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/retrieval_manifest.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/rights_decisions.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/sealed.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/search.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/streaming_delta.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/catalog/update.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/collections.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/contracts.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/deletion.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/fitness.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/governance.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/hosted.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/integration.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/range_reader.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/registry.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/rights_rule.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/source_cadence_vectors.v1.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/sports.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/stream.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/stream_capture_session.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/stream_connector.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/stream_connectors/polymarket.clob-market.v1.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/stream_recorder.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/stream_registry.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/stream_rotation.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/stream_series.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/sources/stream_transport.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/thin/__init__.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/thin/acquire.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/thin/acquire_cancel.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/thin/approvals.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/thin/commands.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/thin/download.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/thin/narrative.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/thin/parity.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/thin/research.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/thin/runs.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/thin/session.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/thin/stream.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/thin/transport.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/thin/vocabulary.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/thin/workers.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ucum/TABLE-PIN.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ucum/ucum-subset.v1.json +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/unit_flow.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/units.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/__init__.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/approve.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/author_yaml.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/cloud_auth.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/__init__.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/approve.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/auth.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/author.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/catalog_author.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/catalog_fill.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/catalog_harvest.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/catalog_publish.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/catalog_search.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/catalog_update.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/deploy.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/deploy_dataset.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/deploy_plan.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/deploy_status.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/diff.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/index.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/inventory.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/list_builds.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/login.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/peek.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/plan_check.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/preflight.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/record.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/review_setup.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/search.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/show.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/commands/whoami.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/credential_native.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/credential_store.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/credentials.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/diffing.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/headline.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/hosted_run_status.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/inventory.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/local_review.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/login.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/path_kind.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/peek.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/plain_file.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/plan_check.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/preflight.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/readers.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/ux/workload.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/viewer.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/visual_run/__init__.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/visual_run/authoring.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/visual_run/contracts.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/visual_run/materialize.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/visual_run/observations.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/visual_run/query.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/visual_run/reducer.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/visual_run/sdk.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/visual_run/store.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/visual_run/transport.py +0 -0
- {mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/watch.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mostlyright-data
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.8
|
|
4
4
|
Summary: Mostly Right CLI for reproducible, reviewed Parquet datasets
|
|
5
5
|
Project-URL: Homepage, https://mostlyright.md/
|
|
6
6
|
Project-URL: Documentation, https://mostlyright.md/docs/guides/cli/
|
|
@@ -126,7 +126,10 @@ The local execution lane runs only on Linux:
|
|
|
126
126
|
python -m pip install "mostlyright-data[local]"
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
-
It
|
|
129
|
+
It is not required for the hosted client, and it is off by default: `mr-data` sends that work to
|
|
130
|
+
the backend. What still runs on this computer is catalog authoring, the search index, and the
|
|
131
|
+
commands that check a document or a run folder. A command with no backend lane refuses by name and
|
|
132
|
+
says why.
|
|
130
133
|
|
|
131
134
|
## Documentation
|
|
132
135
|
|
|
@@ -138,11 +141,12 @@ It builds and checks worker inputs. It is not required for the hosted client.
|
|
|
138
141
|
Use `mr-data --help` for the full command list and options. Commands that support
|
|
139
142
|
`--json` write one JSON object.
|
|
140
143
|
|
|
141
|
-
|
|
144
|
+
`--input-root` and `--output` may use relative paths.
|
|
142
145
|
|
|
143
146
|
## Behavior and limits
|
|
144
147
|
|
|
145
|
-
- `mr-data review --local
|
|
148
|
+
- `mr-data review RUN_DIR --local` runs the deterministic checks and writes no review decision. It exits 1 when a check fails. Write the flag after the command name; before it, `--local` is the lane selector.
|
|
149
|
+
- `mr-data review RUN_DIR --report REPORT` seals a review decision from signed reviewer reports.
|
|
146
150
|
- The weather reader accepts one extracted GRIB2 record. It refuses a multi-record GFS or HRRR file.
|
|
147
151
|
- Hosted credential-free acquisition supports one single-address public HTTPS object. Bounded collections require both local attestations.
|
|
148
152
|
|
|
@@ -45,7 +45,10 @@ The local execution lane runs only on Linux:
|
|
|
45
45
|
python -m pip install "mostlyright-data[local]"
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
It
|
|
48
|
+
It is not required for the hosted client, and it is off by default: `mr-data` sends that work to
|
|
49
|
+
the backend. What still runs on this computer is catalog authoring, the search index, and the
|
|
50
|
+
commands that check a document or a run folder. A command with no backend lane refuses by name and
|
|
51
|
+
says why.
|
|
49
52
|
|
|
50
53
|
## Documentation
|
|
51
54
|
|
|
@@ -57,11 +60,12 @@ It builds and checks worker inputs. It is not required for the hosted client.
|
|
|
57
60
|
Use `mr-data --help` for the full command list and options. Commands that support
|
|
58
61
|
`--json` write one JSON object.
|
|
59
62
|
|
|
60
|
-
|
|
63
|
+
`--input-root` and `--output` may use relative paths.
|
|
61
64
|
|
|
62
65
|
## Behavior and limits
|
|
63
66
|
|
|
64
|
-
- `mr-data review --local
|
|
67
|
+
- `mr-data review RUN_DIR --local` runs the deterministic checks and writes no review decision. It exits 1 when a check fails. Write the flag after the command name; before it, `--local` is the lane selector.
|
|
68
|
+
- `mr-data review RUN_DIR --report REPORT` seals a review decision from signed reviewer reports.
|
|
65
69
|
- The weather reader accepts one extracted GRIB2 record. It refuses a multi-record GFS or HRRR file.
|
|
66
70
|
- Hosted credential-free acquisition supports one single-address public HTTPS object. Bounded collections require both local attestations.
|
|
67
71
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "mostlyright-data"
|
|
3
|
-
version = "0.9.
|
|
3
|
+
version = "0.9.8"
|
|
4
4
|
description = "Mostly Right CLI for reproducible, reviewed Parquet datasets"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.13,<3.14"
|
|
@@ -54,8 +54,10 @@ mostlyright-studio-client-v3 = { path = "vendor/wheels/mostlyright_studio_client
|
|
|
54
54
|
[project.scripts]
|
|
55
55
|
# ⚠ NOT `cli:main`. `cli` imports `hosted_worker`, which imports pyarrow and cryptography at module
|
|
56
56
|
# scope, so `cli` cannot even be IMPORTED on a thin install. The router is the one module that can
|
|
57
|
-
# run on a bare interpreter and decide which lane this invocation belongs to
|
|
58
|
-
# extra present it hands
|
|
57
|
+
# run on a bare interpreter and decide which lane this invocation belongs to. The local product
|
|
58
|
+
# lanes are off by default, so with the `local` extra present it hands the names that still run on
|
|
59
|
+
# this computer to `cli.main` unchanged, and every other name is answered by the hosted lane or
|
|
60
|
+
# told, by name, that this computer no longer runs it.
|
|
59
61
|
mr-data = "mostlyright.data_harness.thin.router:main"
|
|
60
62
|
# ⚠ AND NOT THE MODULES THEMSELVES, for the same reason. Each of these seven is defined in a
|
|
61
63
|
# module that imports pyarrow or cryptography at module scope -- or, for the catalogue job, reaches
|
|
@@ -59,6 +59,7 @@ from mostlyright.data_harness.acquisition.url_policy import (
|
|
|
59
59
|
AcquisitionSecurityError,
|
|
60
60
|
EgressPolicy,
|
|
61
61
|
SystemResolver,
|
|
62
|
+
canonical_peer_order,
|
|
62
63
|
validate_public_https_url,
|
|
63
64
|
)
|
|
64
65
|
from mostlyright.data_harness.canonical import canonical_sha256, sha256_bytes
|
|
@@ -3011,7 +3012,10 @@ def _parse_approved_endpoints(
|
|
|
3011
3012
|
)
|
|
3012
3013
|
normalized.append(address.compressed)
|
|
3013
3014
|
key = (hostname, port)
|
|
3014
|
-
|
|
3015
|
+
# The SAME order `url_policy.canonical_peer_order` writes, read from that function rather
|
|
3016
|
+
# than restated: the parent decides connection order there, and a second sorting rule here
|
|
3017
|
+
# would refuse the very sets the parent now produces (#351).
|
|
3018
|
+
if key in endpoints or canonical_peer_order(normalized) != addresses:
|
|
3015
3019
|
raise AcquisitionSecurityError(
|
|
3016
3020
|
"SANDBOX_EGRESS",
|
|
3017
3021
|
"approved endpoint set is duplicate or non-canonical",
|
|
@@ -6,6 +6,7 @@ import ipaddress
|
|
|
6
6
|
import re
|
|
7
7
|
import socket
|
|
8
8
|
import unicodedata
|
|
9
|
+
from collections.abc import Iterable
|
|
9
10
|
from dataclasses import dataclass
|
|
10
11
|
from typing import Protocol
|
|
11
12
|
from urllib.parse import SplitResult, urlsplit, urlunsplit
|
|
@@ -188,6 +189,31 @@ class ValidatedTarget:
|
|
|
188
189
|
return urlunsplit(("", "", parsed.path or "/", parsed.query, ""))
|
|
189
190
|
|
|
190
191
|
|
|
192
|
+
def canonical_peer_order(addresses: Iterable[str]) -> tuple[str, ...]:
|
|
193
|
+
"""The one order an approved peer set is ever written in: IPv4 first, then lexicographic.
|
|
194
|
+
|
|
195
|
+
⚠ THIS IS A CONNECTION ORDER, NOT ONLY A CANONICAL FORM. A fetch spends a bounded request
|
|
196
|
+
budget (``max_requests``, four) walking this tuple, so whatever sorts first is what an
|
|
197
|
+
IPv4-only deployment -- every Cloud Run job -- actually dials. Plain lexicographic sorting put
|
|
198
|
+
``2606:…`` ahead of ``3.x``/``34.x``/``52.x``, which is precisely the A-record shape every
|
|
199
|
+
Fastly and CloudFront host has, so an IPv6-unroutable worker burned its whole budget on AAAA
|
|
200
|
+
candidates and died ``REQUEST_LIMIT`` before reaching a routable address (#351).
|
|
201
|
+
|
|
202
|
+
Family first is therefore the rule, and it is a rule rather than a preference expressed in the
|
|
203
|
+
resolver: ordering is decided HERE, and ``sandbox._parse_approved_endpoints`` refuses an
|
|
204
|
+
endpoint set that is not in this exact order, so the two must move together. Within a family
|
|
205
|
+
the order stays lexicographic on the compressed text, which keeps the set canonical -- the
|
|
206
|
+
resolution digest is computed over it -- and keeps it independent of resolver answer order.
|
|
207
|
+
"""
|
|
208
|
+
|
|
209
|
+
return tuple(
|
|
210
|
+
sorted(
|
|
211
|
+
dict.fromkeys(addresses),
|
|
212
|
+
key=lambda address: (0 if ipaddress.ip_address(address).version == 4 else 1, address),
|
|
213
|
+
)
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
|
|
191
217
|
def approved_public_addresses(
|
|
192
218
|
hostname: str,
|
|
193
219
|
port: int,
|
|
@@ -233,7 +259,7 @@ def approved_public_addresses(
|
|
|
233
259
|
) from None
|
|
234
260
|
_require_globally_routable(address)
|
|
235
261
|
approved.append(address.compressed)
|
|
236
|
-
approved_ips =
|
|
262
|
+
approved_ips = canonical_peer_order(dict.fromkeys(approved))
|
|
237
263
|
if not approved_ips:
|
|
238
264
|
raise AcquisitionSecurityError("DNS_EMPTY", "target has no approved public addresses")
|
|
239
265
|
if len(approved_ips) > MAX_DNS_ANSWERS:
|
|
@@ -2260,7 +2260,29 @@ def _require_verify_url(value: str) -> str:
|
|
|
2260
2260
|
|
|
2261
2261
|
|
|
2262
2262
|
def _agent_workflow_surface() -> dict[str, Any]:
|
|
2263
|
-
"""Return the versioned discovery surface for external data agents.
|
|
2263
|
+
"""Return the versioned discovery surface for external data agents.
|
|
2264
|
+
|
|
2265
|
+
``implementation_status`` says where a stage runs, and the three values partition the stages
|
|
2266
|
+
rather than describing them: exactly one is true of any stage, and which one is decided by the
|
|
2267
|
+
surface beside it rather than by how the stage feels.
|
|
2268
|
+
|
|
2269
|
+
* ``available`` -- every command the surface names runs from this command line, with no
|
|
2270
|
+
backend: the kept lane-``local`` names and the portable ones.
|
|
2271
|
+
* ``hosted_only`` -- the surface names only hosted-lane commands. The stage still happens, and
|
|
2272
|
+
the named commands are how it is asked for and reported on; what is not true of it is that
|
|
2273
|
+
this computer performs it. A hosted-lane command is not a skipped stage.
|
|
2274
|
+
* ``backend_internal`` -- a backend operator step: it has a name, and nobody runs it from here.
|
|
2275
|
+
|
|
2276
|
+
⚠ THE STATUS IS THE PROMISE, SO IT IS NOT DECORATION. An agent chooses its route from this
|
|
2277
|
+
payload, and a stage that says ``available`` about a command which exits 2 sends the agent to
|
|
2278
|
+
a refusal it will read as a defect and retry. The word has to be the answer the command would
|
|
2279
|
+
actually give.
|
|
2280
|
+
|
|
2281
|
+
⚠ AND A SURFACE NAMED TWICE IS CLASSIFIED ONCE. ``view`` appears under two stages; both say
|
|
2282
|
+
``hosted_only``, because the same command cannot run here in one row and on the backend in the
|
|
2283
|
+
next. ``tests/test_agent_workflow_cli.py`` derives both halves of the partition from the live
|
|
2284
|
+
lane table, so a command that changes lane fails there rather than drifting.
|
|
2285
|
+
"""
|
|
2264
2286
|
|
|
2265
2287
|
return {
|
|
2266
2288
|
"schema_version": "mr-data-agent-workflow.v4",
|
|
@@ -2269,9 +2291,9 @@ def _agent_workflow_surface() -> dict[str, Any]:
|
|
|
2269
2291
|
"stages": [
|
|
2270
2292
|
{
|
|
2271
2293
|
"stage": "viewer_observability",
|
|
2272
|
-
"implementation_status": "
|
|
2294
|
+
"implementation_status": "hosted_only",
|
|
2273
2295
|
"judgment_owner": "external_agent",
|
|
2274
|
-
"deterministic_surface": "mr-data view",
|
|
2296
|
+
"deterministic_surface": "mr-data watch/view",
|
|
2275
2297
|
},
|
|
2276
2298
|
{
|
|
2277
2299
|
"stage": "question_and_requirements",
|
|
@@ -2299,15 +2321,15 @@ def _agent_workflow_surface() -> dict[str, Any]:
|
|
|
2299
2321
|
},
|
|
2300
2322
|
{
|
|
2301
2323
|
"stage": "recipe_approval",
|
|
2302
|
-
"implementation_status": "
|
|
2324
|
+
"implementation_status": "hosted_only",
|
|
2303
2325
|
"judgment_owner": "human",
|
|
2304
2326
|
"deterministic_surface": "mr-data recipe-approve",
|
|
2305
2327
|
},
|
|
2306
2328
|
{
|
|
2307
2329
|
"stage": "acquire_clean_join_validate_package",
|
|
2308
|
-
"implementation_status": "
|
|
2330
|
+
"implementation_status": "hosted_only",
|
|
2309
2331
|
"judgment_owner": "deterministic_worker",
|
|
2310
|
-
"deterministic_surface": "mr-data
|
|
2332
|
+
"deterministic_surface": "mr-data run/status",
|
|
2311
2333
|
},
|
|
2312
2334
|
{
|
|
2313
2335
|
"stage": "independent_review",
|
|
@@ -2317,19 +2339,19 @@ def _agent_workflow_surface() -> dict[str, Any]:
|
|
|
2317
2339
|
},
|
|
2318
2340
|
{
|
|
2319
2341
|
"stage": "independent_verification",
|
|
2320
|
-
"implementation_status": "
|
|
2342
|
+
"implementation_status": "hosted_only",
|
|
2321
2343
|
"judgment_owner": "deterministic_verifier",
|
|
2322
2344
|
"deterministic_surface": "mr-data verify/status/inspect",
|
|
2323
2345
|
},
|
|
2324
2346
|
{
|
|
2325
2347
|
"stage": "handoff",
|
|
2326
|
-
"implementation_status": "
|
|
2348
|
+
"implementation_status": "hosted_only",
|
|
2327
2349
|
"judgment_owner": "external_agent",
|
|
2328
2350
|
"deterministic_surface": "mr-data notebook/view",
|
|
2329
2351
|
},
|
|
2330
2352
|
{
|
|
2331
2353
|
"stage": "hosted_export",
|
|
2332
|
-
"implementation_status": "
|
|
2354
|
+
"implementation_status": "backend_internal",
|
|
2333
2355
|
"judgment_owner": "external_agent",
|
|
2334
2356
|
"deterministic_surface": "mr-data export-hosted-candidate",
|
|
2335
2357
|
},
|
{mostlyright_data-0.9.6 → mostlyright_data-0.9.8}/src/mostlyright/data_harness/hosted_bootstrap.py
RENAMED
|
@@ -22,7 +22,7 @@ from datetime import UTC, datetime
|
|
|
22
22
|
from pathlib import Path
|
|
23
23
|
from typing import Any, NoReturn, Protocol
|
|
24
24
|
from urllib.error import HTTPError
|
|
25
|
-
from urllib.parse import urlencode, urlsplit
|
|
25
|
+
from urllib.parse import urlencode, urlsplit, urlunsplit
|
|
26
26
|
from urllib.request import (
|
|
27
27
|
HTTPRedirectHandler,
|
|
28
28
|
HTTPSHandler,
|
|
@@ -42,6 +42,7 @@ from mostlyright.data_harness.governors import (
|
|
|
42
42
|
Reservation,
|
|
43
43
|
)
|
|
44
44
|
from mostlyright.data_harness.hosted_worker import (
|
|
45
|
+
CRAWLER_RESULTS_BUCKET_ENV,
|
|
45
46
|
MAX_CAPABILITY_BYTES,
|
|
46
47
|
MAX_DESCRIPTOR_BYTES,
|
|
47
48
|
MAX_SIGNING_KEY_BYTES,
|
|
@@ -62,6 +63,7 @@ BOOTSTRAP_REQUEST_SCHEMA = "mostlyright-worker-bootstrap-request.v3"
|
|
|
62
63
|
BOOTSTRAP_RESPONSE_SCHEMA = "mostlyright-worker-bootstrap-response.v3"
|
|
63
64
|
GENERIC_PROBE_BOOTSTRAP_RESPONSE_SCHEMA = "mostlyright-worker-bootstrap-response.v5"
|
|
64
65
|
BOOTSTRAP_EXCHANGE_PATH = "/_internal/worker-bootstrap:exchange"
|
|
66
|
+
BOOTSTRAP_FAILURE_PATH = "/_internal/worker-bootstrap:fail"
|
|
65
67
|
GENERIC_PROBE_BOOTSTRAP_EXCHANGE_PATH = "/_internal/generic-api-probe-bootstrap:exchange"
|
|
66
68
|
METADATA_IDENTITY_URL = (
|
|
67
69
|
"http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/identity"
|
|
@@ -69,6 +71,21 @@ METADATA_IDENTITY_URL = (
|
|
|
69
71
|
MAX_IDENTITY_BYTES = 16 * 1024
|
|
70
72
|
MAX_BOOTSTRAP_RESPONSE_BYTES = 768 * 1024
|
|
71
73
|
BOOTSTRAP_TIMEOUT_SECONDS = 10.0
|
|
74
|
+
#: Exchange refusals worth waiting out. Everything else in 4xx is Studio's final answer for this
|
|
75
|
+
#: dispatch, so the attempt is dead and something has to say so before this process exits.
|
|
76
|
+
RETRYABLE_EXCHANGE_STATUSES = frozenset({408, 425, 429})
|
|
77
|
+
#: The closed set of reasons a bootstrap can report before it holds a job, one per refusal it can
|
|
78
|
+
#: be told. Keep it closed in lock-step with Studio's accepted set: a code Studio does not know is
|
|
79
|
+
#: refused, the report is lost, and the run waits for the stuck-run poller instead.
|
|
80
|
+
EXCHANGE_REFUSAL_CODES = {
|
|
81
|
+
400: "BOOTSTRAP_EXCHANGE_REJECTED",
|
|
82
|
+
401: "BOOTSTRAP_IDENTITY_REJECTED",
|
|
83
|
+
403: "BOOTSTRAP_IDENTITY_REJECTED",
|
|
84
|
+
404: "BOOTSTRAP_DISPATCH_UNCLAIMABLE",
|
|
85
|
+
409: "BOOTSTRAP_DISPATCH_UNCLAIMABLE",
|
|
86
|
+
410: "BOOTSTRAP_DISPATCH_UNCLAIMABLE",
|
|
87
|
+
422: "BOOTSTRAP_EXCHANGE_REJECTED",
|
|
88
|
+
}
|
|
72
89
|
WORKER_BIN_DIRECTORY = Path("/opt/worker/bin")
|
|
73
90
|
_JWT = re.compile(r"^[A-Za-z0-9_-]{1,8192}\.[A-Za-z0-9_-]{1,8192}\.[A-Za-z0-9_-]{1,8192}$")
|
|
74
91
|
_DISPATCH_QUERY = re.compile(
|
|
@@ -284,6 +301,14 @@ def _local_validation_policy_digests() -> dict[str, str]:
|
|
|
284
301
|
|
|
285
302
|
|
|
286
303
|
def _require_local_policy_binding(binding: WorkerPolicyBinding) -> None:
|
|
304
|
+
"""Fail a misdeployed image before it spends an exchange. Not the authority on a run.
|
|
305
|
+
|
|
306
|
+
The run's own authority is the sealed preflight, which ``_require_worker_policy_preflight``
|
|
307
|
+
holds against this same runtime. This one only catches an image whose deployment record and
|
|
308
|
+
whose code disagree, which no run can be sealed correctly against, and it catches it one
|
|
309
|
+
round trip earlier.
|
|
310
|
+
"""
|
|
311
|
+
|
|
287
312
|
local = _local_validation_policy_digests()
|
|
288
313
|
if binding.validation_policy_digests != local:
|
|
289
314
|
deployed = canonical_json_bytes(binding.validation_policy_digests).decode("utf-8")
|
|
@@ -434,6 +459,46 @@ def _metadata_identity(
|
|
|
434
459
|
return bytearray(raw)
|
|
435
460
|
|
|
436
461
|
|
|
462
|
+
def _report_attempt_failure(
|
|
463
|
+
config: BootstrapConfig,
|
|
464
|
+
transport: BootstrapTransport,
|
|
465
|
+
identity: bytearray,
|
|
466
|
+
status: int,
|
|
467
|
+
) -> bool:
|
|
468
|
+
"""Tell Studio, best effort, that this attempt will never start. Return whether it landed.
|
|
469
|
+
|
|
470
|
+
A refused bootstrap is the one failure the attempt itself cannot report: the process holds no
|
|
471
|
+
job, no capability and no attempt id, so nothing downstream of it will ever call ``fail``. Left
|
|
472
|
+
silent, the run sits in "running" until a human notices. This is the cheapest way to close that
|
|
473
|
+
gap, not the guarantee -- Studio's stuck-run poller is what actually guarantees it, so a report
|
|
474
|
+
that cannot be delivered changes nothing about how this process exits.
|
|
475
|
+
|
|
476
|
+
It reuses the attempt's own identity token, sends only the allowlisted refusal code in
|
|
477
|
+
canonical bytes on the ``:fail`` sibling of the exchange route, and accepts only an empty 204.
|
|
478
|
+
Nothing a compromised Studio could answer here can cross back into the worker.
|
|
479
|
+
"""
|
|
480
|
+
|
|
481
|
+
code = EXCHANGE_REFUSAL_CODES.get(status)
|
|
482
|
+
if code is None:
|
|
483
|
+
return False
|
|
484
|
+
parsed = urlsplit(config.exchange_url)
|
|
485
|
+
try:
|
|
486
|
+
reported, raw = transport.request(
|
|
487
|
+
"POST",
|
|
488
|
+
urlunsplit((parsed.scheme, parsed.netloc, BOOTSTRAP_FAILURE_PATH, parsed.query, "")),
|
|
489
|
+
{
|
|
490
|
+
"Accept": "application/json",
|
|
491
|
+
"Authorization": "Bearer " + identity.decode("ascii"),
|
|
492
|
+
"Content-Type": "application/json",
|
|
493
|
+
},
|
|
494
|
+
canonical_json_bytes({"failure_code": code}),
|
|
495
|
+
0,
|
|
496
|
+
)
|
|
497
|
+
except Exception:
|
|
498
|
+
return False
|
|
499
|
+
return reported == 204 and not raw
|
|
500
|
+
|
|
501
|
+
|
|
437
502
|
def _exchange(
|
|
438
503
|
config: BootstrapConfig,
|
|
439
504
|
transport: BootstrapTransport,
|
|
@@ -457,6 +522,14 @@ def _exchange(
|
|
|
457
522
|
MAX_BOOTSTRAP_RESPONSE_BYTES,
|
|
458
523
|
)
|
|
459
524
|
if status != 200:
|
|
525
|
+
# The generic API probe is excluded on purpose: it has no run and no attempt behind it, so
|
|
526
|
+
# there is no state anywhere that a report would move off "running".
|
|
527
|
+
if (
|
|
528
|
+
config.role != "generic_api"
|
|
529
|
+
and 400 <= status < 500
|
|
530
|
+
and status not in RETRYABLE_EXCHANGE_STATUSES
|
|
531
|
+
):
|
|
532
|
+
_report_attempt_failure(config, transport, identity, status)
|
|
460
533
|
raise HostedWorkerError(
|
|
461
534
|
"BOOTSTRAP_EXCHANGE_FAILED",
|
|
462
535
|
f"Studio bootstrap exchange returned HTTP {status}",
|
|
@@ -475,9 +548,19 @@ def _require_worker_policy_preflight(
|
|
|
475
548
|
job_wire: Any,
|
|
476
549
|
job: Any,
|
|
477
550
|
response_preflight: Any,
|
|
478
|
-
binding: WorkerPolicyBinding,
|
|
479
551
|
) -> None:
|
|
480
|
-
"""Bind the
|
|
552
|
+
"""Bind the Studio response, the sealed preflight and the parsed recipe before execution.
|
|
553
|
+
|
|
554
|
+
The sealed preflight is the run's single fleet authority. The image digests, selection id and
|
|
555
|
+
release fence it names are deliberately NOT re-compared against a second copy carried in this
|
|
556
|
+
worker's environment: that mirror could only ever say "the fleet moved on since this run was
|
|
557
|
+
sealed", which is not a reason to refuse a run whose tooling was chosen for it. Nine hosted
|
|
558
|
+
builds died as WORKER_POLICY_BINDING_MISMATCH saying exactly that.
|
|
559
|
+
|
|
560
|
+
What survives is everything the traveler can be held to without a second copy: both preflight
|
|
561
|
+
copies agree, the field set is exact, it names this job's scope and this recipe's mode, its
|
|
562
|
+
policy set is internally consistent, and that policy set is the one this runtime implements.
|
|
563
|
+
"""
|
|
481
564
|
|
|
482
565
|
if not isinstance(job_wire, dict):
|
|
483
566
|
raise HostedWorkerError(
|
|
@@ -524,6 +607,7 @@ def _require_worker_policy_preflight(
|
|
|
524
607
|
"table_recipe_id": job.table_recipe_id,
|
|
525
608
|
"recipe_version": job.recipe_version,
|
|
526
609
|
"recipe_digest": job.documents.recipe_digest,
|
|
610
|
+
"policy_mode": mode,
|
|
527
611
|
}
|
|
528
612
|
if any(job_preflight.get(name) != value for name, value in expected_scope.items()) or (
|
|
529
613
|
"table_id" in job_preflight and job_preflight["table_id"] != str(job.table_id)
|
|
@@ -532,21 +616,41 @@ def _require_worker_policy_preflight(
|
|
|
532
616
|
"WORKER_POLICY_BINDING_MISMATCH",
|
|
533
617
|
"worker policy preflight scope differs from the bootstrap job",
|
|
534
618
|
)
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
"
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
619
|
+
digests = job_preflight["validation_policy_digests"]
|
|
620
|
+
# Shape first, and before anything renders it. The refusals below quote the sealed set back as
|
|
621
|
+
# canonical JSON, and canonical JSON is a narrower dialect than the one the response was parsed
|
|
622
|
+
# in -- a non-integer number inside this field would raise out of the renderer, past the coded
|
|
623
|
+
# refusal it was rendering, and reach the operator as a traceback with no code on it.
|
|
624
|
+
if (
|
|
625
|
+
not isinstance(digests, dict)
|
|
626
|
+
or set(digests) != {"table", "graph"}
|
|
627
|
+
or any(not isinstance(digest, str) for digest in digests.values())
|
|
628
|
+
):
|
|
629
|
+
raise HostedWorkerError(
|
|
630
|
+
"WORKER_POLICY_BINDING_MISMATCH",
|
|
631
|
+
"worker policy preflight validation policy set is not one table and graph digest pair",
|
|
632
|
+
)
|
|
633
|
+
# The runtime is the authority on which validation policy this image implements, so the sealed
|
|
634
|
+
# set is checked against the code rather than against a deployment variable claiming to
|
|
635
|
+
# describe the code. A run sealed under a policy this image does not implement would attest to
|
|
636
|
+
# a check it never ran.
|
|
637
|
+
local = _local_validation_policy_digests()
|
|
638
|
+
if digests != local:
|
|
639
|
+
sealed = canonical_json_bytes(digests).decode("utf-8")
|
|
640
|
+
computed = canonical_json_bytes(local).decode("utf-8")
|
|
641
|
+
raise HostedWorkerError(
|
|
642
|
+
"WORKER_POLICY_RUNTIME_MISMATCH",
|
|
643
|
+
f"sealed validation policy set {sealed} differs from this worker runtime {computed}; "
|
|
644
|
+
"launch this run on the worker image its preflight sealed",
|
|
645
|
+
)
|
|
646
|
+
if (
|
|
647
|
+
job_preflight["validation_policy_digest"] != digests[mode]
|
|
648
|
+
or job_preflight["policy_set_digest"]
|
|
649
|
+
!= "sha256:" + hashlib.sha256(canonical_json_bytes(digests)).hexdigest()
|
|
650
|
+
):
|
|
547
651
|
raise HostedWorkerError(
|
|
548
652
|
"WORKER_POLICY_BINDING_MISMATCH",
|
|
549
|
-
"worker policy preflight
|
|
653
|
+
"worker policy preflight does not carry one self-consistent policy set",
|
|
550
654
|
)
|
|
551
655
|
|
|
552
656
|
|
|
@@ -611,7 +715,6 @@ def _validate_bootstrap_response(
|
|
|
611
715
|
job_wire=job_wire,
|
|
612
716
|
job=parsed_job,
|
|
613
717
|
response_preflight=value["worker_policy_preflight"],
|
|
614
|
-
binding=worker_policy_binding,
|
|
615
718
|
)
|
|
616
719
|
return {"job": job_raw, "capability": capability_raw}, parsed_job
|
|
617
720
|
|
|
@@ -625,7 +728,6 @@ def _validate_bootstrap_response(
|
|
|
625
728
|
job_wire=job_wire,
|
|
626
729
|
job=parsed_job,
|
|
627
730
|
response_preflight=value["worker_policy_preflight"],
|
|
628
|
-
binding=worker_policy_binding,
|
|
629
731
|
)
|
|
630
732
|
signing_key = value["signing_key"]
|
|
631
733
|
parse_signing_key(signing_key)
|
|
@@ -977,6 +1079,19 @@ def launch(
|
|
|
977
1079
|
"PYTHONDONTWRITEBYTECODE": "1",
|
|
978
1080
|
"PYTHONUNBUFFERED": "1",
|
|
979
1081
|
}
|
|
1082
|
+
# The hygiene exec strips the inherited environment so no credential can leak into
|
|
1083
|
+
# the worker -- and it must keep doing so. But the crawler-results bucket is a public
|
|
1084
|
+
# deployment coordinate, not a secret: it names which GCS bucket a result download's
|
|
1085
|
+
# storage authority may claim, the worker's download check refuses every GCS-served
|
|
1086
|
+
# crawl without it, and the deploy pins it on the job for exactly that check. It is
|
|
1087
|
+
# the ONE inherited name that crosses; anything else stays stripped.
|
|
1088
|
+
# It is the FALLBACK, not the source: a job that carries `results_bucket` travels with
|
|
1089
|
+
# its own pin and the worker prefers that one. This pass-through covers dispatch
|
|
1090
|
+
# payloads minted before the traveler did; it retires once every dispatch mints
|
|
1091
|
+
# the field.
|
|
1092
|
+
results_bucket = os.environ.get(CRAWLER_RESULTS_BUCKET_ENV)
|
|
1093
|
+
if results_bucket:
|
|
1094
|
+
environment[CRAWLER_RESULTS_BUCKET_ENV] = results_bucket
|
|
980
1095
|
allowed = {payload.descriptor for payload in descriptors.values()}
|
|
981
1096
|
changed = _restrict_inherited_descriptors(allowed)
|
|
982
1097
|
try:
|
|
@@ -997,21 +1112,47 @@ def launch(
|
|
|
997
1112
|
|
|
998
1113
|
|
|
999
1114
|
def main(argv: Sequence[str] | None = None) -> int:
|
|
1115
|
+
"""Parse one Cloud Run Job dispatch and launch the bootstrap it names.
|
|
1116
|
+
|
|
1117
|
+
Two dispatch spellings reach this executable, because two Studio enqueuers write them and
|
|
1118
|
+
each names the coordinate it carries. A Builder or verifier task carries
|
|
1119
|
+
``--exchange-url ...?dispatch_id=<uuid> --role {producer,verifier}``. A standalone generic
|
|
1120
|
+
API probe carries ``--generic-api-probe-bootstrap-url ...?probe_id=<uuid>`` and no ``--role``
|
|
1121
|
+
at all: the flag names the probe exchange, so the role is not a second thing to state and
|
|
1122
|
+
Studio's ``GoogleCloudTasksGenericApiProbeEnqueuer`` does not state it.
|
|
1123
|
+
|
|
1124
|
+
Accepting only the first spelling is what made the hosted keyed-source probe lane
|
|
1125
|
+
unreachable: argparse rejected the deployed probe task's argv outright (``unrecognized
|
|
1126
|
+
arguments`` plus a missing ``--role``) and the Job exited 2 before a single line of bootstrap
|
|
1127
|
+
code ran. ``tests/test_hosted_bootstrap.py`` holds this parser against the argv Studio's own
|
|
1128
|
+
``dispatch.py`` emits, so the two cannot drift apart again silently.
|
|
1129
|
+
"""
|
|
1130
|
+
|
|
1000
1131
|
parser = argparse.ArgumentParser()
|
|
1001
|
-
parser.
|
|
1132
|
+
source = parser.add_mutually_exclusive_group(required=True)
|
|
1133
|
+
source.add_argument("--exchange-url")
|
|
1134
|
+
source.add_argument("--generic-api-probe-bootstrap-url")
|
|
1002
1135
|
parser.add_argument("--audience", required=True)
|
|
1003
|
-
parser.add_argument("--role",
|
|
1136
|
+
parser.add_argument("--role", choices=("producer", "verifier", "generic_api"))
|
|
1004
1137
|
arguments = parser.parse_args(argv)
|
|
1138
|
+
if arguments.generic_api_probe_bootstrap_url is not None:
|
|
1139
|
+
if arguments.role not in {None, "generic_api"}:
|
|
1140
|
+
parser.error("--generic-api-probe-bootstrap-url admits only --role generic_api")
|
|
1141
|
+
exchange_url = arguments.generic_api_probe_bootstrap_url
|
|
1142
|
+
role = "generic_api"
|
|
1143
|
+
else:
|
|
1144
|
+
if arguments.role is None:
|
|
1145
|
+
parser.error("--exchange-url requires --role")
|
|
1146
|
+
exchange_url = arguments.exchange_url
|
|
1147
|
+
role = arguments.role
|
|
1005
1148
|
try:
|
|
1006
1149
|
launch(
|
|
1007
1150
|
BootstrapConfig(
|
|
1008
|
-
exchange_url=
|
|
1151
|
+
exchange_url=exchange_url,
|
|
1009
1152
|
audience=arguments.audience,
|
|
1010
|
-
role=
|
|
1153
|
+
role=role,
|
|
1011
1154
|
worker_policy_binding=(
|
|
1012
|
-
None
|
|
1013
|
-
if arguments.role == "generic_api"
|
|
1014
|
-
else _binding_from_environment(os.environ)
|
|
1155
|
+
None if role == "generic_api" else _binding_from_environment(os.environ)
|
|
1015
1156
|
),
|
|
1016
1157
|
)
|
|
1017
1158
|
)
|
|
@@ -139,7 +139,15 @@ def _public_https_retriever(
|
|
|
139
139
|
max_concurrency=2,
|
|
140
140
|
min_interval_seconds=1.0,
|
|
141
141
|
allowed_media_types=_public_expected_media_types(request.query),
|
|
142
|
-
|
|
142
|
+
# The contact URL is load-bearing, not decoration: Akamai-fronted
|
|
143
|
+
# providers (stlouisfed.org, measured 2026-08-27 in harness#430)
|
|
144
|
+
# silently tarpit a bare unknown product token - RST on h2, a
|
|
145
|
+
# 15s+ hang on http/1.1 that surfaces as the acquisition timeout -
|
|
146
|
+
# while the same token WITH the crawler-convention "(+URL)"
|
|
147
|
+
# segment answers in half a second from the same egress IP. An
|
|
148
|
+
# honest identity that names where to reach us is also simply the
|
|
149
|
+
# right thing for a public crawler to send.
|
|
150
|
+
user_agent="MostlyRightDataHarness-PublicHttps/1.0 (+https://mostlyright.md/crawler)",
|
|
143
151
|
),
|
|
144
152
|
limiter=_PUBLIC_HTTPS_LIMITER,
|
|
145
153
|
)
|