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,162 @@
1
+ """Deterministic source-fitness report construction and comparison."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+
7
+ from mostlyright.data_harness.local_contracts import SourceProposal
8
+ from mostlyright.data_harness.sources.contracts import (
9
+ FITNESS_DIMENSIONS,
10
+ EvidenceReference,
11
+ FitnessEvidence,
12
+ FitnessReport,
13
+ RightsEvidence,
14
+ SourceContractError,
15
+ SourceObservation,
16
+ evaluate_obligations,
17
+ )
18
+ from mostlyright.data_harness.sources.rights_rule import rights_disposition
19
+
20
+
21
+ @dataclass(frozen=True)
22
+ class FitnessSignals:
23
+ """Worker-calculated or exact-review inputs for every required dimension."""
24
+
25
+ outcomes: tuple[tuple[str, bool], ...]
26
+ summaries: tuple[tuple[str, str], ...]
27
+ evidence: tuple[EvidenceReference, ...]
28
+
29
+ def __post_init__(self) -> None:
30
+ outcome_keys = [key for key, _ in self.outcomes]
31
+ summary_keys = [key for key, _ in self.summaries]
32
+ if set(outcome_keys) != FITNESS_DIMENSIONS or len(outcome_keys) != len(FITNESS_DIMENSIONS):
33
+ raise SourceContractError(
34
+ "FITNESS_SIGNALS",
35
+ "signals.outcomes",
36
+ "must contain each required fitness dimension exactly once",
37
+ )
38
+ if set(summary_keys) != FITNESS_DIMENSIONS or len(summary_keys) != len(FITNESS_DIMENSIONS):
39
+ raise SourceContractError(
40
+ "FITNESS_SIGNALS",
41
+ "signals.summaries",
42
+ "must contain each required fitness dimension exactly once",
43
+ )
44
+ if not self.evidence:
45
+ raise SourceContractError(
46
+ "FITNESS_EVIDENCE",
47
+ "signals.evidence",
48
+ "fitness requires immutable cited evidence",
49
+ )
50
+
51
+ def outcome_map(self) -> dict[str, bool]:
52
+ return dict(self.outcomes)
53
+
54
+ def summary_map(self) -> dict[str, str]:
55
+ return dict(self.summaries)
56
+
57
+
58
+ def build_fitness_report(
59
+ *,
60
+ report_id: str,
61
+ question_id: str,
62
+ proposal: SourceProposal,
63
+ observation: SourceObservation,
64
+ rights: RightsEvidence,
65
+ intended_use: str,
66
+ attached_license_artifact_digests: tuple[str, ...],
67
+ signals: FitnessSignals,
68
+ require_timely: bool,
69
+ max_publication_delay_seconds: int,
70
+ ) -> FitnessReport:
71
+ """Build a complete cited report and derive its decision."""
72
+
73
+ if proposal.source_id != observation.source_id:
74
+ raise SourceContractError(
75
+ "SOURCE_BINDING",
76
+ "proposal.source_id",
77
+ "proposal and observation source IDs must match",
78
+ )
79
+ if proposal.observed_at != observation.observed_at:
80
+ raise SourceContractError(
81
+ "OBSERVATION_TIME_BINDING",
82
+ "proposal.observed_at",
83
+ "proposal and worker observation must refer to the same observation time",
84
+ )
85
+ if max_publication_delay_seconds < 0:
86
+ raise SourceContractError(
87
+ "DELAY_LIMIT",
88
+ "max_publication_delay_seconds",
89
+ "must not be negative",
90
+ )
91
+ if rights_disposition(rights.status) == "admit":
92
+ evaluate_obligations(
93
+ rights=rights,
94
+ lifecycle="candidate",
95
+ intended_use=intended_use,
96
+ attached_artifact_digests=attached_license_artifact_digests,
97
+ )
98
+
99
+ outcomes = signals.outcome_map()
100
+ summaries = signals.summary_map()
101
+ cited_digests = tuple(item.content_sha256 for item in signals.evidence)
102
+ if rights_disposition(rights.status) != "admit":
103
+ outcomes["rights"] = False
104
+ summaries["rights"] = f"rights status {rights.status} blocks source selection"
105
+ if require_timely and (
106
+ observation.live_status != "live"
107
+ or observation.publication_delay_seconds > max_publication_delay_seconds
108
+ ):
109
+ outcomes["liveness"] = False
110
+ outcomes["publication_delay"] = False
111
+ summaries["liveness"] = (
112
+ f"timely source required; observed endpoint is {observation.live_status}"
113
+ )
114
+ summaries["publication_delay"] = (
115
+ f"observed delay {observation.publication_delay_seconds}s exceeds "
116
+ f"{max_publication_delay_seconds}s"
117
+ )
118
+
119
+ dimensions = tuple(
120
+ FitnessEvidence(
121
+ dimension=dimension,
122
+ outcome="pass" if outcomes[dimension] else "fail",
123
+ summary=summaries[dimension],
124
+ evidence_digests=cited_digests,
125
+ )
126
+ for dimension in sorted(FITNESS_DIMENSIONS)
127
+ )
128
+ failed = [item.dimension for item in dimensions if item.outcome != "pass"]
129
+ if rights_disposition(rights.status) == "escalate":
130
+ decision = "human_escalation_required"
131
+ reason = "rights are unclear and require human legal/product escalation"
132
+ elif failed:
133
+ decision = "rejected"
134
+ reason = f"failed fitness dimensions: {', '.join(failed)}"
135
+ else:
136
+ decision = "selected"
137
+ reason = "all required fitness dimensions pass"
138
+ return FitnessReport(
139
+ report_id=report_id,
140
+ question_id=question_id,
141
+ source_id=proposal.source_id,
142
+ observed_at=observation.observed_at,
143
+ intended_use=intended_use,
144
+ dimensions=dimensions,
145
+ decision=decision,
146
+ decision_reason=reason,
147
+ rights_digest=rights.digest,
148
+ observation_digest=observation.digest,
149
+ )
150
+
151
+
152
+ def select_one_source(reports: tuple[FitnessReport, ...]) -> FitnessReport:
153
+ """Require one and only one fully selected source."""
154
+
155
+ selected = tuple(report for report in reports if report.decision == "selected")
156
+ if len(selected) != 1:
157
+ raise SourceContractError(
158
+ "SOURCE_SELECTION",
159
+ "fitness_reports",
160
+ f"expected exactly one selected source, found {len(selected)}",
161
+ )
162
+ return selected[0]
@@ -0,0 +1,163 @@
1
+ """Pre-persistence classification and governance controls."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from dataclasses import dataclass
7
+
8
+ from mostlyright.data_harness.canonical import sha256_bytes
9
+ from mostlyright.data_harness.sources.contracts import SourceContractError
10
+
11
+ # Sized to the hosted contract's normalized-output maximum: the classification scan runs
12
+ # over the exact bytes a hosted acquisition persists, and a year-scale normalized source
13
+ # is gigabytes. The scan stays one bounded pass; measured at ~10 MB/s on digit-heavy
14
+ # tables (the payment-card scan dominates), so the ceiling costs minutes, not hours --
15
+ # the guard is against unbounded input, not against large input.
16
+ MAX_CLASSIFICATION_SCAN_BYTES = 4_294_967_296
17
+
18
+ _SECRET_PATTERNS = (
19
+ ("private_key", re.compile(rb"-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----")),
20
+ ("aws_access_key", re.compile(rb"\bAKIA[0-9A-Z]{16}\b")),
21
+ ("github_token", re.compile(rb"\bgh[pousr]_[A-Za-z0-9_]{30,255}\b")),
22
+ ("bearer_token", re.compile(rb"(?i)\bauthorization\s*:\s*bearer\s+\S{16,}")),
23
+ (
24
+ "credential_assignment",
25
+ re.compile(
26
+ rb"""(?ix)
27
+ \b(?:password|passwd|api[_-]?key|secret)\b
28
+ ["']?\s*[=:]\s*["']?\S{8,}
29
+ """
30
+ ),
31
+ ),
32
+ )
33
+ _HIGHLY_SENSITIVE_PATTERNS = (
34
+ (
35
+ "us_social_security_number",
36
+ re.compile(rb"(?<![0-9])(?:[0-6][0-9]{2}|7[0-6][0-9])-[0-9]{2}-[0-9]{4}(?![0-9])"),
37
+ ),
38
+ (
39
+ "health_record_field",
40
+ re.compile(rb"(?i)\b(?:diagnosis|medical_record|patient_id|health_condition)\b"),
41
+ ),
42
+ )
43
+ # The boundaries exclude adjacent letters as well as digits: a primary account number is
44
+ # never embedded inside a longer alphanumeric token, while a SHA-256 digest or a hex
45
+ # identifier routinely carries a thirteen-plus digit run that happens to pass Luhn -- the
46
+ # ECB ICP flow's structure digest opens with sixteen such digits, and a digit-only boundary
47
+ # refused a catalog entry over its own evidence digest. A separator-grouped or
48
+ # punctuation-adjacent number still matches, because quotes, commas, and whitespace are not
49
+ # alphanumeric.
50
+ _PAYMENT_CARD_PATTERN = re.compile(rb"(?<![0-9A-Za-z])(?:[0-9][ -]?){13,19}(?![0-9A-Za-z])")
51
+
52
+
53
+ def _luhn_valid(value: bytes) -> bool:
54
+ digits = [byte - ord("0") for byte in value if ord("0") <= byte <= ord("9")]
55
+ if not 13 <= len(digits) <= 19:
56
+ return False
57
+ total = 0
58
+ parity = len(digits) % 2
59
+ for index, digit in enumerate(digits):
60
+ if index % 2 == parity:
61
+ digit *= 2
62
+ if digit > 9:
63
+ digit -= 9
64
+ total += digit
65
+ return total % 10 == 0
66
+
67
+
68
+ @dataclass(frozen=True)
69
+ class ClassificationFinding:
70
+ code: str
71
+ byte_offset: int
72
+
73
+ def __post_init__(self) -> None:
74
+ if not self.code or type(self.byte_offset) is not int or self.byte_offset < 0:
75
+ raise SourceContractError(
76
+ "CLASSIFICATION_FINDING",
77
+ "classification.finding",
78
+ "finding code and byte offset must be valid",
79
+ )
80
+
81
+
82
+ @dataclass(frozen=True)
83
+ class ClassificationResult:
84
+ content_sha256: str
85
+ classification: str
86
+ admitted: bool
87
+ findings: tuple[ClassificationFinding, ...]
88
+
89
+
90
+ def classify_before_persistence(
91
+ content: bytes,
92
+ *,
93
+ declared_classification: str,
94
+ lawful_basis_declared: bool,
95
+ ) -> ClassificationResult:
96
+ """Scan bounded bytes before an admitted snapshot is persisted."""
97
+
98
+ if not isinstance(content, bytes):
99
+ raise SourceContractError("TYPE", "content", "classification content must be bytes")
100
+ if len(content) > MAX_CLASSIFICATION_SCAN_BYTES:
101
+ raise SourceContractError(
102
+ "CLASSIFICATION_LIMIT",
103
+ "content",
104
+ f"classification input exceeds {MAX_CLASSIFICATION_SCAN_BYTES} bytes",
105
+ )
106
+ if declared_classification not in {"public", "internal", "confidential", "restricted"}:
107
+ raise SourceContractError(
108
+ "CLASSIFICATION",
109
+ "declared_classification",
110
+ "must be public, internal, confidential, or restricted",
111
+ )
112
+ findings: list[ClassificationFinding] = []
113
+ for code, pattern in (*_SECRET_PATTERNS, *_HIGHLY_SENSITIVE_PATTERNS):
114
+ match = pattern.search(content)
115
+ if match:
116
+ findings.append(ClassificationFinding(code=code, byte_offset=match.start()))
117
+ payment_match = next(
118
+ (match for match in _PAYMENT_CARD_PATTERN.finditer(content) if _luhn_valid(match.group())),
119
+ None,
120
+ )
121
+ if payment_match is not None:
122
+ findings.append(
123
+ ClassificationFinding(
124
+ code="payment_card_candidate",
125
+ byte_offset=payment_match.start(),
126
+ )
127
+ )
128
+ if not lawful_basis_declared:
129
+ findings.append(ClassificationFinding(code="lawful_basis_missing", byte_offset=0))
130
+ admitted = not findings
131
+ return ClassificationResult(
132
+ content_sha256=sha256_bytes(content),
133
+ classification=declared_classification if admitted else "rejected",
134
+ admitted=admitted,
135
+ findings=tuple(findings),
136
+ )
137
+
138
+
139
+ def require_admissible(result: ClassificationResult) -> None:
140
+ if not result.admitted:
141
+ codes = sorted(item.code for item in result.findings)
142
+ raise SourceContractError(
143
+ "DATA_CLASSIFICATION_REJECTED",
144
+ "classification",
145
+ f"content must not persist; findings={codes}",
146
+ )
147
+
148
+
149
+ def classify_and_require_admissible(
150
+ content: bytes,
151
+ *,
152
+ declared_classification: str,
153
+ lawful_basis_declared: bool,
154
+ ) -> ClassificationResult:
155
+ """Return the sole admissible classification evidence for these exact bytes."""
156
+
157
+ result = classify_before_persistence(
158
+ content,
159
+ declared_classification=declared_classification,
160
+ lawful_basis_declared=lawful_basis_declared,
161
+ )
162
+ require_admissible(result)
163
+ return result
@@ -0,0 +1,173 @@
1
+ """Studio-hosted public HTTPS adapter.
2
+
3
+ Kept outside ``sources.adapters`` because the generated Studio boundary imports recipe contracts,
4
+ which in turn import the core source package. This leaf module may depend on both without making
5
+ the core adapter import graph cyclic.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass
11
+ from uuid import UUID
12
+
13
+ from mostlyright.data_harness.acquisition.http import seal_content_addressed_snapshot
14
+ from mostlyright.data_harness.canonical import canonical_sha256
15
+ from mostlyright.data_harness.local_contracts import ContractError, validate_source_locator
16
+ from mostlyright.data_harness.sources._adapter_steps import (
17
+ DecodeRecord,
18
+ _authorize_candidate,
19
+ _output,
20
+ )
21
+ from mostlyright.data_harness.sources.adapters import (
22
+ AdapterGovernance,
23
+ _bind_request,
24
+ _https_query,
25
+ )
26
+ from mostlyright.data_harness.sources.collections import COLLECTION_ADAPTER_ID
27
+ from mostlyright.data_harness.sources.contracts import (
28
+ AcquisitionRequest,
29
+ AdapterDescriptor,
30
+ SourceContractError,
31
+ )
32
+ from mostlyright.data_harness.sources.governance import (
33
+ classify_before_persistence,
34
+ require_admissible,
35
+ )
36
+ from mostlyright.data_harness.sources.registry import AcquisitionContext, AcquisitionOutput
37
+ from mostlyright.data_harness.ux.hosted_acquisition import (
38
+ StudioExchange,
39
+ acquire_public_https,
40
+ source_authority_digest,
41
+ )
42
+
43
+
44
+ @dataclass(frozen=True)
45
+ class HostedPublicHttpsAdapter:
46
+ """Public HTTPS adapter executed by Studio's credential-free hosted clean room."""
47
+
48
+ exchange: StudioExchange
49
+ workspace_id: UUID
50
+ governance: AdapterGovernance
51
+ descriptor: AdapterDescriptor
52
+
53
+ def __post_init__(self) -> None:
54
+ if self.descriptor.adapter_id == COLLECTION_ADAPTER_ID:
55
+ raise SourceContractError(
56
+ "HOSTED_COLLECTION_UNSUPPORTED",
57
+ "adapter.descriptor",
58
+ "bounded collections require the local attested acquisition route",
59
+ )
60
+ if self.descriptor.source_class not in {"user_url", "user_api", "external_adapter"}:
61
+ raise SourceContractError(
62
+ "ADAPTER_CLASS",
63
+ "adapter.descriptor.source_class",
64
+ "hosted public HTTPS adapter requires user_url, user_api, or external_adapter",
65
+ )
66
+
67
+ def acquire(
68
+ self,
69
+ request: AcquisitionRequest,
70
+ context: AcquisitionContext,
71
+ ) -> AcquisitionOutput:
72
+ _bind_request(request, self.descriptor)
73
+ if request.credential_reference_id is not None:
74
+ raise SourceContractError(
75
+ "AUTHENTICATED_SOURCE_REQUIRES_TRUSTED_GATEWAY",
76
+ "request.credential_reference_id",
77
+ "hosted public acquisition receives no source credential",
78
+ )
79
+ url, data_format, filename = _https_query(request.query)
80
+ try:
81
+ validate_source_locator(url, "https_url", "request.query.url")
82
+ except ContractError as error:
83
+ raise SourceContractError(
84
+ "HTTPS_URL",
85
+ "request.query.url",
86
+ "hosted public acquisition requires a credential-free canonical URL",
87
+ ) from error
88
+ _authorize_candidate(request, self.governance)
89
+ query = {
90
+ "url": url,
91
+ "data_format": data_format,
92
+ "filename": filename,
93
+ "reader_pin": None if request.reader_pin is None else dict(request.reader_pin),
94
+ "resource_caps": (
95
+ None if request.resource_caps is None else dict(request.resource_caps)
96
+ ),
97
+ "limits": {
98
+ "max_source_bytes": context.max_source_bytes,
99
+ "max_normalized_bytes": (
100
+ context.max_source_bytes
101
+ if context.max_normalized_bytes is None
102
+ else context.max_normalized_bytes
103
+ ),
104
+ "max_rows": context.max_rows,
105
+ "max_columns": context.max_columns,
106
+ },
107
+ }
108
+ acquired = acquire_public_https(
109
+ exchange=self.exchange,
110
+ workspace_id=self.workspace_id,
111
+ source_id=request.source_id,
112
+ source_authority_digest=source_authority_digest(request.source_id, query),
113
+ acquisition_attempt_id=context.attempt_id,
114
+ query=query,
115
+ )
116
+ classification = classify_before_persistence(
117
+ acquired.content,
118
+ declared_classification=self.governance.declared_classification,
119
+ lawful_basis_declared=self.governance.lawful_basis_declared,
120
+ )
121
+ require_admissible(classification)
122
+ snapshot_path = seal_content_addressed_snapshot(
123
+ context.snapshot_root,
124
+ content=acquired.content,
125
+ suffix=data_format,
126
+ )
127
+ decode = None
128
+ if acquired.family_id is not None:
129
+ if acquired.family_version is None or acquired.decode_options_digest is None:
130
+ raise SourceContractError(
131
+ "HOSTED_RESULT_BINDING",
132
+ "hosted.decode",
133
+ "hosted acquisition returned an incomplete Reader identity",
134
+ )
135
+ decode = DecodeRecord(
136
+ fetched_content_sha256=acquired.raw_content_sha256,
137
+ family_id=acquired.family_id,
138
+ family_version=acquired.family_version,
139
+ decode_options_digest=acquired.decode_options_digest,
140
+ flags=acquired.decode_flags,
141
+ )
142
+ transport_envelope = canonical_sha256(
143
+ {
144
+ "schema_version": "hosted-public-https-transport-envelope.v1",
145
+ "hosted_request_digest": acquired.request_digest,
146
+ "crawler_transport_evidence_digest": acquired.transport_evidence_digest,
147
+ "egress_policy_attestation": acquired.egress_policy_attestation,
148
+ "clean_room": {
149
+ "host_platform": "linux-amd64",
150
+ "parser_network_syscalls": "denied",
151
+ "parser_process_creation": "denied",
152
+ "no_new_privs": True,
153
+ },
154
+ }
155
+ )
156
+ return _output(
157
+ request=request,
158
+ descriptor=self.descriptor,
159
+ governance=self.governance,
160
+ snapshot_path=snapshot_path,
161
+ content=acquired.content,
162
+ data_format=acquired.data_format,
163
+ media_type=acquired.media_type,
164
+ source_uri=acquired.source_url,
165
+ final_uri=acquired.final_url,
166
+ classification=classification.classification,
167
+ transport_evidence_digest=transport_envelope,
168
+ parsed_schema_digest=acquired.parsed_schema_digest,
169
+ decode=decode,
170
+ )
171
+
172
+
173
+ __all__ = ["HostedPublicHttpsAdapter"]