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,657 @@
|
|
|
1
|
+
"""Plain-language rendering of the payload mappings the CLI already emits as JSON.
|
|
2
|
+
|
|
3
|
+
The renderer is a pure function over the payload mapping: it never re-reads a written file, never
|
|
4
|
+
touches the environment, and never inspects an exception's cause or traceback. That is what keeps
|
|
5
|
+
``cli._snapshot_result_receipt``'s claim honest -- the plain rendering and the ``--json`` rendering
|
|
6
|
+
carry the same facts from the same dict, so neither can quietly say more than the other.
|
|
7
|
+
|
|
8
|
+
Nothing here prints. Every function returns a string, so the same facts can be rendered into a
|
|
9
|
+
browser page later without re-deriving them.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from collections.abc import Mapping, Sequence
|
|
15
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
# Plain names for the payload keys a user or their agent reads. Internal identifiers keep their
|
|
18
|
+
# engineering-precise spelling; only the label shown to a human moves (docs/VOCABULARY.md).
|
|
19
|
+
PLAIN_LABELS: dict[str, str] = {
|
|
20
|
+
# Identity of a build
|
|
21
|
+
# The bare key is mapped as well as the compounds: an unmapped key falls back to the key's own
|
|
22
|
+
# spelling, and that fallback is a label no sweep of the source can see, because it is built at
|
|
23
|
+
# render time rather than written down anywhere.
|
|
24
|
+
"candidate": "Build",
|
|
25
|
+
"candidate_digest": "Build fingerprint",
|
|
26
|
+
"candidate_contract_version": "Build contract version",
|
|
27
|
+
"producer_principal": "Built by",
|
|
28
|
+
"producer_attempt": "Build attempt",
|
|
29
|
+
"table_sha256": "Data fingerprint",
|
|
30
|
+
"manifest_version": "Receipt version",
|
|
31
|
+
"validation_policy_digest": "Checks fingerprint",
|
|
32
|
+
"row_count": "Rows",
|
|
33
|
+
"columns": "Columns",
|
|
34
|
+
# Looking at a file or an address before anything is built
|
|
35
|
+
"source": "Looked at",
|
|
36
|
+
"origin": "Opened from",
|
|
37
|
+
"data_format": "Format",
|
|
38
|
+
"input_sha256": "Bytes fingerprint",
|
|
39
|
+
"content_sha256": "Content fingerprint",
|
|
40
|
+
"schema_digest": "Schema fingerprint",
|
|
41
|
+
"schema": "Column facts",
|
|
42
|
+
"sample": "First rows",
|
|
43
|
+
"fetched_from": "Fetched from",
|
|
44
|
+
"saved_to_disk": "Saved to disk",
|
|
45
|
+
"null_count": "Missing values",
|
|
46
|
+
"distinct_count": "Different values",
|
|
47
|
+
"minimum": "Lowest",
|
|
48
|
+
"maximum": "Highest",
|
|
49
|
+
"grain": "One row per",
|
|
50
|
+
"engine": "Engine",
|
|
51
|
+
# Recipes and approvals
|
|
52
|
+
"recipe_id": "Recipe ID",
|
|
53
|
+
"recipe_version": "Recipe version",
|
|
54
|
+
"recipe_digest": "Recipe fingerprint",
|
|
55
|
+
"predecessor_recipe_digest": "Previous recipe fingerprint",
|
|
56
|
+
"approval_id": "Approval ID",
|
|
57
|
+
"approval_digest": "Approval fingerprint",
|
|
58
|
+
"approval_policy_digest": "Approval policy fingerprint",
|
|
59
|
+
"approved_by": "Approved by",
|
|
60
|
+
"approved_at": "Approved at",
|
|
61
|
+
"execution_digest": "Run-settings fingerprint",
|
|
62
|
+
"execution_mode": "Run mode",
|
|
63
|
+
# Review
|
|
64
|
+
"decision_digest": "Decision fingerprint",
|
|
65
|
+
"review_decision_digest": "Review decision fingerprint",
|
|
66
|
+
"acquisition_bundle_digest": "Acquisition evidence fingerprint",
|
|
67
|
+
"review_dir": "Review folder",
|
|
68
|
+
"review_authority": "Who verified this",
|
|
69
|
+
"review_record": "Review record",
|
|
70
|
+
"signed_report": "Signed report",
|
|
71
|
+
"release_eligible": "Ready to go live",
|
|
72
|
+
"drift_report": "Drift alert",
|
|
73
|
+
# Places
|
|
74
|
+
"workspace": "Workbench folder",
|
|
75
|
+
"run_dir": "Build folder",
|
|
76
|
+
"root": "Folder looked in",
|
|
77
|
+
"output": "Wrote",
|
|
78
|
+
"input_root": "Input folder",
|
|
79
|
+
"member_paths": "Receipt contents",
|
|
80
|
+
# Records and receipts
|
|
81
|
+
"schema_version": "Record version",
|
|
82
|
+
"run_id": "Run ID",
|
|
83
|
+
# One deployed run's own state, as Studio holds it. The key spellings stay Studio's; only
|
|
84
|
+
# these labels move, and `repair_task_id` moves because its own fallback label would print
|
|
85
|
+
# the internal name for a fix-it task at somebody sitting at a terminal.
|
|
86
|
+
"run_status": "Run state",
|
|
87
|
+
# `run_disposition`, not `disposition`: the bare key is already a field of the local search
|
|
88
|
+
# trace, and a label declared here reaches every payload that carries the key. Naming this one
|
|
89
|
+
# for the run keeps a label written for a deployed run out of an unrelated command's output.
|
|
90
|
+
"run_disposition": "Where this stands",
|
|
91
|
+
"run_seconds": "Run took, in seconds",
|
|
92
|
+
"watch_limit_seconds": "Waited at most, in seconds",
|
|
93
|
+
"repair_task_id": "Fix-it task ID",
|
|
94
|
+
"revision": "Revision",
|
|
95
|
+
"state_phase": "Stage",
|
|
96
|
+
"publication": "File receipt",
|
|
97
|
+
"expected_size_bytes": "Size in bytes",
|
|
98
|
+
"expected_content_digest": "Content fingerprint",
|
|
99
|
+
"output_bytes": "Bytes written",
|
|
100
|
+
"output_bytes_sha256": "Written-bytes fingerprint",
|
|
101
|
+
"media_type": "Media type",
|
|
102
|
+
"request_sha256": "Request fingerprint",
|
|
103
|
+
"evidence_authority": "Authoritative record",
|
|
104
|
+
"file_observed": "File seen on disk",
|
|
105
|
+
"linearization_point": "Observed at",
|
|
106
|
+
"namespace_linearization": "Observed at",
|
|
107
|
+
"post_linearization_path_persistence": "After this observation",
|
|
108
|
+
"authority": "Authority",
|
|
109
|
+
"hosted_release": "Live in Studio",
|
|
110
|
+
"successor_repair_closure": "Fix-it cycle closed",
|
|
111
|
+
"url": "Address",
|
|
112
|
+
"dir": "Folder",
|
|
113
|
+
# Question and sources
|
|
114
|
+
"question": "Question",
|
|
115
|
+
"question_id": "Question ID",
|
|
116
|
+
"requirements": "Requirements",
|
|
117
|
+
"requirements_id": "Requirements ID",
|
|
118
|
+
"feasibility": "Feasibility",
|
|
119
|
+
"sources": "Sources",
|
|
120
|
+
"source_ids": "Source IDs",
|
|
121
|
+
"source_proposals": "Source options",
|
|
122
|
+
"required_check_ids": "Required checks",
|
|
123
|
+
"quality": "Quality checks",
|
|
124
|
+
"join": "Join",
|
|
125
|
+
"lineage": "Where it came from",
|
|
126
|
+
"counts": "Counts",
|
|
127
|
+
"manifest_sha256": "Manifest fingerprint",
|
|
128
|
+
"aggregate_sha256": "Aggregate fingerprint",
|
|
129
|
+
"entry_count": "Indexed entries",
|
|
130
|
+
"locator_count": "Private locations",
|
|
131
|
+
"diagnostic_count": "Diagnostics",
|
|
132
|
+
"total_bytes": "Indexed bytes",
|
|
133
|
+
"checkpoint_sha256": "Checkpoint fingerprint",
|
|
134
|
+
"staging_sha256": "Complete staging fingerprint",
|
|
135
|
+
"fill_receipt_sha256": "Fill receipt fingerprint",
|
|
136
|
+
"fill_receipt": "Fill receipt",
|
|
137
|
+
"flagged_queue_sha256": "Flagged-rights queue fingerprint",
|
|
138
|
+
"classification_sha256": "Delta classification fingerprint",
|
|
139
|
+
"classification_checkpoint_sha256": "Classification checkpoint fingerprint",
|
|
140
|
+
"publication_sha256": "Publication receipt fingerprint",
|
|
141
|
+
"provider_count_reconciliation": "Provider count rule",
|
|
142
|
+
"convergence_passes": "Convergence passes",
|
|
143
|
+
"reason_code": "Reason code",
|
|
144
|
+
"recommendation": "Recommendation",
|
|
145
|
+
"representations": "Representations",
|
|
146
|
+
"fallback_reason": "Fallback reason",
|
|
147
|
+
"role": "Role",
|
|
148
|
+
"tasks": "Steps",
|
|
149
|
+
"events": "History",
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
# One plain headline sentence per status the harness puts on stdout. Statuses remain machine
|
|
153
|
+
# contract values; only the sentence shown to a human is translated into plain language.
|
|
154
|
+
STATUS_HEADLINES: dict[str, str] = {
|
|
155
|
+
"ready": "Notebook ready.",
|
|
156
|
+
# Workbench folder states (offline._PHASES)
|
|
157
|
+
"initialized": "Workbench folder created.",
|
|
158
|
+
"planned": "Plan checked and recorded.",
|
|
159
|
+
"building": "A build is in progress.",
|
|
160
|
+
"idle": "No Build is running.",
|
|
161
|
+
"done": "Build finished.",
|
|
162
|
+
"candidate_built": "Build sealed.",
|
|
163
|
+
"review_recorded": "Review decision sealed.",
|
|
164
|
+
"failed": "The last build failed.",
|
|
165
|
+
# Workbench folder commands
|
|
166
|
+
"plan_validated": "Plan checked and recorded.",
|
|
167
|
+
"candidate_inspected": "Build inspected and replayed exactly.",
|
|
168
|
+
"candidate_verified": "Build re-checked and intact.",
|
|
169
|
+
"deployment_approval_required": "Deployment is waiting for human approval.",
|
|
170
|
+
"dataset_activation_queued": "Dataset activation queued.",
|
|
171
|
+
# Both answers about a queued run are answers whatever they say. The headline never claims the
|
|
172
|
+
# run finished: which of the thirteen states it is in is the line below it, every time.
|
|
173
|
+
"run_status_reported": "Here is what Studio says about that run.",
|
|
174
|
+
"run_watch_timed_out": (
|
|
175
|
+
"The wait ran out and the run had not settled. Below is the state it was really in."
|
|
176
|
+
),
|
|
177
|
+
"hosted_dataset_ready": "The released Build is here and its dataset notebook is ready.",
|
|
178
|
+
"reconciled": "The prior deployment result was recovered.",
|
|
179
|
+
# Cloud device-key lifecycle. Each status says what durable local state or Cloud's exact
|
|
180
|
+
# answer established; none implies that a parent-process environment override changed.
|
|
181
|
+
"logged_out": "The stored device credential was removed.",
|
|
182
|
+
"local_recovery_completed": "The local credential recovery is complete.",
|
|
183
|
+
"recovered": "The credential state was recovered.",
|
|
184
|
+
"recovery_required": "Credential recovery is required before this can continue.",
|
|
185
|
+
"revoked": "The device credential was revoked.",
|
|
186
|
+
"rotated": "A new device credential was stored and the old one was revoked.",
|
|
187
|
+
# Recipes
|
|
188
|
+
"frozen_recipe_validated": "Recipe checked. Nothing was approved or run.",
|
|
189
|
+
"recipe_authored": "Recipe written from your YAML.",
|
|
190
|
+
"recipe_exported": "Recipe written.",
|
|
191
|
+
"recipe_approved": "Recipe approved.",
|
|
192
|
+
# The hosted half of an approval. Two words rather than one, because "the ask was recorded"
|
|
193
|
+
# and "a person settled it" are the two different things somebody needs to be able to tell
|
|
194
|
+
# apart -- and a single word covering both is how a pending approval gets read as a yes.
|
|
195
|
+
"approval_requested": "The approval was asked for. A person still has to grant it.",
|
|
196
|
+
"approval_settled": "A person settled that approval.",
|
|
197
|
+
# The decision record, written into a hosted run's own log. Two words for the same reason the
|
|
198
|
+
# two above are two: writing a cell and reading what is written are different answers, and a
|
|
199
|
+
# single word covering both would let a list read as though something had just been recorded.
|
|
200
|
+
"narrative_cell_appended": "Note written into the run's record.",
|
|
201
|
+
"narrative_listed": "The notes written about this run.",
|
|
202
|
+
"version_built": "Recipe version built.",
|
|
203
|
+
"recipe_version_verified": "Recipe version verified.",
|
|
204
|
+
# Review
|
|
205
|
+
"report_signed": "Report signed.",
|
|
206
|
+
"reported": "Report prepared.",
|
|
207
|
+
"reviewed_candidate": "Review passed. No blocking findings.",
|
|
208
|
+
"fixes_required": "Review found blocking findings. Fixes are required.",
|
|
209
|
+
# Local deterministic checks do not create a review decision.
|
|
210
|
+
"local_checks_completed": "Checks run here. Nothing has been decided.",
|
|
211
|
+
"review_setup_created": "Protected review setup created. This does not approve a Build.",
|
|
212
|
+
# Capturing a live source: what was recorded is now sealed and can be built from.
|
|
213
|
+
"stream_recorded": "Recorded messages sealed.",
|
|
214
|
+
# Looking before authoring
|
|
215
|
+
"peeked": "Here is what is in there.",
|
|
216
|
+
# Asking what would stop a build, and what this build can do at all. Both are answers whatever
|
|
217
|
+
# they contain: "this machine cannot write a file safely" is the thing the command was run to
|
|
218
|
+
# find out, so the headline does not change into an apology when it says so.
|
|
219
|
+
"preflight_completed": "Here is what would stop a build on this machine.",
|
|
220
|
+
"inventory_listed": "Here is what this build can do.",
|
|
221
|
+
"catalog_searched": "Here is the best admitted source in that verified catalog.",
|
|
222
|
+
"catalog_fill_incomplete": (
|
|
223
|
+
"Catalog fill stopped incomplete. Resume from its exact checkpoint."
|
|
224
|
+
),
|
|
225
|
+
"catalog_published": "Public catalog successor published.",
|
|
226
|
+
# The three explicit provider-scale mutations. Each one is a separate answer with its own
|
|
227
|
+
# receipt, so none of them may read as another: a sweep that stopped is not a generation, and
|
|
228
|
+
# a key file that was accepted is not a sweep.
|
|
229
|
+
"harvest_preflight_accepted": (
|
|
230
|
+
"That key file was accepted. Nothing was fetched and nothing was written."
|
|
231
|
+
),
|
|
232
|
+
"harvest_complete": "The provider sweep finished. Nothing has been published yet.",
|
|
233
|
+
"harvest_incomplete": (
|
|
234
|
+
"The provider sweep stopped before it finished. The reason below says what stopped it; "
|
|
235
|
+
"run the same command again with --resume to carry on from exactly there."
|
|
236
|
+
),
|
|
237
|
+
"generation_published": "Public catalog generation published, and read back from disk.",
|
|
238
|
+
"generation_incomplete": (
|
|
239
|
+
"The generation stopped before it was published. What is already written is verified and "
|
|
240
|
+
"kept; run the same command again with --resume to carry on from exactly there."
|
|
241
|
+
),
|
|
242
|
+
"build_index_published": "Private Build index published.",
|
|
243
|
+
"local_search_complete": "Local search complete.",
|
|
244
|
+
# A public store can be searched under a stated work budget, and a budget that closes before
|
|
245
|
+
# every relevant part of it has been read is not an answer. The headline says so out loud
|
|
246
|
+
# rather than letting "no match" stand in for "we stopped looking".
|
|
247
|
+
"local_search_incomplete": (
|
|
248
|
+
"Local search stopped before it finished. Nothing was ruled out; the reason below says "
|
|
249
|
+
"which budget closed."
|
|
250
|
+
),
|
|
251
|
+
# Writing one generation of catalog entries out into bounded parts. These two words are the
|
|
252
|
+
# whole answer of that command -- it puts its own receipt's `status` at the top of what it
|
|
253
|
+
# prints -- so without a sentence here a reader was shown the bare word `complete`.
|
|
254
|
+
"complete": "Authoring finished. Every record in that generation was written.",
|
|
255
|
+
"incomplete": (
|
|
256
|
+
"Authoring stopped before it finished. The reason below says what stopped it, and what "
|
|
257
|
+
"was written is listed under it."
|
|
258
|
+
),
|
|
259
|
+
# The catalogue pipeline job, asked to resolve its deployment's configuration and stop. The
|
|
260
|
+
# word is the whole answer: nothing ran, so the headline has to say so rather than let a
|
|
261
|
+
# reader take a printed receipt for a completed stage.
|
|
262
|
+
"dry-run": "Nothing ran. This is the stage that would have run, and what it would have run as.",
|
|
263
|
+
# Trying a plan before committing to it. The build was real; the folder it went into was not
|
|
264
|
+
# kept, so the headline says what was learned rather than what was made.
|
|
265
|
+
"plan_checked": "That plan builds.",
|
|
266
|
+
# Reading back what you already have
|
|
267
|
+
"build_shown": "Here is what this build holds.",
|
|
268
|
+
"builds_listed": "Here are the builds under that folder.",
|
|
269
|
+
# Comparing two of them. Both outcomes are ordinary answers, so both read as answers: a
|
|
270
|
+
# difference is something to look at, not something that went wrong.
|
|
271
|
+
"builds_identical": "Those two builds hold the same data, in the same shape.",
|
|
272
|
+
"builds_differ": "Those two builds are not the same.",
|
|
273
|
+
# Agent-facing surfaces
|
|
274
|
+
"agent_request_validated": "Agent request checked. No model was called.",
|
|
275
|
+
"source_proposals_validated": "Source options checked. Nothing was fetched.",
|
|
276
|
+
"workflow_described": "Here is the workflow and who decides at each step.",
|
|
277
|
+
"adapters_listed": "Here are the available source adapters.",
|
|
278
|
+
"events_read": "Here is the build history.",
|
|
279
|
+
"fleet_scanned": "Here is the worker fleet.",
|
|
280
|
+
"no_new_run": "No new Recipe run was needed.",
|
|
281
|
+
"refused": "That request was refused.",
|
|
282
|
+
"slices_acquired": "The requested source slices were acquired.",
|
|
283
|
+
"source_acquired": "The source was acquired.",
|
|
284
|
+
# Handoff
|
|
285
|
+
"hosted_candidate_exported": "Build packaged for Studio.",
|
|
286
|
+
"viewer_started": "Viewer running.",
|
|
287
|
+
"notebook_ready": "Table notebook ready.",
|
|
288
|
+
# Signing in to the Mostly Right cloud, and reading back what is stored locally
|
|
289
|
+
"device_authenticated": "Signed in. A device credential is stored on this machine.",
|
|
290
|
+
"authenticated": "This machine is signed in.",
|
|
291
|
+
"not_authenticated": "This machine is not signed in.",
|
|
292
|
+
"listed": "Here are the device credentials Cloud knows about.",
|
|
293
|
+
"not_implemented": "That credential operation is not available in this release.",
|
|
294
|
+
"unsupported": "That transport-token operation is not supported.",
|
|
295
|
+
# A deployment plan is only a request document. These statuses deliberately name the plan,
|
|
296
|
+
# never external state: the command contacts nothing, and Studio remains the authority that
|
|
297
|
+
# decides whether anything runs live.
|
|
298
|
+
"deployment_plan_ready": (
|
|
299
|
+
"Here is the request for running this dataset live. Nothing has been sent."
|
|
300
|
+
),
|
|
301
|
+
"deployment_plan_refused": (
|
|
302
|
+
"A deployment request could not be prepared. The reasons are below."
|
|
303
|
+
),
|
|
304
|
+
# The hosted lane. Every one of these headlines is about a run on the backend, and none of
|
|
305
|
+
# them claims anything about this machine: "queued" is what Studio accepted, "terminal" is
|
|
306
|
+
# what Studio's own state machine reached, and "the watch ended" is honest about the case
|
|
307
|
+
# where the connection stopped before the run did.
|
|
308
|
+
"run_queued": "The run is queued. Watch it at the address below.",
|
|
309
|
+
"run_reported": "Here is what Studio says about that run.",
|
|
310
|
+
"run_terminal": "The run has finished. Its final state is below.",
|
|
311
|
+
"watch_ended": "The watch ended before the run did. The run is unaffected.",
|
|
312
|
+
"artifacts_downloaded": "The dataset is here, and its digest matched.",
|
|
313
|
+
# The research session. Three words for opening one, because "a worker holds it", "Studio
|
|
314
|
+
# recorded it and nobody holds it yet" and "it ended" are three different answers to the same
|
|
315
|
+
# command; and three for a probe, because a probe that settled without an answer is neither
|
|
316
|
+
# an answer nor still running, and a single word covering all three is how a failed probe gets
|
|
317
|
+
# read as a result.
|
|
318
|
+
"research_session_ready": "The research session is ready. Its worker is warm.",
|
|
319
|
+
"research_session_opened": (
|
|
320
|
+
"The research session is recorded. Its worker has not taken it yet; the state is below."
|
|
321
|
+
),
|
|
322
|
+
"research_session_ended": "The research session ended before a worker answered.",
|
|
323
|
+
"research_session_reported": "Here is what Studio says about that research session.",
|
|
324
|
+
"research_session_closed": "The research session is closed. Its worker exits.",
|
|
325
|
+
"research_probe_submitted": "The probe is queued. Its answer is read back separately.",
|
|
326
|
+
"research_probe_answered": "The worker answered the probe. The answer is below.",
|
|
327
|
+
"research_probe_settled": "The probe settled without an answer. The state is below.",
|
|
328
|
+
# The authoring front door. Three words because "a stage stopped where you asked", "the
|
|
329
|
+
# proposal exists and nothing has approved it", and "the approval is open and waiting on a
|
|
330
|
+
# person" are three different answers to the one command, and a single word covering all three
|
|
331
|
+
# is how a proposal nobody has approved gets read as a finished one.
|
|
332
|
+
"authoring_stage_complete": "The authoring stage you asked for is done. What is next is below.",
|
|
333
|
+
"recipe_proposed": "The recipe proposal exists. Nothing has approved it yet.",
|
|
334
|
+
"recipe_proposal_approval_requested": (
|
|
335
|
+
"The recipe proposal is open and waiting for a person to approve it."
|
|
336
|
+
),
|
|
337
|
+
"recipe_proposal_approved": "A person approved the recipe. Queue its first build below.",
|
|
338
|
+
"recipe_proposal_not_approved": "The approval settled without approving the recipe.",
|
|
339
|
+
"recipe_build_queued": "The approval already started the first build. Follow the run below.",
|
|
340
|
+
# `build` against a proposal whose confirmation already started the run: that run is reported
|
|
341
|
+
# rather than a second one queued, and the word says so.
|
|
342
|
+
"run_already_queued": "This build was already queued by the approval. Its run is below.",
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
RECOMMENDATION_HEADLINES: dict[str, str] = {
|
|
346
|
+
"reuse_build": "A verified local Build can be reused.",
|
|
347
|
+
"use_source": "An admitted public source can be used.",
|
|
348
|
+
"no_match": "No fitting local Build or admitted public source was found.",
|
|
349
|
+
"public_incomplete": (
|
|
350
|
+
"The public source search stopped before it finished, so nothing was ruled out."
|
|
351
|
+
),
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
# Facts a reader looks for first. Everything not named here follows, sorted, so the rendering is
|
|
355
|
+
# deterministic whatever order the payload dict happens to carry.
|
|
356
|
+
_HEADLINE_KEYS: tuple[str, ...] = (
|
|
357
|
+
# Whether anything is stopping you, and then what to do about it. `mr-data preflight` exists to
|
|
358
|
+
# be read by somebody who is stuck, and the list of everything that was fine is not the answer
|
|
359
|
+
# they came for. These two keys appear in no other payload.
|
|
360
|
+
"blocked",
|
|
361
|
+
"what to do",
|
|
362
|
+
# What is about to be frozen comes before the receipt for freezing it: the point of
|
|
363
|
+
# `mr-data approve` is that the block is read before the outcome lines (29-07). The section
|
|
364
|
+
# names below belong to that block alone and appear in no other payload, so naming them here
|
|
365
|
+
# orders the summary without touching how any other command reads.
|
|
366
|
+
"summary",
|
|
367
|
+
"what this answers",
|
|
368
|
+
"one row is",
|
|
369
|
+
"it covers",
|
|
370
|
+
"the columns",
|
|
371
|
+
"the sources",
|
|
372
|
+
# Directly under the source list, because that is what the sentence is about: what the Recipe
|
|
373
|
+
# declares the result is for, and the permission every source above has to carry for it.
|
|
374
|
+
"what the result may be used for",
|
|
375
|
+
"the cleaning steps",
|
|
376
|
+
"the join",
|
|
377
|
+
"the ordered graph steps",
|
|
378
|
+
"the graph output",
|
|
379
|
+
"the checks it must pass",
|
|
380
|
+
"the refresh bounds",
|
|
381
|
+
"the backfill window",
|
|
382
|
+
"the pinned versions",
|
|
383
|
+
"the recipe",
|
|
384
|
+
"the fingerprint being frozen",
|
|
385
|
+
"what freezing means",
|
|
386
|
+
# What a thing is comes before the detail of it, so one listed change reads in the order a
|
|
387
|
+
# person says it: what changed, which column, from what, to what, by how much. Sorted
|
|
388
|
+
# alphabetically these would arrive as "difference, from, related drift alert, to", which is
|
|
389
|
+
# nobody's sentence.
|
|
390
|
+
"what",
|
|
391
|
+
"column",
|
|
392
|
+
"from",
|
|
393
|
+
"to",
|
|
394
|
+
"difference",
|
|
395
|
+
# What a thing is called comes before anything said about it.
|
|
396
|
+
"name",
|
|
397
|
+
"run_id",
|
|
398
|
+
"workspace",
|
|
399
|
+
"run_dir",
|
|
400
|
+
"review_dir",
|
|
401
|
+
"output",
|
|
402
|
+
"url",
|
|
403
|
+
"dir",
|
|
404
|
+
"root",
|
|
405
|
+
"recipe_id",
|
|
406
|
+
"recipe_version",
|
|
407
|
+
"approval_id",
|
|
408
|
+
"candidate_digest",
|
|
409
|
+
"table_sha256",
|
|
410
|
+
"recipe_digest",
|
|
411
|
+
"approval_digest",
|
|
412
|
+
"decision_digest",
|
|
413
|
+
"review_decision_digest",
|
|
414
|
+
"acquisition_bundle_digest",
|
|
415
|
+
"execution_digest",
|
|
416
|
+
"row_count",
|
|
417
|
+
"columns",
|
|
418
|
+
"grain",
|
|
419
|
+
"manifest_version",
|
|
420
|
+
"engine",
|
|
421
|
+
"release_eligible",
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
# Facts that are the last thing a reader should read, whatever else the payload carries. A key
|
|
425
|
+
# named here renders after every other key, with a blank line before it, so a closing sentence
|
|
426
|
+
# stays closing even when the block above it is a list of checks. Only the top level is affected;
|
|
427
|
+
# nested blocks keep their ordinary order.
|
|
428
|
+
_TAIL_KEYS: tuple[str, ...] = (
|
|
429
|
+
# `review --local` must end by saying that human review is still pending.
|
|
430
|
+
"what happens next",
|
|
431
|
+
# `plan-check` must end by saying which fingerprint it did not report, and why. It reads as a
|
|
432
|
+
# closing line only after the fingerprint it does report.
|
|
433
|
+
"what this does not tell you",
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
# Two levels of indentation, then a count. Deeper structure is a machine record, not a human line.
|
|
437
|
+
_MAX_DEPTH = 2
|
|
438
|
+
_INDENT = " "
|
|
439
|
+
_EMPTY = "(none)"
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
def render_human(payload: Mapping[str, Any]) -> str:
|
|
443
|
+
"""Render one payload mapping as plain labelled lines.
|
|
444
|
+
|
|
445
|
+
The ``status`` key becomes the headline sentence and is not repeated as a line. Every other
|
|
446
|
+
key becomes ``label: value``. Nested mappings become indented blocks up to
|
|
447
|
+
:data:`_MAX_DEPTH`; anything deeper renders as a count that points at ``--json``.
|
|
448
|
+
|
|
449
|
+
⚠ A PAYLOAD THAT STATES ITS OWN ``headline`` STATES IT, and it is not then repeated as a
|
|
450
|
+
labelled field. The status map is the sentence for a status word; a ``headline`` is a sentence
|
|
451
|
+
about this particular answer, which the acquisition receipt carries in both profiles -- how
|
|
452
|
+
many members were fetched, and from where -- and which the status word cannot know. Printing
|
|
453
|
+
both would open every one of those answers with two headlines, the general one and the true
|
|
454
|
+
one, in that order.
|
|
455
|
+
"""
|
|
456
|
+
|
|
457
|
+
status = payload.get("status")
|
|
458
|
+
stated = payload.get("headline")
|
|
459
|
+
if isinstance(stated, str) and stated:
|
|
460
|
+
headline = stated
|
|
461
|
+
elif status is None:
|
|
462
|
+
headline = "Done."
|
|
463
|
+
elif status == "local_search_complete" and isinstance(payload.get("recommendation"), Mapping):
|
|
464
|
+
kind = payload["recommendation"].get("kind")
|
|
465
|
+
headline = RECOMMENDATION_HEADLINES.get(str(kind), STATUS_HEADLINES[str(status)])
|
|
466
|
+
else:
|
|
467
|
+
headline = STATUS_HEADLINES.get(str(status), str(status))
|
|
468
|
+
lines = [_printable(headline)]
|
|
469
|
+
lines.extend(_render_mapping(payload, depth=0, skip=("status", "headline")))
|
|
470
|
+
return "\n".join(lines)
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
def render_error(
|
|
474
|
+
headline: str,
|
|
475
|
+
*,
|
|
476
|
+
code: str | None = None,
|
|
477
|
+
severity: str | None = None,
|
|
478
|
+
remediation: Sequence[str] = (),
|
|
479
|
+
note: str | None = None,
|
|
480
|
+
) -> str:
|
|
481
|
+
"""Render one failure as a plain block: what happened, what to do, what to quote.
|
|
482
|
+
|
|
483
|
+
``code`` is what a person quotes in a bug report, so it survives into plain mode verbatim.
|
|
484
|
+
Remediation lines are supplied by the error-remediation map; the default is empty. ``note``
|
|
485
|
+
sits with the code rather than with the advice, because it is about this rendering of the
|
|
486
|
+
failure rather than about the failure.
|
|
487
|
+
"""
|
|
488
|
+
|
|
489
|
+
# The headline carries a raise-site message, and a raise-site message regularly carries a name
|
|
490
|
+
# somebody else chose -- a path, a column, a member. One refusal is one line, so a name with a
|
|
491
|
+
# line break or an escape sequence in it is written out rather than acted on, by the same rule
|
|
492
|
+
# every other rendered value goes through.
|
|
493
|
+
lines = [_printable(headline)]
|
|
494
|
+
if remediation:
|
|
495
|
+
lines.append("")
|
|
496
|
+
lines.extend(f"{_INDENT}{_printable(str(item))}" for item in remediation)
|
|
497
|
+
tail = []
|
|
498
|
+
if severity is not None:
|
|
499
|
+
tail.append(f"Severity: {severity}")
|
|
500
|
+
if code is not None:
|
|
501
|
+
tail.append(f"Code: {code}")
|
|
502
|
+
if note is not None:
|
|
503
|
+
tail.append(note)
|
|
504
|
+
if tail:
|
|
505
|
+
lines.append("")
|
|
506
|
+
lines.extend(tail)
|
|
507
|
+
return "\n".join(lines)
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
def render_lines(mapping: Mapping[str, Any], *, skip: Sequence[str] = ()) -> list[str]:
|
|
511
|
+
"""Render one mapping as plain labelled lines, with no headline sentence.
|
|
512
|
+
|
|
513
|
+
This is :func:`render_human` without the status line, for a block of facts that is part of a
|
|
514
|
+
larger payload rather than the whole of one. A caller that has its own structured record and
|
|
515
|
+
wants the terminal rendering of it uses this, so the block a person reads and the record a
|
|
516
|
+
machine reads never become two truths.
|
|
517
|
+
"""
|
|
518
|
+
|
|
519
|
+
return _render_mapping(mapping, depth=0, skip=skip)
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
def plain_label(key: str) -> str:
|
|
523
|
+
"""Plain label for one payload key; an unmapped key still renders, never crashes."""
|
|
524
|
+
|
|
525
|
+
mapped = PLAIN_LABELS.get(key)
|
|
526
|
+
if mapped is not None:
|
|
527
|
+
return mapped
|
|
528
|
+
return key.replace("_", " ").capitalize()
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
def _render_mapping(
|
|
532
|
+
mapping: Mapping[str, Any],
|
|
533
|
+
*,
|
|
534
|
+
depth: int,
|
|
535
|
+
skip: Sequence[str] = (),
|
|
536
|
+
) -> list[str]:
|
|
537
|
+
indent = _INDENT * depth
|
|
538
|
+
lines: list[str] = []
|
|
539
|
+
for key in _ordered_keys(mapping, skip=skip):
|
|
540
|
+
value = mapping[key]
|
|
541
|
+
# Lexical mode was explicitly selected, so no fallback happened. The token remains in the
|
|
542
|
+
# JSON receipt for compatibility but is not a human-facing reason to explain.
|
|
543
|
+
if key == "fallback_reason" and value == "NEURAL_NOT_REQUESTED":
|
|
544
|
+
continue
|
|
545
|
+
label = plain_label(str(key))
|
|
546
|
+
if depth == 0 and key in _TAIL_KEYS and lines:
|
|
547
|
+
lines.append("")
|
|
548
|
+
if isinstance(value, Mapping):
|
|
549
|
+
if depth >= _MAX_DEPTH:
|
|
550
|
+
lines.append(f"{indent}{label}: {_summary(len(value))}")
|
|
551
|
+
continue
|
|
552
|
+
lines.append(f"{indent}{label}:")
|
|
553
|
+
if not value:
|
|
554
|
+
lines.append(f"{indent}{_INDENT}{_EMPTY}")
|
|
555
|
+
continue
|
|
556
|
+
lines.extend(_render_mapping(value, depth=depth + 1))
|
|
557
|
+
continue
|
|
558
|
+
if _is_block(value):
|
|
559
|
+
# A value written over several lines is a block a person reads, not a field. Putting
|
|
560
|
+
# it after its own label keeps every line of it flush with the others -- and every
|
|
561
|
+
# line of it goes through `_printable`, so the newlines this branch honours are the
|
|
562
|
+
# only control characters that survive into the rendering.
|
|
563
|
+
lines.append(f"{indent}{label}:")
|
|
564
|
+
lines.extend(f"{indent}{_INDENT}{_printable(part)}" for part in str(value).split("\n"))
|
|
565
|
+
continue
|
|
566
|
+
if _is_sequence(value):
|
|
567
|
+
items = list(value)
|
|
568
|
+
if not items:
|
|
569
|
+
lines.append(f"{indent}{label}: {_EMPTY}")
|
|
570
|
+
continue
|
|
571
|
+
if all(_is_scalar(item) for item in items):
|
|
572
|
+
joined = ", ".join(_scalar(item) for item in items)
|
|
573
|
+
lines.append(f"{indent}{label}: {joined}")
|
|
574
|
+
continue
|
|
575
|
+
lines.append(f"{indent}{label}: {_summary(len(items))}")
|
|
576
|
+
continue
|
|
577
|
+
lines.append(f"{indent}{label}: {_scalar(value)}")
|
|
578
|
+
return lines
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
def _ordered_keys(mapping: Mapping[str, Any], *, skip: Sequence[str] = ()) -> list[Any]:
|
|
582
|
+
present = [key for key in mapping if key not in skip]
|
|
583
|
+
tail = [key for key in _TAIL_KEYS if key in present]
|
|
584
|
+
headline = [key for key in _HEADLINE_KEYS if key in present and key not in tail]
|
|
585
|
+
remainder = sorted(
|
|
586
|
+
(key for key in present if key not in headline and key not in tail),
|
|
587
|
+
key=lambda key: (_is_container(mapping[key]), str(key)),
|
|
588
|
+
)
|
|
589
|
+
return [*headline, *remainder, *tail]
|
|
590
|
+
|
|
591
|
+
|
|
592
|
+
def _summary(count: int) -> str:
|
|
593
|
+
noun = "item" if count == 1 else "items"
|
|
594
|
+
return f"<{count} {noun} - use --json for the full record>"
|
|
595
|
+
|
|
596
|
+
|
|
597
|
+
def _is_scalar(value: Any) -> bool:
|
|
598
|
+
return value is None or isinstance(value, str | int | float | bool)
|
|
599
|
+
|
|
600
|
+
|
|
601
|
+
def _is_sequence(value: Any) -> bool:
|
|
602
|
+
return isinstance(value, list | tuple)
|
|
603
|
+
|
|
604
|
+
|
|
605
|
+
def _is_block(value: Any) -> bool:
|
|
606
|
+
"""Whether this value is text written over more than one line."""
|
|
607
|
+
|
|
608
|
+
return isinstance(value, str) and "\n" in value
|
|
609
|
+
|
|
610
|
+
|
|
611
|
+
def _is_container(value: Any) -> bool:
|
|
612
|
+
return isinstance(value, Mapping) or _is_sequence(value) or _is_block(value)
|
|
613
|
+
|
|
614
|
+
|
|
615
|
+
def _scalar(value: Any) -> str:
|
|
616
|
+
if value is None:
|
|
617
|
+
return _EMPTY
|
|
618
|
+
if isinstance(value, bool):
|
|
619
|
+
return "yes" if value else "no"
|
|
620
|
+
return _printable(str(value))
|
|
621
|
+
|
|
622
|
+
|
|
623
|
+
def _printable(text: str) -> str:
|
|
624
|
+
"""One line of text with every character that is not one written as an escape.
|
|
625
|
+
|
|
626
|
+
A payload value is regularly a cell out of a file nobody has cleaned -- that is what `mr-data
|
|
627
|
+
peek` is for -- and the plain rendering is what a person, and per SKILL.md a driving agent,
|
|
628
|
+
reads and branches on. Text goes to a terminal, and a terminal acts on some of what it is
|
|
629
|
+
given: a newline in a cell puts attacker-chosen text at column 0, where `[ok] ...` and
|
|
630
|
+
`All checks passed: yes` live, and an escape sequence in a cell reaches the terminal itself.
|
|
631
|
+
Neither is a thing this renderer may pass on.
|
|
632
|
+
|
|
633
|
+
The rule is the Reader's own, one level down. A column *name* carrying a control character is
|
|
634
|
+
refused outright (`PARSE_COLUMN_NAME`); a value may not be refused, because refusing messy
|
|
635
|
+
values would leave peek unable to do the only thing it exists for -- so it is shown instead,
|
|
636
|
+
exactly, as the escape that spells it. ``str.isprintable`` is the test, so the C0 and C1
|
|
637
|
+
control characters, the delete character, and the line and paragraph separators are all
|
|
638
|
+
covered by one rule rather than by a list that has to be kept up to date.
|
|
639
|
+
|
|
640
|
+
A multi-line string that is a block of the product's own prose never reaches here: it is
|
|
641
|
+
rendered as an indented block, where every line is already flush with the others and none of
|
|
642
|
+
them can start at column 0. Each line of that block is still put through this function.
|
|
643
|
+
"""
|
|
644
|
+
|
|
645
|
+
if text.isprintable():
|
|
646
|
+
return text
|
|
647
|
+
return "".join(part if part.isprintable() else _escaped(part) for part in text)
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
def _escaped(character: str) -> str:
|
|
651
|
+
"""One character that cannot be printed, written the way Python writes it in a string.
|
|
652
|
+
|
|
653
|
+
``repr`` is the spelling, so a newline reads as ``\\n`` and an escape as ``\\x1b`` -- the form
|
|
654
|
+
a person recognises and can paste back into a search.
|
|
655
|
+
"""
|
|
656
|
+
|
|
657
|
+
return repr(character)[1:-1]
|