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.
Files changed (314) hide show
  1. mostlyright/data_harness/__init__.py +158 -0
  2. mostlyright/data_harness/acquisition/__init__.py +55 -0
  3. mostlyright/data_harness/acquisition/http.py +2773 -0
  4. mostlyright/data_harness/acquisition/parsing.py +809 -0
  5. mostlyright/data_harness/acquisition/ranges.py +495 -0
  6. mostlyright/data_harness/acquisition/result_download.py +360 -0
  7. mostlyright/data_harness/acquisition/retention_admission.py +248 -0
  8. mostlyright/data_harness/acquisition/sandbox.py +4888 -0
  9. mostlyright/data_harness/acquisition/url_policy.py +530 -0
  10. mostlyright/data_harness/agent_runtime.py +2743 -0
  11. mostlyright/data_harness/assets/logo-ink.svg +31 -0
  12. mostlyright/data_harness/backends/__init__.py +28 -0
  13. mostlyright/data_harness/backends/pandas_backend.py +350 -0
  14. mostlyright/data_harness/backends/polars_backend.py +366 -0
  15. mostlyright/data_harness/backends/protocol.py +124 -0
  16. mostlyright/data_harness/backends/reference.py +83 -0
  17. mostlyright/data_harness/backends/registry.py +55 -0
  18. mostlyright/data_harness/backends/restrictions.py +126 -0
  19. mostlyright/data_harness/canonical.py +333 -0
  20. mostlyright/data_harness/catalog_job.py +625 -0
  21. mostlyright/data_harness/cli.py +5398 -0
  22. mostlyright/data_harness/contracts.py +53 -0
  23. mostlyright/data_harness/coordinator.py +1307 -0
  24. mostlyright/data_harness/deploy.py +924 -0
  25. mostlyright/data_harness/deploy_target.py +312 -0
  26. mostlyright/data_harness/deployment_evidence.py +1067 -0
  27. mostlyright/data_harness/event_presentation.py +576 -0
  28. mostlyright/data_harness/events.py +2152 -0
  29. mostlyright/data_harness/fast_delimited.py +239 -0
  30. mostlyright/data_harness/fleet.py +237 -0
  31. mostlyright/data_harness/formats.py +236 -0
  32. mostlyright/data_harness/governors.py +1163 -0
  33. mostlyright/data_harness/hosted_bootstrap.py +972 -0
  34. mostlyright/data_harness/hosted_crawler.py +1115 -0
  35. mostlyright/data_harness/hosted_crawler_container_smoke.py +351 -0
  36. mostlyright/data_harness/hosted_crawler_fetch.py +423 -0
  37. mostlyright/data_harness/hosted_crawler_job.py +1277 -0
  38. mostlyright/data_harness/hosted_crawler_protocol.py +676 -0
  39. mostlyright/data_harness/hosted_dataset.py +1500 -0
  40. mostlyright/data_harness/hosted_deploy.py +3037 -0
  41. mostlyright/data_harness/hosted_handoff.py +62 -0
  42. mostlyright/data_harness/hosted_ingestion_contract.py +504 -0
  43. mostlyright/data_harness/hosted_ingestion_job.py +356 -0
  44. mostlyright/data_harness/hosted_ingestion_job_smoke.py +40 -0
  45. mostlyright/data_harness/hosted_session_container_smoke.py +194 -0
  46. mostlyright/data_harness/hosted_session_worker.py +3554 -0
  47. mostlyright/data_harness/hosted_session_worker_job_smoke.py +46 -0
  48. mostlyright/data_harness/hosted_worker.py +6784 -0
  49. mostlyright/data_harness/ingestion/__init__.py +56 -0
  50. mostlyright/data_harness/ingestion/contracts.py +461 -0
  51. mostlyright/data_harness/ingestion/faults.py +42 -0
  52. mostlyright/data_harness/ingestion/gcs_store.py +1162 -0
  53. mostlyright/data_harness/ingestion/spool.py +130 -0
  54. mostlyright/data_harness/ingestion/store.py +885 -0
  55. mostlyright/data_harness/key_seam.py +434 -0
  56. mostlyright/data_harness/linux_process_boundary.py +262 -0
  57. mostlyright/data_harness/local_contracts.py +2880 -0
  58. mostlyright/data_harness/local_search/__init__.py +5 -0
  59. mostlyright/data_harness/local_search/build_index.py +1087 -0
  60. mostlyright/data_harness/local_search/contracts.py +920 -0
  61. mostlyright/data_harness/local_search/query_trace.py +266 -0
  62. mostlyright/data_harness/local_search/retrieval.py +700 -0
  63. mostlyright/data_harness/local_search/sealed.py +474 -0
  64. mostlyright/data_harness/local_search/service.py +784 -0
  65. mostlyright/data_harness/nbrender/CONTRACT.md +212 -0
  66. mostlyright/data_harness/nbrender/__init__.py +12 -0
  67. mostlyright/data_harness/nbrender/chrome.py +359 -0
  68. mostlyright/data_harness/nbrender/code_body.py +266 -0
  69. mostlyright/data_harness/nbrender/document.py +407 -0
  70. mostlyright/data_harness/nbrender/frame.py +275 -0
  71. mostlyright/data_harness/nbrender/interactive.py +337 -0
  72. mostlyright/data_harness/nbrender/markdown_body.py +477 -0
  73. mostlyright/data_harness/nbrender/mr_components.py +134 -0
  74. mostlyright/data_harness/nbrender/outputs_data.py +595 -0
  75. mostlyright/data_harness/nbrender/outputs_rich.py +906 -0
  76. mostlyright/data_harness/nbrender/outputs_source.py +260 -0
  77. mostlyright/data_harness/nbrender/outputs_stage.py +176 -0
  78. mostlyright/data_harness/nbrender/outputs_text.py +400 -0
  79. mostlyright/data_harness/nbrender/parse.py +394 -0
  80. mostlyright/data_harness/nbrender/status.py +40 -0
  81. mostlyright/data_harness/nbrender/tokens.py +1295 -0
  82. mostlyright/data_harness/notebook.py +1710 -0
  83. mostlyright/data_harness/offline.py +2049 -0
  84. mostlyright/data_harness/operation_registry.py +1007 -0
  85. mostlyright/data_harness/operator_setup.py +239 -0
  86. mostlyright/data_harness/pipeline.py +6428 -0
  87. mostlyright/data_harness/plan_graph.py +2026 -0
  88. mostlyright/data_harness/preparation/__init__.py +104 -0
  89. mostlyright/data_harness/preparation/contracts.py +1017 -0
  90. mostlyright/data_harness/preparation/engine.py +221 -0
  91. mostlyright/data_harness/preparation/errors.py +14 -0
  92. mostlyright/data_harness/preparation/gates.py +751 -0
  93. mostlyright/data_harness/preparation/joins.py +574 -0
  94. mostlyright/data_harness/preparation/profile.py +384 -0
  95. mostlyright/data_harness/preparation/table.py +217 -0
  96. mostlyright/data_harness/preparation/transforms.py +568 -0
  97. mostlyright/data_harness/progress_events.py +534 -0
  98. mostlyright/data_harness/readers/__init__.py +46 -0
  99. mostlyright/data_harness/readers/containers.py +963 -0
  100. mostlyright/data_harness/readers/contracts.py +542 -0
  101. mostlyright/data_harness/readers/delimited.py +257 -0
  102. mostlyright/data_harness/readers/grib2/__init__.py +33 -0
  103. mostlyright/data_harness/readers/grib2/admission.py +722 -0
  104. mostlyright/data_harness/readers/grib2/decode.py +1009 -0
  105. mostlyright/data_harness/readers/grib2/geometry.py +1133 -0
  106. mostlyright/data_harness/readers/grib2/portable_math.py +501 -0
  107. mostlyright/data_harness/readers/json_tabular.py +485 -0
  108. mostlyright/data_harness/readers/registry.py +514 -0
  109. mostlyright/data_harness/readers/samples/README.md +110 -0
  110. mostlyright/data_harness/readers/samples/archive.gzip/1.0.0/cities_one_stream/cities.csv.gz +0 -0
  111. mostlyright/data_harness/readers/samples/archive.gzip/1.0.0/cities_one_stream/expected.json +24 -0
  112. mostlyright/data_harness/readers/samples/archive.gzip/1.1.0/cities_one_stream/cities.csv.gz +0 -0
  113. mostlyright/data_harness/readers/samples/archive.gzip/1.1.0/cities_one_stream/expected.json +24 -0
  114. mostlyright/data_harness/readers/samples/archive.tar/1.0.0/cities_beside_a_directory_entry/cities.tar +0 -0
  115. mostlyright/data_harness/readers/samples/archive.tar/1.0.0/cities_beside_a_directory_entry/expected.json +24 -0
  116. mostlyright/data_harness/readers/samples/archive.tar/1.1.0/cities_beside_a_directory_entry/cities.tar +0 -0
  117. mostlyright/data_harness/readers/samples/archive.tar/1.1.0/cities_beside_a_directory_entry/expected.json +24 -0
  118. mostlyright/data_harness/readers/samples/archive.zip/1.0.0/cities_beside_a_second_member/cities.zip +0 -0
  119. mostlyright/data_harness/readers/samples/archive.zip/1.0.0/cities_beside_a_second_member/expected.json +25 -0
  120. mostlyright/data_harness/readers/samples/archive.zip/1.1.0/dwd_semicolon_station_member/dwd-station.zip +0 -0
  121. mostlyright/data_harness/readers/samples/archive.zip/1.1.0/dwd_semicolon_station_member/expected.json +25 -0
  122. mostlyright/data_harness/readers/samples/archive.zip/1.2.0/dwd_semicolon_station_member/dwd-station.zip +0 -0
  123. mostlyright/data_harness/readers/samples/archive.zip/1.2.0/dwd_semicolon_station_member/expected.json +25 -0
  124. mostlyright/data_harness/readers/samples/delimited_text/1.0.0/an_ordinary_comma_separated_table/cities.csv +3 -0
  125. mostlyright/data_harness/readers/samples/delimited_text/1.0.0/an_ordinary_comma_separated_table/expected.json +23 -0
  126. mostlyright/data_harness/readers/samples/delimited_text/1.0.0/quoted_fields_holding_the_delimiter/cities.tsv +5 -0
  127. mostlyright/data_harness/readers/samples/delimited_text/1.0.0/quoted_fields_holding_the_delimiter/expected.json +25 -0
  128. mostlyright/data_harness/readers/samples/delimited_text/1.1.0/an_hourly_observation_table_served_as_plain_text/expected.json +30 -0
  129. mostlyright/data_harness/readers/samples/delimited_text/1.1.0/an_hourly_observation_table_served_as_plain_text/observations.csv +5 -0
  130. mostlyright/data_harness/readers/samples/json.tabular/1.0.0/nested_hourly_observations/expected.json +44 -0
  131. mostlyright/data_harness/readers/samples/json.tabular/1.0.0/nested_hourly_observations/stations.json +1 -0
  132. mostlyright/data_harness/readers/samples/json.tabular/1.1.0/an_observation_stream_served_as_plain_text/expected.json +48 -0
  133. mostlyright/data_harness/readers/samples/json.tabular/1.1.0/an_observation_stream_served_as_plain_text/observations.ndjson +4 -0
  134. mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/an_ordinary_table_beside_a_second_sheet/cities.xlsx +0 -0
  135. mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/an_ordinary_table_beside_a_second_sheet/expected.json +24 -0
  136. mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/shares_the_workbook_had_already_computed/expected.json +27 -0
  137. mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/shares_the_workbook_had_already_computed/shares.xlsx +0 -0
  138. mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.1.0/shares_the_workbook_had_already_computed/expected.json +27 -0
  139. mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.1.0/shares_the_workbook_had_already_computed/shares.xlsx +0 -0
  140. mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/README.md +20 -0
  141. mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/gfs_2m_temperature/expected.json +55 -0
  142. mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/gfs_2m_temperature/gfs-2m-temperature.grib2 +0 -0
  143. mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_2m_temperature/expected.json +54 -0
  144. mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_2m_temperature/hrrr-2m-temperature.grib2 +0 -0
  145. mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_categorical_rain/expected.json +54 -0
  146. mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_categorical_rain/hrrr-categorical-rain.grib2 +0 -0
  147. mostlyright/data_harness/readers/samples/weather.grib2/2.0.0/hrrr_2m_temperature/expected.json +54 -0
  148. mostlyright/data_harness/readers/samples/weather.grib2/2.0.0/hrrr_2m_temperature/hrrr-2m-temperature.grib2 +0 -0
  149. mostlyright/data_harness/readers/samples.py +582 -0
  150. mostlyright/data_harness/readers/spreadsheet.py +803 -0
  151. mostlyright/data_harness/readers/tabular.py +510 -0
  152. mostlyright/data_harness/recipe.py +5321 -0
  153. mostlyright/data_harness/repair/__init__.py +78 -0
  154. mostlyright/data_harness/repair/adapters.py +274 -0
  155. mostlyright/data_harness/repair/contracts.py +872 -0
  156. mostlyright/data_harness/repair/coordinator.py +1099 -0
  157. mostlyright/data_harness/repair/errors.py +16 -0
  158. mostlyright/data_harness/review.py +2533 -0
  159. mostlyright/data_harness/rowset.py +283 -0
  160. mostlyright/data_harness/serving.py +1975 -0
  161. mostlyright/data_harness/serving_edge.py +590 -0
  162. mostlyright/data_harness/serving_http.py +1031 -0
  163. mostlyright/data_harness/session_probes.py +759 -0
  164. mostlyright/data_harness/signing.py +101 -0
  165. mostlyright/data_harness/source_discovery.py +898 -0
  166. mostlyright/data_harness/sources/__init__.py +209 -0
  167. mostlyright/data_harness/sources/_adapter_steps.py +213 -0
  168. mostlyright/data_harness/sources/adapters.py +1214 -0
  169. mostlyright/data_harness/sources/cadence.py +1428 -0
  170. mostlyright/data_harness/sources/cadence_emission.py +453 -0
  171. mostlyright/data_harness/sources/cadence_history.py +546 -0
  172. mostlyright/data_harness/sources/catalog/__init__.py +17 -0
  173. mostlyright/data_harness/sources/catalog/admission.py +477 -0
  174. mostlyright/data_harness/sources/catalog/authoring.py +1701 -0
  175. mostlyright/data_harness/sources/catalog/authoring_policy.py +701 -0
  176. mostlyright/data_harness/sources/catalog/authoring_shards.py +1217 -0
  177. mostlyright/data_harness/sources/catalog/bounded_io.py +231 -0
  178. mostlyright/data_harness/sources/catalog/channel.py +523 -0
  179. mostlyright/data_harness/sources/catalog/channel_client.py +296 -0
  180. mostlyright/data_harness/sources/catalog/contracts.py +825 -0
  181. mostlyright/data_harness/sources/catalog/coverage.py +137 -0
  182. mostlyright/data_harness/sources/catalog/delta.py +1340 -0
  183. mostlyright/data_harness/sources/catalog/embedding.py +532 -0
  184. mostlyright/data_harness/sources/catalog/entry_v2.py +1182 -0
  185. mostlyright/data_harness/sources/catalog/fill.py +3889 -0
  186. mostlyright/data_harness/sources/catalog/fill_partitions.py +459 -0
  187. mostlyright/data_harness/sources/catalog/fill_staging.py +1105 -0
  188. mostlyright/data_harness/sources/catalog/gating.py +374 -0
  189. mostlyright/data_harness/sources/catalog/generation_receipt.py +1607 -0
  190. mostlyright/data_harness/sources/catalog/harvest/__init__.py +7 -0
  191. mostlyright/data_harness/sources/catalog/harvest/ckan.py +384 -0
  192. mostlyright/data_harness/sources/catalog/harvest/datagov_v4.py +798 -0
  193. mostlyright/data_harness/sources/catalog/harvest/protocol.py +964 -0
  194. mostlyright/data_harness/sources/catalog/harvest/sdmx.py +445 -0
  195. mostlyright/data_harness/sources/catalog/harvest/stac.py +384 -0
  196. mostlyright/data_harness/sources/catalog/health.py +447 -0
  197. mostlyright/data_harness/sources/catalog/hosted_catalog.py +105 -0
  198. mostlyright/data_harness/sources/catalog/identity_history.py +1549 -0
  199. mostlyright/data_harness/sources/catalog/neural.py +1618 -0
  200. mostlyright/data_harness/sources/catalog/packed_catalog.py +2345 -0
  201. mostlyright/data_harness/sources/catalog/packed_retrieval.py +1517 -0
  202. mostlyright/data_harness/sources/catalog/packed_writer.py +2802 -0
  203. mostlyright/data_harness/sources/catalog/query_trace.py +1037 -0
  204. mostlyright/data_harness/sources/catalog/recommend.py +171 -0
  205. mostlyright/data_harness/sources/catalog/retrieval.py +230 -0
  206. mostlyright/data_harness/sources/catalog/retrieval_manifest.py +995 -0
  207. mostlyright/data_harness/sources/catalog/rights_decisions.py +254 -0
  208. mostlyright/data_harness/sources/catalog/sealed.py +560 -0
  209. mostlyright/data_harness/sources/catalog/search.py +230 -0
  210. mostlyright/data_harness/sources/catalog/streaming_delta.py +1097 -0
  211. mostlyright/data_harness/sources/catalog/update.py +891 -0
  212. mostlyright/data_harness/sources/collections.py +815 -0
  213. mostlyright/data_harness/sources/contracts.py +2223 -0
  214. mostlyright/data_harness/sources/deletion.py +761 -0
  215. mostlyright/data_harness/sources/fitness.py +162 -0
  216. mostlyright/data_harness/sources/governance.py +163 -0
  217. mostlyright/data_harness/sources/hosted.py +173 -0
  218. mostlyright/data_harness/sources/integration.py +218 -0
  219. mostlyright/data_harness/sources/range_reader.py +418 -0
  220. mostlyright/data_harness/sources/registry.py +514 -0
  221. mostlyright/data_harness/sources/rights_rule.py +59 -0
  222. mostlyright/data_harness/sources/source_cadence_vectors.v1.json +1 -0
  223. mostlyright/data_harness/sources/sports.py +521 -0
  224. mostlyright/data_harness/sources/stream.py +524 -0
  225. mostlyright/data_harness/sources/stream_connector.py +418 -0
  226. mostlyright/data_harness/sources/stream_recorder.py +1404 -0
  227. mostlyright/data_harness/studio_boundary.py +2019 -0
  228. mostlyright/data_harness/thin/__init__.py +37 -0
  229. mostlyright/data_harness/thin/acquire.py +1137 -0
  230. mostlyright/data_harness/thin/acquire_cancel.py +579 -0
  231. mostlyright/data_harness/thin/approvals.py +617 -0
  232. mostlyright/data_harness/thin/commands.py +406 -0
  233. mostlyright/data_harness/thin/download.py +194 -0
  234. mostlyright/data_harness/thin/narrative.py +589 -0
  235. mostlyright/data_harness/thin/parity.py +1070 -0
  236. mostlyright/data_harness/thin/propose.py +2759 -0
  237. mostlyright/data_harness/thin/research.py +1663 -0
  238. mostlyright/data_harness/thin/router.py +924 -0
  239. mostlyright/data_harness/thin/runs.py +519 -0
  240. mostlyright/data_harness/thin/session.py +281 -0
  241. mostlyright/data_harness/thin/stream.py +501 -0
  242. mostlyright/data_harness/thin/transport.py +187 -0
  243. mostlyright/data_harness/thin/vocabulary.py +368 -0
  244. mostlyright/data_harness/thin/workers.py +164 -0
  245. mostlyright/data_harness/ucum/TABLE-PIN.json +40 -0
  246. mostlyright/data_harness/ucum/ucum-subset.v1.json +632 -0
  247. mostlyright/data_harness/unit_flow.py +927 -0
  248. mostlyright/data_harness/units.py +572 -0
  249. mostlyright/data_harness/ux/__init__.py +9 -0
  250. mostlyright/data_harness/ux/approve.py +485 -0
  251. mostlyright/data_harness/ux/author_yaml.py +597 -0
  252. mostlyright/data_harness/ux/cloud_auth.py +447 -0
  253. mostlyright/data_harness/ux/commands/__init__.py +260 -0
  254. mostlyright/data_harness/ux/commands/approve.py +136 -0
  255. mostlyright/data_harness/ux/commands/auth.py +744 -0
  256. mostlyright/data_harness/ux/commands/author.py +79 -0
  257. mostlyright/data_harness/ux/commands/catalog_author.py +403 -0
  258. mostlyright/data_harness/ux/commands/catalog_fill.py +523 -0
  259. mostlyright/data_harness/ux/commands/catalog_harvest.py +545 -0
  260. mostlyright/data_harness/ux/commands/catalog_publish.py +1838 -0
  261. mostlyright/data_harness/ux/commands/catalog_search.py +71 -0
  262. mostlyright/data_harness/ux/commands/catalog_update.py +437 -0
  263. mostlyright/data_harness/ux/commands/deploy.py +134 -0
  264. mostlyright/data_harness/ux/commands/deploy_dataset.py +98 -0
  265. mostlyright/data_harness/ux/commands/deploy_plan.py +105 -0
  266. mostlyright/data_harness/ux/commands/deploy_status.py +104 -0
  267. mostlyright/data_harness/ux/commands/diff.py +74 -0
  268. mostlyright/data_harness/ux/commands/index.py +84 -0
  269. mostlyright/data_harness/ux/commands/inventory.py +47 -0
  270. mostlyright/data_harness/ux/commands/list_builds.py +143 -0
  271. mostlyright/data_harness/ux/commands/login.py +63 -0
  272. mostlyright/data_harness/ux/commands/peek.py +236 -0
  273. mostlyright/data_harness/ux/commands/plan_check.py +90 -0
  274. mostlyright/data_harness/ux/commands/preflight.py +97 -0
  275. mostlyright/data_harness/ux/commands/record.py +107 -0
  276. mostlyright/data_harness/ux/commands/review_setup.py +47 -0
  277. mostlyright/data_harness/ux/commands/search.py +440 -0
  278. mostlyright/data_harness/ux/commands/show.py +61 -0
  279. mostlyright/data_harness/ux/commands/whoami.py +37 -0
  280. mostlyright/data_harness/ux/credential_native.py +551 -0
  281. mostlyright/data_harness/ux/credential_store.py +1055 -0
  282. mostlyright/data_harness/ux/credentials.py +631 -0
  283. mostlyright/data_harness/ux/diffing.py +444 -0
  284. mostlyright/data_harness/ux/headline.py +671 -0
  285. mostlyright/data_harness/ux/hosted_acquisition.py +974 -0
  286. mostlyright/data_harness/ux/hosted_run_status.py +619 -0
  287. mostlyright/data_harness/ux/inventory.py +427 -0
  288. mostlyright/data_harness/ux/local_review.py +375 -0
  289. mostlyright/data_harness/ux/login.py +691 -0
  290. mostlyright/data_harness/ux/path_kind.py +147 -0
  291. mostlyright/data_harness/ux/peek.py +1000 -0
  292. mostlyright/data_harness/ux/plain_file.py +178 -0
  293. mostlyright/data_harness/ux/plan_check.py +311 -0
  294. mostlyright/data_harness/ux/preflight.py +918 -0
  295. mostlyright/data_harness/ux/readers.py +1124 -0
  296. mostlyright/data_harness/ux/remediation.py +2195 -0
  297. mostlyright/data_harness/ux/render.py +657 -0
  298. mostlyright/data_harness/ux/workload.py +1077 -0
  299. mostlyright/data_harness/viewer.py +3713 -0
  300. mostlyright/data_harness/visual_run/__init__.py +83 -0
  301. mostlyright/data_harness/visual_run/authoring.py +235 -0
  302. mostlyright/data_harness/visual_run/contracts.py +673 -0
  303. mostlyright/data_harness/visual_run/materialize.py +486 -0
  304. mostlyright/data_harness/visual_run/observations.py +874 -0
  305. mostlyright/data_harness/visual_run/query.py +259 -0
  306. mostlyright/data_harness/visual_run/reducer.py +280 -0
  307. mostlyright/data_harness/visual_run/sdk.py +892 -0
  308. mostlyright/data_harness/visual_run/store.py +584 -0
  309. mostlyright/data_harness/visual_run/transport.py +239 -0
  310. mostlyright/data_harness/watch.py +2999 -0
  311. mostlyright_data-0.9.0.dist-info/METADATA +607 -0
  312. mostlyright_data-0.9.0.dist-info/RECORD +314 -0
  313. mostlyright_data-0.9.0.dist-info/WHEEL +4 -0
  314. mostlyright_data-0.9.0.dist-info/entry_points.txt +12 -0
@@ -0,0 +1,523 @@
1
+ """``mr-data catalog-fill``: bounded staging followed by one complete publication.
2
+
3
+ This is the small-catalog command: one invocation stages a whole public catalog and publishes one
4
+ successor from it, with the authored entries handed in as one document.
5
+
6
+ A keyed provider-scale catalog is not filled this way and this command refuses to try. That work
7
+ is three separate commands with three separate receipts -- ``catalog-harvest``, then
8
+ ``catalog-author``, then ``catalog-publish`` -- because a sweep of several hundred thousand
9
+ records is interrupted and resumed rather than run once, and because the key that reaches it
10
+ belongs to exactly one of those three.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import argparse
16
+ import os
17
+ import re
18
+ import stat
19
+ from dataclasses import dataclass
20
+ from pathlib import Path
21
+ from typing import Any
22
+ from urllib.parse import urlsplit
23
+
24
+ from mostlyright.data_harness.acquisition.http import (
25
+ PinnedHttpsRetriever,
26
+ RetrievalLimits,
27
+ StdlibPinnedTransport,
28
+ )
29
+ from mostlyright.data_harness.acquisition.url_policy import EgressPolicy, SystemResolver
30
+ from mostlyright.data_harness.canonical import parse_canonical_json, sha256_bytes
31
+ from mostlyright.data_harness.sources.catalog.contracts import (
32
+ CatalogEntry,
33
+ catalog_entry_from_dict,
34
+ )
35
+ from mostlyright.data_harness.sources.catalog.delta import (
36
+ checkpoint_catalog_delta_classification,
37
+ classify_catalog_delta,
38
+ publish_retrieval_catalog_successor,
39
+ )
40
+ from mostlyright.data_harness.sources.catalog.embedding import LexicalHashingBackend
41
+ from mostlyright.data_harness.sources.catalog.fill import (
42
+ CatalogFillConfig,
43
+ CatalogFillLimits,
44
+ run_catalog_fill,
45
+ )
46
+ from mostlyright.data_harness.sources.catalog.retrieval_manifest import load_retrieval_catalog
47
+ from mostlyright.data_harness.sources.catalog.rights_decisions import load_rights_decisions
48
+ from mostlyright.data_harness.sources.contracts import SourceContractError
49
+ from mostlyright.data_harness.ux.commands import CommandSpec
50
+
51
+ _AUTHORING_SCHEMA = "mr-data-catalog-fill-authoring.v1"
52
+ _MAX_AUTHORING_BYTES = 64 * 1024 * 1024
53
+ _DIGEST = re.compile(r"^[0-9a-f]{64}$")
54
+
55
+
56
+ @dataclass(frozen=True)
57
+ class _AuthoringBundle:
58
+ candidates_by_record_id: dict[str, CatalogEntry]
59
+ predecessor_record_ids: dict[str, str]
60
+ predecessor_chains: dict[str, tuple[CatalogEntry, ...]]
61
+
62
+
63
+ def add_arguments(parser: argparse.ArgumentParser) -> None:
64
+ parser.add_argument(
65
+ "--protocol",
66
+ choices=("ckan", "stac", "sdmx"),
67
+ required=True,
68
+ help=(
69
+ "the closed public catalog protocol; a keyed provider is harvested, authored and "
70
+ "published as three separate commands instead"
71
+ ),
72
+ )
73
+ parser.add_argument("--endpoint", required=True, help="credential-free public HTTPS endpoint")
74
+ parser.add_argument(
75
+ "--output",
76
+ dest="output_root",
77
+ type=Path,
78
+ required=True,
79
+ help="the explicit public catalog output root",
80
+ )
81
+ parser.add_argument(
82
+ "--predecessor",
83
+ dest="predecessor_root",
84
+ type=Path,
85
+ help="the exact predecessor catalog root, when updating",
86
+ )
87
+ parser.add_argument(
88
+ "--predecessor-sha256", help="the exact predecessor retrieval-manifest fingerprint"
89
+ )
90
+ parser.add_argument(
91
+ "--staging",
92
+ dest="staging_root",
93
+ type=Path,
94
+ required=True,
95
+ help="the private resumable staging root",
96
+ )
97
+ parser.add_argument(
98
+ "--checkpoint",
99
+ "--checkpoint-sha256",
100
+ dest="checkpoint_sha256",
101
+ help="the exact retained checkpoint fingerprint required for resume",
102
+ )
103
+ parser.add_argument(
104
+ "--observed-at", required=True, help="the canonical UTC observation timestamp"
105
+ )
106
+ parser.add_argument(
107
+ "--page-size", type=int, required=True, help="records requested per provider page"
108
+ )
109
+ parser.add_argument(
110
+ "--provider-count-reconciliation",
111
+ choices=("required-when-reported",),
112
+ required=True,
113
+ help="require equality whenever the provider reports a total",
114
+ )
115
+ parser.add_argument(
116
+ "--max-convergence-passes",
117
+ type=int,
118
+ required=True,
119
+ help="maximum complete passes allowed to reach convergence",
120
+ )
121
+ parser.add_argument(
122
+ "--max-requests", type=int, required=True, help="maximum aggregate network requests"
123
+ )
124
+ parser.add_argument(
125
+ "--max-responses", type=int, required=True, help="maximum aggregate network responses"
126
+ )
127
+ parser.add_argument(
128
+ "--max-pages", type=int, required=True, help="maximum aggregate provider pages"
129
+ )
130
+ parser.add_argument(
131
+ "--max-records", type=int, required=True, help="maximum aggregate provider records"
132
+ )
133
+ parser.add_argument(
134
+ "--max-response-bytes",
135
+ type=int,
136
+ required=True,
137
+ help="maximum bytes in one response",
138
+ )
139
+ parser.add_argument(
140
+ "--max-aggregate-bytes",
141
+ type=int,
142
+ required=True,
143
+ help="maximum bytes across all responses",
144
+ )
145
+ parser.add_argument(
146
+ "--max-wall-time-ns",
147
+ type=int,
148
+ required=True,
149
+ help="maximum cumulative retrieval time in nanoseconds",
150
+ )
151
+ parser.add_argument(
152
+ "--max-pages-this-invocation",
153
+ type=int,
154
+ help="stop after this many newly fetched pages and return an incomplete checkpoint",
155
+ )
156
+ parser.add_argument(
157
+ "--authoring",
158
+ type=Path,
159
+ required=True,
160
+ help="bounded canonical current-entry and predecessor mapping document",
161
+ )
162
+ parser.add_argument(
163
+ "--authoring-sha256", required=True, help="the exact authoring-document fingerprint"
164
+ )
165
+ parser.add_argument(
166
+ "--rights-decisions",
167
+ type=Path,
168
+ help="bounded canonical human rights-decision document for queued records",
169
+ )
170
+ parser.add_argument(
171
+ "--rights-decisions-sha256",
172
+ help="the exact rights-decision-document fingerprint",
173
+ )
174
+ parser.add_argument(
175
+ "--neural-mode",
176
+ choices=("lexical-only", "sidecar"),
177
+ required=True,
178
+ help="the explicit representation mode to publish",
179
+ )
180
+ parser.add_argument(
181
+ "--neural-model-root",
182
+ type=Path,
183
+ help="the explicit governed sidecar root for neural mode",
184
+ )
185
+
186
+
187
+ def run(args: argparse.Namespace) -> dict[str, Any]:
188
+ _validate_coordinate_pairs(args)
189
+ fill_result = _run_fill(args)
190
+ base = _fill_payload(args, fill_result)
191
+ if fill_result.status != "complete":
192
+ return {
193
+ **base,
194
+ "status": "catalog_fill_incomplete",
195
+ "manifest_sha256": None,
196
+ "publication_sha256": None,
197
+ }
198
+
199
+ # No caller-authored facts are read before the deterministic fill proves a complete,
200
+ # reconciled generation. In particular, a pilot or budget stop cannot reach publication.
201
+ bundle = _load_authoring_bundle(args.authoring, args.authoring_sha256)
202
+ rights_decisions = None
203
+ if args.rights_decisions is not None:
204
+ rights_decisions = load_rights_decisions(
205
+ args.rights_decisions, args.rights_decisions_sha256
206
+ )
207
+ lexical_backend, neural_backend, fallback_reason = _publication_backends(args)
208
+ try:
209
+ predecessor, predecessor_directory = _load_predecessor(args, neural_backend)
210
+ classification = classify_catalog_delta(
211
+ predecessor=predecessor,
212
+ predecessor_record_ids=bundle.predecessor_record_ids,
213
+ candidates_by_record_id=bundle.candidates_by_record_id,
214
+ fill_result=fill_result,
215
+ staging_root=args.staging_root,
216
+ predecessor_chains=bundle.predecessor_chains,
217
+ rights_decisions=rights_decisions,
218
+ rights_decisions_sha256=(
219
+ args.rights_decisions_sha256 if rights_decisions is not None else None
220
+ ),
221
+ )
222
+ classification_checkpoint = checkpoint_catalog_delta_classification(
223
+ classification,
224
+ staging_root=args.staging_root,
225
+ lexical_backend=lexical_backend,
226
+ neural_backend=neural_backend,
227
+ )
228
+ # This is the only public-writer call in the command. It happens after complete fill,
229
+ # strict authoring capture, predecessor verification, classification, and checkpointing.
230
+ publication = publish_retrieval_catalog_successor(
231
+ classification,
232
+ classification_checkpoint_sha256=classification_checkpoint,
233
+ staging_root=args.staging_root,
234
+ lexical_backend=lexical_backend,
235
+ neural_backend=neural_backend,
236
+ directory=args.output_root,
237
+ predecessor_directory=predecessor_directory,
238
+ egress_policy=_publication_citation_policy(args.endpoint, rights_decisions),
239
+ fallback_reason=fallback_reason,
240
+ )
241
+ finally:
242
+ close = getattr(neural_backend, "close", None)
243
+ if callable(close):
244
+ close()
245
+
246
+ return {
247
+ **base,
248
+ "status": "catalog_published",
249
+ "rights_decisions_sha256": classification.rights_decisions_sha256,
250
+ "classification_sha256": classification.digest,
251
+ "classification_checkpoint_sha256": classification_checkpoint,
252
+ "manifest_sha256": publication.manifest_sha256,
253
+ "publication_sha256": publication.digest,
254
+ "counts": {
255
+ "unchanged": publication.unchanged,
256
+ "changed": publication.changed,
257
+ "new": publication.new,
258
+ "absent": publication.absent,
259
+ "flagged": publication.flagged,
260
+ },
261
+ "representations": {
262
+ "lexical": {
263
+ "reused_vector_sha256s": list(publication.lexical_reused_vector_sha256s),
264
+ "created_vector_sha256s": list(publication.lexical_created_vector_sha256s),
265
+ "encoder_invocations": publication.lexical_encoder_invocations,
266
+ },
267
+ "neural": {
268
+ "reused_vector_sha256s": list(publication.neural_reused_vector_sha256s),
269
+ "created_vector_sha256s": list(publication.neural_created_vector_sha256s),
270
+ "encoder_invocations": publication.neural_encoder_invocations,
271
+ },
272
+ },
273
+ "fallback_reason": publication.fallback_reason,
274
+ }
275
+
276
+
277
+ def _run_fill(args: argparse.Namespace):
278
+ limits = CatalogFillLimits(
279
+ max_requests=args.max_requests,
280
+ max_pages=args.max_pages,
281
+ max_records=args.max_records,
282
+ max_response_bytes=args.max_response_bytes,
283
+ max_aggregate_bytes=args.max_aggregate_bytes,
284
+ max_responses=args.max_responses,
285
+ max_wall_time_ns=args.max_wall_time_ns,
286
+ )
287
+ config = CatalogFillConfig(
288
+ protocol=args.protocol,
289
+ endpoint=args.endpoint,
290
+ observed_at=args.observed_at,
291
+ page_size=args.page_size,
292
+ max_convergence_passes=args.max_convergence_passes,
293
+ limits=limits,
294
+ predecessor_sha256=args.predecessor_sha256,
295
+ )
296
+ retriever = PinnedHttpsRetriever(
297
+ resolver=SystemResolver(),
298
+ egress_policy=_endpoint_policy(args.endpoint),
299
+ transport=StdlibPinnedTransport(),
300
+ limits=RetrievalLimits(
301
+ max_response_bytes=min(args.max_response_bytes, 1 << 34),
302
+ max_aggregate_response_bytes=min(args.max_aggregate_bytes, 1 << 40),
303
+ max_redirects=5,
304
+ max_requests=16,
305
+ ),
306
+ )
307
+ return run_catalog_fill(
308
+ config=config,
309
+ staging_root=args.staging_root,
310
+ retriever=retriever,
311
+ expected_checkpoint_digest=args.checkpoint_sha256,
312
+ max_pages_this_invocation=args.max_pages_this_invocation,
313
+ )
314
+
315
+
316
+ def _fill_payload(args: argparse.Namespace, result) -> dict[str, Any]:
317
+ receipt = result.receipt
318
+ return {
319
+ "schema_version": "mr-data-catalog-fill.v1",
320
+ "reason_code": result.reason_code,
321
+ "fill_receipt_sha256": receipt.digest,
322
+ "fill_receipt": receipt.to_dict(),
323
+ "flagged_queue_sha256": receipt.flagged_queue_sha256,
324
+ "staging_sha256": result.eligible_staging_sha256,
325
+ "checkpoint_sha256": result.checkpoint_sha256,
326
+ "provider_count_reconciliation": args.provider_count_reconciliation,
327
+ "convergence_passes": receipt.convergence_passes,
328
+ }
329
+
330
+
331
+ def _validate_coordinate_pairs(args: argparse.Namespace) -> None:
332
+ predecessor_pair = (args.predecessor_root is None, args.predecessor_sha256 is None)
333
+ if predecessor_pair not in {(True, True), (False, False)}:
334
+ raise SourceContractError(
335
+ "CATALOG_PREDECESSOR_COORDINATE",
336
+ "predecessor",
337
+ "predecessor root and exact digest must be supplied together",
338
+ )
339
+ decisions_pair = (args.rights_decisions is None, args.rights_decisions_sha256 is None)
340
+ if decisions_pair not in {(True, True), (False, False)}:
341
+ raise SourceContractError(
342
+ "RIGHTS_DECISIONS_COORDINATE",
343
+ "rights_decisions",
344
+ "rights decisions and their exact digest must be supplied together",
345
+ )
346
+ if args.neural_mode == "sidecar" and args.neural_model_root is None:
347
+ raise SourceContractError(
348
+ "NEURAL_MODEL_ROOT_REQUIRED",
349
+ "neural_model_root",
350
+ "sidecar mode requires one explicit local model root",
351
+ )
352
+ if args.neural_mode == "lexical-only" and args.neural_model_root is not None:
353
+ raise SourceContractError(
354
+ "NEURAL_MODEL_ROOT_UNEXPECTED",
355
+ "neural_model_root",
356
+ "lexical-only mode accepts no model root",
357
+ )
358
+
359
+
360
+ def _endpoint_policy(endpoint: str) -> EgressPolicy:
361
+ hostname = urlsplit(endpoint).hostname
362
+ if hostname is None:
363
+ raise SourceContractError("FILL_ENDPOINT", "endpoint", "must name one public host")
364
+ return EgressPolicy(allowed_hostnames=(hostname.lower(),))
365
+
366
+
367
+ def _publication_citation_policy(endpoint: str, rights_decisions) -> EgressPolicy:
368
+ """The hosts a sealed entry may cite: the provider, plus what a person's decision cites.
369
+
370
+ Machine-derived citations all name the provider endpoint, so the fetch policy and the
371
+ citation policy used to be the same object. A human rights decision breaks that identity
372
+ by construction: the person looked at a licence page, and licence pages live on the
373
+ publisher's own site, not on its data API. The widening is bounded and receipted -- only
374
+ hosts named as evidence inside the digest-verified decision document join the allowlist,
375
+ and the document's digest rides the published classification. Network egress is untouched:
376
+ this policy governs which citations a sealed entry may carry, and the fetch retriever
377
+ keeps the endpoint-only policy.
378
+ """
379
+
380
+ endpoint_policy = _endpoint_policy(endpoint)
381
+ if not rights_decisions:
382
+ return endpoint_policy
383
+ hosts = set(endpoint_policy.allowed_hostnames)
384
+ for decision in rights_decisions.values():
385
+ for reference in decision.rights.evidence:
386
+ hostname = urlsplit(reference.uri).hostname
387
+ if hostname is not None:
388
+ hosts.add(hostname.lower())
389
+ return EgressPolicy(allowed_hostnames=tuple(sorted(hosts)))
390
+
391
+
392
+ def _publication_backends(args: argparse.Namespace):
393
+ lexical = LexicalHashingBackend()
394
+ if args.neural_mode == "lexical-only":
395
+ return lexical, None, "NEURAL_NOT_REQUESTED"
396
+ from mostlyright.data_harness.sources.catalog.neural import resolve_local_neural_backend
397
+
398
+ return lexical, resolve_local_neural_backend(args.neural_model_root), None
399
+
400
+
401
+ def _load_predecessor(args: argparse.Namespace, neural_backend):
402
+ if args.predecessor_root is None:
403
+ return (), None
404
+ loaded = load_retrieval_catalog(
405
+ args.predecessor_root,
406
+ expected_manifest_sha256=args.predecessor_sha256,
407
+ neural_backend=neural_backend,
408
+ )
409
+ return loaded.lexical.entries, args.predecessor_root
410
+
411
+
412
+ def _load_authoring_bundle(path: Path, expected_sha256: str) -> _AuthoringBundle:
413
+ if not isinstance(expected_sha256, str) or _DIGEST.fullmatch(expected_sha256) is None:
414
+ raise SourceContractError(
415
+ "CATALOG_AUTHORING_DIGEST", "authoring_sha256", "must be a lowercase SHA-256"
416
+ )
417
+ raw = _read_bounded_regular(path)
418
+ if sha256_bytes(raw) != expected_sha256:
419
+ raise SourceContractError(
420
+ "CATALOG_AUTHORING_DIGEST",
421
+ "authoring",
422
+ "authoring bytes differ from the required digest",
423
+ )
424
+ value = parse_canonical_json(raw)
425
+ expected = {
426
+ "schema_version",
427
+ "candidates_by_record_id",
428
+ "predecessor_record_ids",
429
+ "predecessor_chains",
430
+ }
431
+ if (
432
+ not isinstance(value, dict)
433
+ or set(value) != expected
434
+ or value["schema_version"] != _AUTHORING_SCHEMA
435
+ ):
436
+ raise SourceContractError(
437
+ "CATALOG_AUTHORING_SCHEMA", "authoring", "authoring fields or version differ"
438
+ )
439
+ candidates_raw = _mapping(value["candidates_by_record_id"], "candidates_by_record_id")
440
+ predecessor_ids_raw = _mapping(value["predecessor_record_ids"], "predecessor_record_ids")
441
+ chains_raw = _mapping(value["predecessor_chains"], "predecessor_chains")
442
+ all_keys = (*candidates_raw, *predecessor_ids_raw, *chains_raw)
443
+ if any(not isinstance(key, str) for key in all_keys):
444
+ raise SourceContractError(
445
+ "CATALOG_AUTHORING_SCHEMA", "authoring", "mapping keys must be strings"
446
+ )
447
+ candidates = {
448
+ key: catalog_entry_from_dict(candidate) for key, candidate in candidates_raw.items()
449
+ }
450
+ predecessor_ids: dict[str, str] = {}
451
+ for key, entry_id in predecessor_ids_raw.items():
452
+ if not isinstance(entry_id, str):
453
+ raise SourceContractError(
454
+ "CATALOG_AUTHORING_SCHEMA",
455
+ "predecessor_record_ids",
456
+ "entry identities must be strings",
457
+ )
458
+ predecessor_ids[key] = entry_id
459
+ chains: dict[str, tuple[CatalogEntry, ...]] = {}
460
+ for entry_id, raw_chain in chains_raw.items():
461
+ if not isinstance(raw_chain, list):
462
+ raise SourceContractError(
463
+ "CATALOG_AUTHORING_SCHEMA", "predecessor_chains", "chains must be arrays"
464
+ )
465
+ chains[entry_id] = tuple(catalog_entry_from_dict(item) for item in raw_chain)
466
+ return _AuthoringBundle(candidates, predecessor_ids, chains)
467
+
468
+
469
+ def _read_bounded_regular(path: Path) -> bytes:
470
+ flags = os.O_RDONLY | os.O_NONBLOCK | getattr(os, "O_NOFOLLOW", 0)
471
+ try:
472
+ descriptor = os.open(path, flags)
473
+ except OSError as error:
474
+ raise SourceContractError(
475
+ "CATALOG_AUTHORING_UNREADABLE", "authoring", "cannot open the authoring document"
476
+ ) from error
477
+ try:
478
+ opened = os.fstat(descriptor)
479
+ if not stat.S_ISREG(opened.st_mode) or opened.st_nlink != 1:
480
+ raise SourceContractError(
481
+ "CATALOG_AUTHORING_FILE",
482
+ "authoring",
483
+ "must be a single-link regular file",
484
+ )
485
+ if opened.st_size > _MAX_AUTHORING_BYTES:
486
+ raise SourceContractError(
487
+ "CATALOG_AUTHORING_LIMIT", "authoring", "exceeds the authoring byte limit"
488
+ )
489
+ chunks: list[bytes] = []
490
+ remaining = _MAX_AUTHORING_BYTES + 1
491
+ while remaining:
492
+ chunk = os.read(descriptor, min(remaining, 1 << 16))
493
+ if not chunk:
494
+ break
495
+ chunks.append(chunk)
496
+ remaining -= len(chunk)
497
+ finally:
498
+ os.close(descriptor)
499
+ raw = b"".join(chunks)
500
+ if len(raw) > _MAX_AUTHORING_BYTES:
501
+ raise SourceContractError(
502
+ "CATALOG_AUTHORING_LIMIT", "authoring", "exceeds the authoring byte limit"
503
+ )
504
+ return raw
505
+
506
+
507
+ def _mapping(value: Any, path: str) -> dict[str, Any]:
508
+ if not isinstance(value, dict):
509
+ raise SourceContractError("CATALOG_AUTHORING_SCHEMA", path, "must be an object")
510
+ return value
511
+
512
+
513
+ def _exit_code(payload: dict[str, Any]) -> int:
514
+ return 0 if payload.get("status") == "catalog_published" else 1
515
+
516
+
517
+ SPEC = CommandSpec(
518
+ name="catalog-fill",
519
+ help="stage, reconcile, and publish one bounded public catalog successor",
520
+ add_arguments=add_arguments,
521
+ run=run,
522
+ exit_code=_exit_code,
523
+ )