mostlyright-data 0.9.5__tar.gz → 0.9.7__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.
Files changed (326) hide show
  1. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/PKG-INFO +12 -13
  2. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/README.md +11 -12
  3. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/pyproject.toml +1 -1
  4. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/acquisition/sandbox.py +5 -1
  5. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/acquisition/url_policy.py +27 -1
  6. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/cli.py +46 -10
  7. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/hosted_bootstrap.py +166 -25
  8. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/hosted_crawler_fetch.py +9 -1
  9. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/hosted_session_worker.py +163 -18
  10. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/hosted_worker.py +655 -31
  11. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/pipeline.py +9 -0
  12. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/progress_events.py +75 -2
  13. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/serving.py +17 -4
  14. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/session_probes.py +26 -3
  15. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/studio_boundary.py +1 -1
  16. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/thin/acquire.py +16 -6
  17. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/thin/download.py +80 -11
  18. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/thin/router.py +41 -1
  19. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/thin/stream.py +6 -1
  20. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/hosted_acquisition.py +29 -4
  21. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/remediation.py +1 -1
  22. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/render.py +1 -0
  23. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/.gitignore +0 -0
  24. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/scripts/hatch_build.py +0 -0
  25. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/__init__.py +0 -0
  26. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/acquisition/__init__.py +0 -0
  27. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/acquisition/http.py +0 -0
  28. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/acquisition/parsing.py +0 -0
  29. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/acquisition/ranges.py +0 -0
  30. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/acquisition/result_download.py +0 -0
  31. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/acquisition/retention_admission.py +0 -0
  32. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/agent_runtime.py +0 -0
  33. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/assets/logo-ink.svg +0 -0
  34. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/backends/__init__.py +0 -0
  35. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/backends/pandas_backend.py +0 -0
  36. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/backends/polars_backend.py +0 -0
  37. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/backends/protocol.py +0 -0
  38. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/backends/reference.py +0 -0
  39. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/backends/registry.py +0 -0
  40. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/backends/restrictions.py +0 -0
  41. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/canonical.py +0 -0
  42. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/catalog_job.py +0 -0
  43. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/contracts.py +0 -0
  44. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/coordinator.py +0 -0
  45. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/deploy.py +0 -0
  46. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/deploy_target.py +0 -0
  47. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/deployment_evidence.py +0 -0
  48. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/event_presentation.py +0 -0
  49. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/events.py +0 -0
  50. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/fast_delimited.py +0 -0
  51. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/fleet.py +0 -0
  52. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/formats.py +0 -0
  53. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/governors.py +0 -0
  54. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/hosted_crawler.py +0 -0
  55. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/hosted_crawler_container_smoke.py +0 -0
  56. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/hosted_crawler_job.py +0 -0
  57. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/hosted_crawler_protocol.py +0 -0
  58. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/hosted_dataset.py +0 -0
  59. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/hosted_deploy.py +0 -0
  60. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/hosted_handoff.py +0 -0
  61. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/hosted_ingestion_contract.py +0 -0
  62. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/hosted_ingestion_job.py +0 -0
  63. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/hosted_ingestion_job_smoke.py +0 -0
  64. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/hosted_session_container_smoke.py +0 -0
  65. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/hosted_session_worker_job_smoke.py +0 -0
  66. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ingestion/__init__.py +0 -0
  67. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ingestion/contracts.py +0 -0
  68. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ingestion/faults.py +0 -0
  69. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ingestion/gcs_store.py +0 -0
  70. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ingestion/spool.py +0 -0
  71. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ingestion/store.py +0 -0
  72. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/key_seam.py +0 -0
  73. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/linux_process_boundary.py +0 -0
  74. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/local_contracts.py +0 -0
  75. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/local_search/__init__.py +0 -0
  76. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/local_search/build_index.py +0 -0
  77. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/local_search/contracts.py +0 -0
  78. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/local_search/query_trace.py +0 -0
  79. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/local_search/retrieval.py +0 -0
  80. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/local_search/sealed.py +0 -0
  81. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/local_search/service.py +0 -0
  82. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/nbrender/CONTRACT.md +0 -0
  83. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/nbrender/__init__.py +0 -0
  84. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/nbrender/chrome.py +0 -0
  85. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/nbrender/code_body.py +0 -0
  86. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/nbrender/document.py +0 -0
  87. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/nbrender/frame.py +0 -0
  88. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/nbrender/interactive.py +0 -0
  89. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/nbrender/markdown_body.py +0 -0
  90. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/nbrender/mr_components.py +0 -0
  91. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/nbrender/outputs_data.py +0 -0
  92. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/nbrender/outputs_rich.py +0 -0
  93. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/nbrender/outputs_source.py +0 -0
  94. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/nbrender/outputs_stage.py +0 -0
  95. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/nbrender/outputs_text.py +0 -0
  96. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/nbrender/parse.py +0 -0
  97. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/nbrender/status.py +0 -0
  98. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/nbrender/tokens.py +0 -0
  99. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/notebook.py +0 -0
  100. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/offline.py +0 -0
  101. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/operation_registry.py +0 -0
  102. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/operator_setup.py +0 -0
  103. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/plan_graph.py +0 -0
  104. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/preparation/__init__.py +0 -0
  105. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/preparation/contracts.py +0 -0
  106. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/preparation/engine.py +0 -0
  107. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/preparation/errors.py +0 -0
  108. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/preparation/gates.py +0 -0
  109. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/preparation/joins.py +0 -0
  110. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/preparation/profile.py +0 -0
  111. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/preparation/table.py +0 -0
  112. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/preparation/transforms.py +0 -0
  113. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/__init__.py +0 -0
  114. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/containers.py +0 -0
  115. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/contracts.py +0 -0
  116. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/delimited.py +0 -0
  117. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/grib2/__init__.py +0 -0
  118. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/grib2/admission.py +0 -0
  119. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/grib2/decode.py +0 -0
  120. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/grib2/geometry.py +0 -0
  121. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/grib2/portable_math.py +0 -0
  122. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/json_tabular.py +0 -0
  123. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/parquet_tabular.py +0 -0
  124. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/registry.py +0 -0
  125. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/README.md +0 -0
  126. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/archive.gzip/1.0.0/cities_one_stream/cities.csv.gz +0 -0
  127. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/archive.gzip/1.0.0/cities_one_stream/expected.json +0 -0
  128. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/archive.gzip/1.1.0/cities_one_stream/cities.csv.gz +0 -0
  129. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/archive.gzip/1.1.0/cities_one_stream/expected.json +0 -0
  130. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/archive.tar/1.0.0/cities_beside_a_directory_entry/cities.tar +0 -0
  131. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/archive.tar/1.0.0/cities_beside_a_directory_entry/expected.json +0 -0
  132. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/archive.tar/1.1.0/cities_beside_a_directory_entry/cities.tar +0 -0
  133. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/archive.tar/1.1.0/cities_beside_a_directory_entry/expected.json +0 -0
  134. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/archive.zip/1.0.0/cities_beside_a_second_member/cities.zip +0 -0
  135. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/archive.zip/1.0.0/cities_beside_a_second_member/expected.json +0 -0
  136. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/archive.zip/1.1.0/dwd_semicolon_station_member/dwd-station.zip +0 -0
  137. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/archive.zip/1.1.0/dwd_semicolon_station_member/expected.json +0 -0
  138. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/archive.zip/1.2.0/dwd_semicolon_station_member/dwd-station.zip +0 -0
  139. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/archive.zip/1.2.0/dwd_semicolon_station_member/expected.json +0 -0
  140. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/delimited_text/1.0.0/an_ordinary_comma_separated_table/cities.csv +0 -0
  141. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/delimited_text/1.0.0/an_ordinary_comma_separated_table/expected.json +0 -0
  142. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/delimited_text/1.0.0/quoted_fields_holding_the_delimiter/cities.tsv +0 -0
  143. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/delimited_text/1.0.0/quoted_fields_holding_the_delimiter/expected.json +0 -0
  144. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/delimited_text/1.1.0/an_hourly_observation_table_served_as_plain_text/expected.json +0 -0
  145. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/delimited_text/1.1.0/an_hourly_observation_table_served_as_plain_text/observations.csv +0 -0
  146. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/json.tabular/1.0.0/nested_hourly_observations/expected.json +0 -0
  147. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/json.tabular/1.0.0/nested_hourly_observations/stations.json +0 -0
  148. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/json.tabular/1.1.0/an_observation_stream_served_as_plain_text/expected.json +0 -0
  149. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/json.tabular/1.1.0/an_observation_stream_served_as_plain_text/observations.ndjson +0 -0
  150. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/parquet.tabular/1.0.0/two_columns/expected.json +0 -0
  151. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/parquet.tabular/1.0.0/two_columns/prices.parquet +0 -0
  152. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/an_ordinary_table_beside_a_second_sheet/cities.xlsx +0 -0
  153. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/an_ordinary_table_beside_a_second_sheet/expected.json +0 -0
  154. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/shares_the_workbook_had_already_computed/expected.json +0 -0
  155. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/shares_the_workbook_had_already_computed/shares.xlsx +0 -0
  156. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.1.0/shares_the_workbook_had_already_computed/expected.json +0 -0
  157. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.1.0/shares_the_workbook_had_already_computed/shares.xlsx +0 -0
  158. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/README.md +0 -0
  159. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/gfs_2m_temperature/expected.json +0 -0
  160. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/gfs_2m_temperature/gfs-2m-temperature.grib2 +0 -0
  161. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_2m_temperature/expected.json +0 -0
  162. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_2m_temperature/hrrr-2m-temperature.grib2 +0 -0
  163. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_categorical_rain/expected.json +0 -0
  164. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_categorical_rain/hrrr-categorical-rain.grib2 +0 -0
  165. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/weather.grib2/2.0.0/hrrr_2m_temperature/expected.json +0 -0
  166. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples/weather.grib2/2.0.0/hrrr_2m_temperature/hrrr-2m-temperature.grib2 +0 -0
  167. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/samples.py +0 -0
  168. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/spreadsheet.py +0 -0
  169. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/readers/tabular.py +0 -0
  170. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/recipe.py +0 -0
  171. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/repair/__init__.py +0 -0
  172. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/repair/adapters.py +0 -0
  173. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/repair/contracts.py +0 -0
  174. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/repair/coordinator.py +0 -0
  175. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/repair/errors.py +0 -0
  176. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/review.py +0 -0
  177. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/rowset.py +0 -0
  178. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/serving_edge.py +0 -0
  179. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/serving_http.py +0 -0
  180. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/signing.py +0 -0
  181. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/source_discovery.py +0 -0
  182. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/__init__.py +0 -0
  183. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/_adapter_steps.py +0 -0
  184. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/adapters.py +0 -0
  185. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/authenticated_https.py +0 -0
  186. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/authenticated_https_v2.py +0 -0
  187. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/cadence.py +0 -0
  188. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/cadence_emission.py +0 -0
  189. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/cadence_history.py +0 -0
  190. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/__init__.py +0 -0
  191. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/admission.py +0 -0
  192. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/authoring.py +0 -0
  193. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/authoring_policy.py +0 -0
  194. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/authoring_shards.py +0 -0
  195. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/bounded_io.py +0 -0
  196. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/channel.py +0 -0
  197. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/channel_client.py +0 -0
  198. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/contracts.py +0 -0
  199. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/coverage.py +0 -0
  200. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/delta.py +0 -0
  201. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/embedding.py +0 -0
  202. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/entry_v2.py +0 -0
  203. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/fill.py +0 -0
  204. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/fill_partitions.py +0 -0
  205. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/fill_staging.py +0 -0
  206. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/gating.py +0 -0
  207. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/generation_receipt.py +0 -0
  208. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/harvest/__init__.py +0 -0
  209. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/harvest/ckan.py +0 -0
  210. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/harvest/datagov_v4.py +0 -0
  211. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/harvest/protocol.py +0 -0
  212. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/harvest/sdmx.py +0 -0
  213. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/harvest/stac.py +0 -0
  214. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/health.py +0 -0
  215. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/hosted_catalog.py +0 -0
  216. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/identity_history.py +0 -0
  217. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/neural.py +0 -0
  218. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/packed_catalog.py +0 -0
  219. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/packed_retrieval.py +0 -0
  220. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/packed_writer.py +0 -0
  221. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/query_trace.py +0 -0
  222. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/recommend.py +0 -0
  223. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/retrieval.py +0 -0
  224. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/retrieval_manifest.py +0 -0
  225. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/rights_decisions.py +0 -0
  226. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/sealed.py +0 -0
  227. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/search.py +0 -0
  228. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/streaming_delta.py +0 -0
  229. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/catalog/update.py +0 -0
  230. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/collections.py +0 -0
  231. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/contracts.py +0 -0
  232. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/deletion.py +0 -0
  233. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/fitness.py +0 -0
  234. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/governance.py +0 -0
  235. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/hosted.py +0 -0
  236. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/integration.py +0 -0
  237. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/range_reader.py +0 -0
  238. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/registry.py +0 -0
  239. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/rights_rule.py +0 -0
  240. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/source_cadence_vectors.v1.json +0 -0
  241. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/sports.py +0 -0
  242. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/stream.py +0 -0
  243. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/stream_capture_session.py +0 -0
  244. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/stream_connector.py +0 -0
  245. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/stream_connectors/polymarket.clob-market.v1.json +0 -0
  246. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/stream_recorder.py +0 -0
  247. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/stream_registry.py +0 -0
  248. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/stream_rotation.py +0 -0
  249. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/stream_series.py +0 -0
  250. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/sources/stream_transport.py +0 -0
  251. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/thin/__init__.py +0 -0
  252. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/thin/acquire_cancel.py +0 -0
  253. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/thin/approvals.py +0 -0
  254. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/thin/commands.py +0 -0
  255. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/thin/narrative.py +0 -0
  256. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/thin/parity.py +0 -0
  257. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/thin/propose.py +0 -0
  258. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/thin/research.py +0 -0
  259. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/thin/runs.py +0 -0
  260. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/thin/session.py +0 -0
  261. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/thin/transport.py +0 -0
  262. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/thin/vocabulary.py +0 -0
  263. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/thin/workers.py +0 -0
  264. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ucum/TABLE-PIN.json +0 -0
  265. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ucum/ucum-subset.v1.json +0 -0
  266. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/unit_flow.py +0 -0
  267. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/units.py +0 -0
  268. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/__init__.py +0 -0
  269. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/approve.py +0 -0
  270. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/author_yaml.py +0 -0
  271. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/cloud_auth.py +0 -0
  272. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/__init__.py +0 -0
  273. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/approve.py +0 -0
  274. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/auth.py +0 -0
  275. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/author.py +0 -0
  276. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/catalog_author.py +0 -0
  277. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/catalog_fill.py +0 -0
  278. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/catalog_harvest.py +0 -0
  279. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/catalog_publish.py +0 -0
  280. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/catalog_search.py +0 -0
  281. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/catalog_update.py +0 -0
  282. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/deploy.py +0 -0
  283. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/deploy_dataset.py +0 -0
  284. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/deploy_plan.py +0 -0
  285. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/deploy_status.py +0 -0
  286. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/diff.py +0 -0
  287. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/index.py +0 -0
  288. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/inventory.py +0 -0
  289. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/list_builds.py +0 -0
  290. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/login.py +0 -0
  291. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/peek.py +0 -0
  292. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/plan_check.py +0 -0
  293. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/preflight.py +0 -0
  294. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/record.py +0 -0
  295. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/review_setup.py +0 -0
  296. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/search.py +0 -0
  297. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/show.py +0 -0
  298. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/commands/whoami.py +0 -0
  299. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/credential_native.py +0 -0
  300. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/credential_store.py +0 -0
  301. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/credentials.py +0 -0
  302. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/diffing.py +0 -0
  303. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/headline.py +0 -0
  304. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/hosted_run_status.py +0 -0
  305. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/inventory.py +0 -0
  306. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/local_review.py +0 -0
  307. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/login.py +0 -0
  308. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/path_kind.py +0 -0
  309. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/peek.py +0 -0
  310. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/plain_file.py +0 -0
  311. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/plan_check.py +0 -0
  312. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/preflight.py +0 -0
  313. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/readers.py +0 -0
  314. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/ux/workload.py +0 -0
  315. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/viewer.py +0 -0
  316. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/visual_run/__init__.py +0 -0
  317. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/visual_run/authoring.py +0 -0
  318. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/visual_run/contracts.py +0 -0
  319. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/visual_run/materialize.py +0 -0
  320. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/visual_run/observations.py +0 -0
  321. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/visual_run/query.py +0 -0
  322. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/visual_run/reducer.py +0 -0
  323. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/visual_run/sdk.py +0 -0
  324. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/visual_run/store.py +0 -0
  325. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/src/mostlyright/data_harness/visual_run/transport.py +0 -0
  326. {mostlyright_data-0.9.5 → mostlyright_data-0.9.7}/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.5
3
+ Version: 0.9.7
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/
@@ -81,12 +81,11 @@ Description-Content-Type: text/markdown
81
81
 
82
82
  # mostlyright-data
83
83
 
84
- Mostly Right turns historical and live public data—weather, economic releases, financial reports,
85
- and satellite data—into consistent datasets for analysis and prediction. Each dataset includes
86
- source links, timestamps, and check results.
84
+ Browse datasets built by our community or create your own with agents that find the sources and
85
+ configure the pipeline. Mostly Right keeps the dataset live.
87
86
 
88
- `mostlyright-data` is the command-line client. It starts hosted research and build work, follows
89
- run status, and downloads completed Parquet datasets.
87
+ `mostlyright-data` is the command-line client. It opens hosted research sessions, starts and
88
+ follows hosted dataset runs, and downloads verified datasets after they finish.
90
89
 
91
90
  ## Requirements
92
91
 
@@ -119,20 +118,20 @@ mr-data --help
119
118
  Use `mr-data research-open`, `mr-data research-status`, and `mr-data research-close` for hosted
120
119
  research sessions. `research-status` shows the current state.
121
120
 
122
- ## Local tools
121
+ ## Local execution
123
122
 
124
- The optional local tools require Linux:
123
+ The local execution lane runs only on Linux:
125
124
 
126
125
  ```bash
127
126
  python -m pip install "mostlyright-data[local]"
128
127
  ```
129
128
 
130
- They build and check worker inputs. They are not required for the hosted client.
129
+ It builds and checks worker inputs. It is not required for the hosted client.
131
130
 
132
131
  ## Documentation
133
132
 
134
133
  - [CLI guide](https://mostlyright.md/docs/guides/cli/)
135
- - [Research sessions](https://mostlyright.md/docs/guides/research/)
134
+ - [Hosted research sessions](https://mostlyright.md/docs/guides/hosted-research/)
136
135
  - [Credentials](https://mostlyright.md/docs/guides/credentials/)
137
136
  - [Public datasets](https://mostlyright.md/docs/guides/use-public-datasets/)
138
137
 
@@ -141,11 +140,11 @@ Use `mr-data --help` for the full command list and options. Commands that suppor
141
140
 
142
141
  For local builds, `--input-root` and `--output` may use relative paths.
143
142
 
144
- ## Limits and behavior
143
+ ## Behavior and limits
145
144
 
146
145
  - `mr-data review --local RUN_DIR` exits 1 when a check fails.
147
- - The weather Reader accepts one extracted GRIB2 record. It refuses a multi-record GFS or HRRR file.
148
- - Hosted credential-free acquisition is limited to one single-address public HTTPS object. Bounded collections require both local attestations.
146
+ - The weather reader accepts one extracted GRIB2 record. It refuses a multi-record GFS or HRRR file.
147
+ - Hosted credential-free acquisition supports one single-address public HTTPS object. Bounded collections require both local attestations.
149
148
 
150
149
  ## Verification
151
150
 
@@ -1,11 +1,10 @@
1
1
  # mostlyright-data
2
2
 
3
- Mostly Right turns historical and live public data—weather, economic releases, financial reports,
4
- and satellite data—into consistent datasets for analysis and prediction. Each dataset includes
5
- source links, timestamps, and check results.
3
+ Browse datasets built by our community or create your own with agents that find the sources and
4
+ configure the pipeline. Mostly Right keeps the dataset live.
6
5
 
7
- `mostlyright-data` is the command-line client. It starts hosted research and build work, follows
8
- run status, and downloads completed Parquet datasets.
6
+ `mostlyright-data` is the command-line client. It opens hosted research sessions, starts and
7
+ follows hosted dataset runs, and downloads verified datasets after they finish.
9
8
 
10
9
  ## Requirements
11
10
 
@@ -38,20 +37,20 @@ mr-data --help
38
37
  Use `mr-data research-open`, `mr-data research-status`, and `mr-data research-close` for hosted
39
38
  research sessions. `research-status` shows the current state.
40
39
 
41
- ## Local tools
40
+ ## Local execution
42
41
 
43
- The optional local tools require Linux:
42
+ The local execution lane runs only on Linux:
44
43
 
45
44
  ```bash
46
45
  python -m pip install "mostlyright-data[local]"
47
46
  ```
48
47
 
49
- They build and check worker inputs. They are not required for the hosted client.
48
+ It builds and checks worker inputs. It is not required for the hosted client.
50
49
 
51
50
  ## Documentation
52
51
 
53
52
  - [CLI guide](https://mostlyright.md/docs/guides/cli/)
54
- - [Research sessions](https://mostlyright.md/docs/guides/research/)
53
+ - [Hosted research sessions](https://mostlyright.md/docs/guides/hosted-research/)
55
54
  - [Credentials](https://mostlyright.md/docs/guides/credentials/)
56
55
  - [Public datasets](https://mostlyright.md/docs/guides/use-public-datasets/)
57
56
 
@@ -60,11 +59,11 @@ Use `mr-data --help` for the full command list and options. Commands that suppor
60
59
 
61
60
  For local builds, `--input-root` and `--output` may use relative paths.
62
61
 
63
- ## Limits and behavior
62
+ ## Behavior and limits
64
63
 
65
64
  - `mr-data review --local RUN_DIR` exits 1 when a check fails.
66
- - The weather Reader accepts one extracted GRIB2 record. It refuses a multi-record GFS or HRRR file.
67
- - Hosted credential-free acquisition is limited to one single-address public HTTPS object. Bounded collections require both local attestations.
65
+ - The weather reader accepts one extracted GRIB2 record. It refuses a multi-record GFS or HRRR file.
66
+ - Hosted credential-free acquisition supports one single-address public HTTPS object. Bounded collections require both local attestations.
68
67
 
69
68
  ## Verification
70
69
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mostlyright-data"
3
- version = "0.9.5"
3
+ version = "0.9.7"
4
4
  description = "Mostly Right CLI for reproducible, reviewed Parquet datasets"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.13,<3.14"
@@ -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
- if key in endpoints or tuple(sorted(normalized)) != addresses:
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 = tuple(sorted(dict.fromkeys(approved)))
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:
@@ -96,7 +96,6 @@ from mostlyright.data_harness.offline import (
96
96
  )
97
97
  from mostlyright.data_harness.pipeline import (
98
98
  _VERIFY_ALLOWLISTED_ENGINES,
99
- MAX_ROWS,
100
99
  SOURCE_PROPOSAL_SET_VERSION,
101
100
  BuildError,
102
101
  ResourceLimits,
@@ -106,7 +105,10 @@ from mostlyright.data_harness.pipeline import (
106
105
  verify_candidate, # noqa: F401 - retained for compatibility/security-route monkeypatch tests
107
106
  )
108
107
  from mostlyright.data_harness.plan_graph import (
108
+ HARD_MAX_INTERMEDIATE_ROWS,
109
+ HARD_MAX_OUTPUT_ROWS,
109
110
  HARD_MAX_RETAINED_BYTES,
111
+ HARD_MAX_SOURCE_ROWS,
110
112
  GraphResourcePolicy,
111
113
  )
112
114
  from mostlyright.data_harness.readers.contracts import ReaderError
@@ -393,17 +395,44 @@ def _selected_graph_limits(
393
395
  max_intermediate_rows: int | None,
394
396
  max_retained_bytes: int | None,
395
397
  ) -> ResourceLimits | None:
396
- """Select only explicitly raised graph dimensions; keep every other row cap at 100k."""
398
+ """Narrow the trusted graph policy by exactly the dimensions the operator named.
399
+
400
+ These flags are a NARROWING instrument and nothing else. The baseline is what a build with no
401
+ flags at all already runs under -- ``GraphResourcePolicy()``, whose defaults are the engine's
402
+ own hard ceilings -- so an unnamed dimension keeps that ceiling and a named one lowers only
403
+ itself. The invariant is worth stating because it is what makes the flags safe to reach for:
404
+ for every dimension, the policy this returns is at most the no-flag default, and equals it
405
+ unless the flag naming that dimension was supplied.
406
+
407
+ It used to default every row dimension to ``pipeline.MAX_ROWS`` instead. That is the v1 plan's
408
+ row policy, not the graph engine's, and it is 1/100th of ``HARD_MAX_SOURCE_ROWS``: naming a
409
+ byte budget alone silently cut a v2 build's row ceiling to 100k, which is the opposite of what
410
+ an operator raising a budget is asking for. ``build`` only reaches this function for a v2 plan
411
+ -- a graph flag on a v1 plan is refused as ``GRAPH_POLICY_V1`` before the build starts -- so
412
+ there is no v1 caller whose 100k cap this could be speaking for.
413
+
414
+ ``--graph-max-rows`` sets the source AND output ceilings, as its help says: one number for
415
+ "how many rows this build may read and release". The intermediate ceiling is separate because
416
+ the engine's own contract separates them (``HARD_MAX_INTERMEDIATE_ROWS`` is four times
417
+ ``HARD_MAX_SOURCE_ROWS``, sized for a union of several year-scale sources), so an operator who
418
+ wants a narrower working set says so with the flag that means it.
419
+ """
397
420
 
398
421
  if max_rows is None and max_intermediate_rows is None and max_retained_bytes is None:
399
422
  return None
400
- selected_rows = max_rows or MAX_ROWS
423
+ selected_rows = max_rows or HARD_MAX_SOURCE_ROWS
401
424
  return ResourceLimits(
425
+ # The v1 field, carried for a v2 build so `_replay_graph_derivations` streams sources under
426
+ # the policy rather than under the 100k default. It re-derives the same value from
427
+ # `graph_policy` anyway; agreeing here keeps the two from reading differently.
402
428
  max_rows=selected_rows,
403
429
  graph_policy=GraphResourcePolicy(
404
430
  max_source_rows=selected_rows,
405
- max_intermediate_rows=max_intermediate_rows or selected_rows,
406
- max_output_rows=selected_rows,
431
+ max_intermediate_rows=max_intermediate_rows or HARD_MAX_INTERMEDIATE_ROWS,
432
+ # `min` because the two ceilings are equal today and are not the same contract: a
433
+ # source ceiling that ever rose above the output one must not raise the output one
434
+ # with it.
435
+ max_output_rows=min(selected_rows, HARD_MAX_OUTPUT_ROWS),
407
436
  max_retained_bytes=max_retained_bytes or HARD_MAX_RETAINED_BYTES,
408
437
  ),
409
438
  )
@@ -1834,22 +1863,29 @@ def _parser(
1834
1863
  build.add_argument("--producer-principal", required=True, help=_BUILT_BY)
1835
1864
  build.add_argument("--producer-attempt", required=True, help=_BUILD_ATTEMPT)
1836
1865
  build.add_argument("--research-dir", type=Path, help="existing visual research directory")
1866
+ # ⚠ THE ARGPARSE MAXIMA ARE THE ENGINE'S OWN HARD CEILINGS, and deliberately not a second,
1867
+ # smaller policy. `GraphResourcePolicy.__post_init__` is the single enforcement point -- it
1868
+ # refuses anything above a ceiling whatever route the value arrived by -- so a smaller number
1869
+ # here would not be a safety property, only a cap the CLI applies and the library does not.
1870
+ # The previous maxima (1M rows, 2M intermediate, 256 MiB retained) were 1/10th, 1/20th and
1871
+ # 1/64th of the ceilings they front, with nothing written down deriving them, and they made
1872
+ # the year-scale capacity the graph engine documents unreachable from the command line.
1837
1873
  build.add_argument(
1838
1874
  "--graph-max-rows",
1839
- type=_integer_between(1, 1_000_000),
1840
- metavar="1..1000000",
1875
+ type=_integer_between(1, HARD_MAX_SOURCE_ROWS),
1876
+ metavar=f"1..{HARD_MAX_SOURCE_ROWS}",
1841
1877
  help="trusted graph source/output row ceiling (v2 plans only)",
1842
1878
  )
1843
1879
  build.add_argument(
1844
1880
  "--graph-max-intermediate-rows",
1845
- type=_integer_between(1, 2_000_000),
1881
+ type=_integer_between(1, HARD_MAX_INTERMEDIATE_ROWS),
1846
1882
  default=None,
1847
- metavar="1..2000000",
1883
+ metavar=f"1..{HARD_MAX_INTERMEDIATE_ROWS}",
1848
1884
  help="trusted graph intermediate row ceiling",
1849
1885
  )
1850
1886
  build.add_argument(
1851
1887
  "--graph-max-retained-bytes",
1852
- type=_integer_between(1, 256 * 1024 * 1024),
1888
+ type=_integer_between(1, HARD_MAX_RETAINED_BYTES),
1853
1889
  default=None,
1854
1890
  metavar="BYTES",
1855
1891
  help="trusted graph retained-byte ceiling",
@@ -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 deployed selection, Studio response, and parsed recipe mode before execution."""
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
- static = {
536
- "builder_image_digest": binding.producer_image_digest,
537
- "verifier_image_digest": binding.verifier_image_digest,
538
- "validation_policy_digests": binding.validation_policy_digests,
539
- "policy_set_digest": binding.policy_set_digest,
540
- "selection_fence": binding.release_revision_coordinate,
541
- "selection_id": binding.selection_id,
542
- "policy_mode": mode,
543
- "validation_policy_digest": binding.validation_policy_digests[mode],
544
- }
545
- mismatched = [name for name, value in static.items() if job_preflight.get(name) != value]
546
- if mismatched:
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 differs from the deployed selection: " + ",".join(mismatched),
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.add_argument("--exchange-url", required=True)
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", required=True, choices=("producer", "verifier", "generic_api"))
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=arguments.exchange_url,
1151
+ exchange_url=exchange_url,
1009
1152
  audience=arguments.audience,
1010
- role=arguments.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
- user_agent="MostlyRightDataHarness-PublicHttps/1.0",
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
  )