mostlyright-data 0.9.2__tar.gz → 0.9.4__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 (320) hide show
  1. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/PKG-INFO +5 -5
  2. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/README.md +3 -3
  3. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/pyproject.toml +3 -2
  4. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/acquisition/http.py +458 -12
  5. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/hosted_bootstrap.py +63 -10
  6. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/hosted_crawler_job.py +188 -88
  7. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/hosted_session_worker.py +137 -6
  8. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/hosted_worker.py +1806 -94
  9. mostlyright_data-0.9.4/src/mostlyright/data_harness/readers/parquet_tabular.py +158 -0
  10. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/registry.py +9 -0
  11. mostlyright_data-0.9.4/src/mostlyright/data_harness/readers/samples/parquet.tabular/1.0.0/two_columns/expected.json +25 -0
  12. mostlyright_data-0.9.4/src/mostlyright/data_harness/readers/samples/parquet.tabular/1.0.0/two_columns/prices.parquet +0 -0
  13. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/recipe.py +92 -0
  14. mostlyright_data-0.9.4/src/mostlyright/data_harness/sources/authenticated_https.py +367 -0
  15. mostlyright_data-0.9.4/src/mostlyright/data_harness/sources/authenticated_https_v2.py +1186 -0
  16. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/admission.py +5 -0
  17. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/authoring_shards.py +36 -2
  18. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/governance.py +98 -8
  19. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/studio_boundary.py +1 -1
  20. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/thin/research.py +34 -12
  21. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/thin/router.py +5 -4
  22. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/thin/vocabulary.py +6 -1
  23. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/thin/workers.py +6 -0
  24. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/catalog_author.py +29 -1
  25. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/catalog_publish.py +25 -4
  26. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/remediation.py +4 -1
  27. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/render.py +1 -0
  28. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/.gitignore +0 -0
  29. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/scripts/hatch_build.py +0 -0
  30. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/__init__.py +0 -0
  31. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/acquisition/__init__.py +0 -0
  32. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/acquisition/parsing.py +0 -0
  33. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/acquisition/ranges.py +0 -0
  34. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/acquisition/result_download.py +0 -0
  35. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/acquisition/retention_admission.py +0 -0
  36. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/acquisition/sandbox.py +0 -0
  37. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/acquisition/url_policy.py +0 -0
  38. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/agent_runtime.py +0 -0
  39. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/assets/logo-ink.svg +0 -0
  40. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/backends/__init__.py +0 -0
  41. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/backends/pandas_backend.py +0 -0
  42. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/backends/polars_backend.py +0 -0
  43. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/backends/protocol.py +0 -0
  44. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/backends/reference.py +0 -0
  45. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/backends/registry.py +0 -0
  46. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/backends/restrictions.py +0 -0
  47. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/canonical.py +0 -0
  48. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/catalog_job.py +0 -0
  49. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/cli.py +0 -0
  50. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/contracts.py +0 -0
  51. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/coordinator.py +0 -0
  52. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/deploy.py +0 -0
  53. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/deploy_target.py +0 -0
  54. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/deployment_evidence.py +0 -0
  55. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/event_presentation.py +0 -0
  56. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/events.py +0 -0
  57. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/fast_delimited.py +0 -0
  58. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/fleet.py +0 -0
  59. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/formats.py +0 -0
  60. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/governors.py +0 -0
  61. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/hosted_crawler.py +0 -0
  62. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/hosted_crawler_container_smoke.py +0 -0
  63. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/hosted_crawler_fetch.py +0 -0
  64. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/hosted_crawler_protocol.py +0 -0
  65. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/hosted_dataset.py +0 -0
  66. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/hosted_deploy.py +0 -0
  67. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/hosted_handoff.py +0 -0
  68. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/hosted_ingestion_contract.py +0 -0
  69. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/hosted_ingestion_job.py +0 -0
  70. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/hosted_ingestion_job_smoke.py +0 -0
  71. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/hosted_session_container_smoke.py +0 -0
  72. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/hosted_session_worker_job_smoke.py +0 -0
  73. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ingestion/__init__.py +0 -0
  74. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ingestion/contracts.py +0 -0
  75. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ingestion/faults.py +0 -0
  76. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ingestion/gcs_store.py +0 -0
  77. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ingestion/spool.py +0 -0
  78. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ingestion/store.py +0 -0
  79. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/key_seam.py +0 -0
  80. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/linux_process_boundary.py +0 -0
  81. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/local_contracts.py +0 -0
  82. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/local_search/__init__.py +0 -0
  83. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/local_search/build_index.py +0 -0
  84. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/local_search/contracts.py +0 -0
  85. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/local_search/query_trace.py +0 -0
  86. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/local_search/retrieval.py +0 -0
  87. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/local_search/sealed.py +0 -0
  88. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/local_search/service.py +0 -0
  89. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/nbrender/CONTRACT.md +0 -0
  90. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/nbrender/__init__.py +0 -0
  91. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/nbrender/chrome.py +0 -0
  92. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/nbrender/code_body.py +0 -0
  93. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/nbrender/document.py +0 -0
  94. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/nbrender/frame.py +0 -0
  95. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/nbrender/interactive.py +0 -0
  96. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/nbrender/markdown_body.py +0 -0
  97. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/nbrender/mr_components.py +0 -0
  98. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/nbrender/outputs_data.py +0 -0
  99. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/nbrender/outputs_rich.py +0 -0
  100. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/nbrender/outputs_source.py +0 -0
  101. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/nbrender/outputs_stage.py +0 -0
  102. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/nbrender/outputs_text.py +0 -0
  103. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/nbrender/parse.py +0 -0
  104. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/nbrender/status.py +0 -0
  105. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/nbrender/tokens.py +0 -0
  106. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/notebook.py +0 -0
  107. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/offline.py +0 -0
  108. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/operation_registry.py +0 -0
  109. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/operator_setup.py +0 -0
  110. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/pipeline.py +0 -0
  111. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/plan_graph.py +0 -0
  112. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/preparation/__init__.py +0 -0
  113. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/preparation/contracts.py +0 -0
  114. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/preparation/engine.py +0 -0
  115. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/preparation/errors.py +0 -0
  116. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/preparation/gates.py +0 -0
  117. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/preparation/joins.py +0 -0
  118. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/preparation/profile.py +0 -0
  119. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/preparation/table.py +0 -0
  120. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/preparation/transforms.py +0 -0
  121. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/progress_events.py +0 -0
  122. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/__init__.py +0 -0
  123. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/containers.py +0 -0
  124. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/contracts.py +0 -0
  125. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/delimited.py +0 -0
  126. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/grib2/__init__.py +0 -0
  127. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/grib2/admission.py +0 -0
  128. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/grib2/decode.py +0 -0
  129. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/grib2/geometry.py +0 -0
  130. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/grib2/portable_math.py +0 -0
  131. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/json_tabular.py +0 -0
  132. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/README.md +0 -0
  133. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/archive.gzip/1.0.0/cities_one_stream/cities.csv.gz +0 -0
  134. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/archive.gzip/1.0.0/cities_one_stream/expected.json +0 -0
  135. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/archive.gzip/1.1.0/cities_one_stream/cities.csv.gz +0 -0
  136. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/archive.gzip/1.1.0/cities_one_stream/expected.json +0 -0
  137. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/archive.tar/1.0.0/cities_beside_a_directory_entry/cities.tar +0 -0
  138. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/archive.tar/1.0.0/cities_beside_a_directory_entry/expected.json +0 -0
  139. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/archive.tar/1.1.0/cities_beside_a_directory_entry/cities.tar +0 -0
  140. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/archive.tar/1.1.0/cities_beside_a_directory_entry/expected.json +0 -0
  141. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/archive.zip/1.0.0/cities_beside_a_second_member/cities.zip +0 -0
  142. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/archive.zip/1.0.0/cities_beside_a_second_member/expected.json +0 -0
  143. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/archive.zip/1.1.0/dwd_semicolon_station_member/dwd-station.zip +0 -0
  144. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/archive.zip/1.1.0/dwd_semicolon_station_member/expected.json +0 -0
  145. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/archive.zip/1.2.0/dwd_semicolon_station_member/dwd-station.zip +0 -0
  146. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/archive.zip/1.2.0/dwd_semicolon_station_member/expected.json +0 -0
  147. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/delimited_text/1.0.0/an_ordinary_comma_separated_table/cities.csv +0 -0
  148. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/delimited_text/1.0.0/an_ordinary_comma_separated_table/expected.json +0 -0
  149. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/delimited_text/1.0.0/quoted_fields_holding_the_delimiter/cities.tsv +0 -0
  150. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/delimited_text/1.0.0/quoted_fields_holding_the_delimiter/expected.json +0 -0
  151. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/delimited_text/1.1.0/an_hourly_observation_table_served_as_plain_text/expected.json +0 -0
  152. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/delimited_text/1.1.0/an_hourly_observation_table_served_as_plain_text/observations.csv +0 -0
  153. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/json.tabular/1.0.0/nested_hourly_observations/expected.json +0 -0
  154. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/json.tabular/1.0.0/nested_hourly_observations/stations.json +0 -0
  155. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/json.tabular/1.1.0/an_observation_stream_served_as_plain_text/expected.json +0 -0
  156. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/json.tabular/1.1.0/an_observation_stream_served_as_plain_text/observations.ndjson +0 -0
  157. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/an_ordinary_table_beside_a_second_sheet/cities.xlsx +0 -0
  158. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/an_ordinary_table_beside_a_second_sheet/expected.json +0 -0
  159. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/shares_the_workbook_had_already_computed/expected.json +0 -0
  160. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.0.0/shares_the_workbook_had_already_computed/shares.xlsx +0 -0
  161. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.1.0/shares_the_workbook_had_already_computed/expected.json +0 -0
  162. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/spreadsheet.xlsx/1.1.0/shares_the_workbook_had_already_computed/shares.xlsx +0 -0
  163. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/README.md +0 -0
  164. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/gfs_2m_temperature/expected.json +0 -0
  165. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/gfs_2m_temperature/gfs-2m-temperature.grib2 +0 -0
  166. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_2m_temperature/expected.json +0 -0
  167. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_2m_temperature/hrrr-2m-temperature.grib2 +0 -0
  168. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_categorical_rain/expected.json +0 -0
  169. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/weather.grib2/1.0.0/hrrr_categorical_rain/hrrr-categorical-rain.grib2 +0 -0
  170. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/weather.grib2/2.0.0/hrrr_2m_temperature/expected.json +0 -0
  171. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples/weather.grib2/2.0.0/hrrr_2m_temperature/hrrr-2m-temperature.grib2 +0 -0
  172. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/samples.py +0 -0
  173. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/spreadsheet.py +0 -0
  174. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/readers/tabular.py +0 -0
  175. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/repair/__init__.py +0 -0
  176. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/repair/adapters.py +0 -0
  177. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/repair/contracts.py +0 -0
  178. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/repair/coordinator.py +0 -0
  179. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/repair/errors.py +0 -0
  180. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/review.py +0 -0
  181. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/rowset.py +0 -0
  182. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/serving.py +0 -0
  183. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/serving_edge.py +0 -0
  184. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/serving_http.py +0 -0
  185. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/session_probes.py +0 -0
  186. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/signing.py +0 -0
  187. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/source_discovery.py +0 -0
  188. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/__init__.py +0 -0
  189. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/_adapter_steps.py +0 -0
  190. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/adapters.py +0 -0
  191. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/cadence.py +0 -0
  192. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/cadence_emission.py +0 -0
  193. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/cadence_history.py +0 -0
  194. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/__init__.py +0 -0
  195. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/authoring.py +0 -0
  196. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/authoring_policy.py +0 -0
  197. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/bounded_io.py +0 -0
  198. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/channel.py +0 -0
  199. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/channel_client.py +0 -0
  200. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/contracts.py +0 -0
  201. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/coverage.py +0 -0
  202. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/delta.py +0 -0
  203. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/embedding.py +0 -0
  204. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/entry_v2.py +0 -0
  205. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/fill.py +0 -0
  206. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/fill_partitions.py +0 -0
  207. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/fill_staging.py +0 -0
  208. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/gating.py +0 -0
  209. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/generation_receipt.py +0 -0
  210. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/harvest/__init__.py +0 -0
  211. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/harvest/ckan.py +0 -0
  212. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/harvest/datagov_v4.py +0 -0
  213. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/harvest/protocol.py +0 -0
  214. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/harvest/sdmx.py +0 -0
  215. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/harvest/stac.py +0 -0
  216. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/health.py +0 -0
  217. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/hosted_catalog.py +0 -0
  218. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/identity_history.py +0 -0
  219. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/neural.py +0 -0
  220. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/packed_catalog.py +0 -0
  221. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/packed_retrieval.py +0 -0
  222. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/packed_writer.py +0 -0
  223. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/query_trace.py +0 -0
  224. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/recommend.py +0 -0
  225. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/retrieval.py +0 -0
  226. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/retrieval_manifest.py +0 -0
  227. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/rights_decisions.py +0 -0
  228. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/sealed.py +0 -0
  229. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/search.py +0 -0
  230. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/streaming_delta.py +0 -0
  231. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/catalog/update.py +0 -0
  232. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/collections.py +0 -0
  233. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/contracts.py +0 -0
  234. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/deletion.py +0 -0
  235. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/fitness.py +0 -0
  236. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/hosted.py +0 -0
  237. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/integration.py +0 -0
  238. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/range_reader.py +0 -0
  239. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/registry.py +0 -0
  240. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/rights_rule.py +0 -0
  241. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/source_cadence_vectors.v1.json +0 -0
  242. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/sports.py +0 -0
  243. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/stream.py +0 -0
  244. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/stream_connector.py +0 -0
  245. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/sources/stream_recorder.py +0 -0
  246. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/thin/__init__.py +0 -0
  247. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/thin/acquire.py +0 -0
  248. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/thin/acquire_cancel.py +0 -0
  249. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/thin/approvals.py +0 -0
  250. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/thin/commands.py +0 -0
  251. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/thin/download.py +0 -0
  252. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/thin/narrative.py +0 -0
  253. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/thin/parity.py +0 -0
  254. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/thin/propose.py +0 -0
  255. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/thin/runs.py +0 -0
  256. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/thin/session.py +0 -0
  257. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/thin/stream.py +0 -0
  258. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/thin/transport.py +0 -0
  259. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ucum/TABLE-PIN.json +0 -0
  260. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ucum/ucum-subset.v1.json +0 -0
  261. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/unit_flow.py +0 -0
  262. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/units.py +0 -0
  263. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/__init__.py +0 -0
  264. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/approve.py +0 -0
  265. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/author_yaml.py +0 -0
  266. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/cloud_auth.py +0 -0
  267. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/__init__.py +0 -0
  268. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/approve.py +0 -0
  269. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/auth.py +0 -0
  270. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/author.py +0 -0
  271. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/catalog_fill.py +0 -0
  272. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/catalog_harvest.py +0 -0
  273. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/catalog_search.py +0 -0
  274. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/catalog_update.py +0 -0
  275. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/deploy.py +0 -0
  276. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/deploy_dataset.py +0 -0
  277. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/deploy_plan.py +0 -0
  278. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/deploy_status.py +0 -0
  279. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/diff.py +0 -0
  280. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/index.py +0 -0
  281. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/inventory.py +0 -0
  282. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/list_builds.py +0 -0
  283. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/login.py +0 -0
  284. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/peek.py +0 -0
  285. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/plan_check.py +0 -0
  286. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/preflight.py +0 -0
  287. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/record.py +0 -0
  288. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/review_setup.py +0 -0
  289. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/search.py +0 -0
  290. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/show.py +0 -0
  291. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/commands/whoami.py +0 -0
  292. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/credential_native.py +0 -0
  293. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/credential_store.py +0 -0
  294. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/credentials.py +0 -0
  295. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/diffing.py +0 -0
  296. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/headline.py +0 -0
  297. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/hosted_acquisition.py +0 -0
  298. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/hosted_run_status.py +0 -0
  299. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/inventory.py +0 -0
  300. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/local_review.py +0 -0
  301. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/login.py +0 -0
  302. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/path_kind.py +0 -0
  303. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/peek.py +0 -0
  304. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/plain_file.py +0 -0
  305. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/plan_check.py +0 -0
  306. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/preflight.py +0 -0
  307. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/readers.py +0 -0
  308. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/ux/workload.py +0 -0
  309. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/viewer.py +0 -0
  310. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/visual_run/__init__.py +0 -0
  311. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/visual_run/authoring.py +0 -0
  312. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/visual_run/contracts.py +0 -0
  313. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/visual_run/materialize.py +0 -0
  314. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/visual_run/observations.py +0 -0
  315. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/visual_run/query.py +0 -0
  316. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/visual_run/reducer.py +0 -0
  317. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/visual_run/sdk.py +0 -0
  318. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/visual_run/store.py +0 -0
  319. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/visual_run/transport.py +0 -0
  320. {mostlyright_data-0.9.2 → mostlyright_data-0.9.4}/src/mostlyright/data_harness/watch.py +0 -0
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mostlyright-data
3
- Version: 0.9.2
3
+ Version: 0.9.4
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/
7
7
  Requires-Python: <3.14,>=3.13
8
8
  Provides-Extra: build
9
9
  Requires-Dist: hatchling==1.28.0; extra == 'build'
10
- Requires-Dist: uv-build==0.9.26; extra == 'build'
10
+ Requires-Dist: uv-build==0.11.3; extra == 'build'
11
11
  Provides-Extra: dev
12
12
  Requires-Dist: cmarkgfm>=2025.10.22; extra == 'dev'
13
13
  Requires-Dist: croniter==6.2.4; extra == 'dev'
@@ -81,9 +81,9 @@ Description-Content-Type: text/markdown
81
81
 
82
82
  # mostlyright-data
83
83
 
84
- Mostly Right turns public weather, economic, financial, and satellite data into datasets for
85
- analysis and prediction. It keeps source links, timestamps, and check results with each dataset
86
- version.
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.
87
87
 
88
88
  `mostlyright-data` is the command-line client. It starts hosted research and build work, follows
89
89
  run status, and downloads completed Parquet datasets.
@@ -1,8 +1,8 @@
1
1
  # mostlyright-data
2
2
 
3
- Mostly Right turns public weather, economic, financial, and satellite data into datasets for
4
- analysis and prediction. It keeps source links, timestamps, and check results with each dataset
5
- version.
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.
6
6
 
7
7
  `mostlyright-data` is the command-line client. It starts hosted research and build work, follows
8
8
  run status, and downloads completed Parquet datasets.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mostlyright-data"
3
- version = "0.9.2"
3
+ version = "0.9.4"
4
4
  description = "Mostly Right CLI for reproducible, reviewed Parquet datasets"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.13,<3.14"
@@ -69,6 +69,7 @@ mr-data-catalog-job = "mostlyright.data_harness.thin.workers:catalog_job_main"
69
69
  mr-data-crawler = "mostlyright.data_harness.thin.workers:crawler_main"
70
70
  mr-data-crawler-job = "mostlyright.data_harness.thin.workers:crawler_job_main"
71
71
  mr-data-producer = "mostlyright.data_harness.thin.workers:producer_main"
72
+ mr-data-generic-api = "mostlyright.data_harness.thin.workers:generic_api_probe_main"
72
73
  mr-data-verifier = "mostlyright.data_harness.thin.workers:verifier_main"
73
74
  # The legacy Cloud Run service entrypoint remains available for rollback. The Job entrypoint is a
74
75
  # separate executable so an image revision cannot accidentally start the retired HTTP service.
@@ -80,7 +81,7 @@ mr-data-ingestion-job = "mostlyright.data_harness.thin.workers:ingestion_job_mai
80
81
  [project.optional-dependencies]
81
82
  build = [
82
83
  "hatchling==1.28.0",
83
- "uv-build==0.9.26",
84
+ "uv-build==0.11.3",
84
85
  ]
85
86
  # Everything the local execution lane needs, and nothing the hosted lane does. Installing this
86
87
  # extra is what turns the thin client back into today's full product; `mr-data` detects its
@@ -17,8 +17,8 @@ import time
17
17
  from collections.abc import Callable, Iterator, Mapping
18
18
  from dataclasses import dataclass, replace
19
19
  from pathlib import Path, PurePosixPath
20
- from typing import Protocol
21
- from urllib.parse import urljoin, urlsplit
20
+ from typing import TYPE_CHECKING, Protocol
21
+ from urllib.parse import unquote_to_bytes, urljoin, urlsplit
22
22
 
23
23
  try:
24
24
  import fcntl
@@ -44,6 +44,11 @@ from mostlyright.data_harness.formats import (
44
44
  )
45
45
  from mostlyright.data_harness.readers.registry import TOOLBOX, ReaderRegistry
46
46
 
47
+ if TYPE_CHECKING:
48
+ from mostlyright.data_harness.sources.authenticated_https import (
49
+ AuthenticatedApiKeyConfiguration,
50
+ )
51
+
47
52
  MAX_HEADER_COUNT = 128
48
53
  MAX_HEADER_BYTES = 32_768
49
54
  REDIRECT_STATUSES = frozenset({301, 302, 303, 307, 308})
@@ -373,6 +378,276 @@ class _DatagovEchoObject(list[tuple[str, object]]):
373
378
  """JSON object retaining duplicate keys for authorization echo inspection."""
374
379
 
375
380
 
381
+ class AuthenticatedApiKeyAuthorization:
382
+ """One-use API-key authorization with one owned mutable secret buffer.
383
+
384
+ Python's HTTP stack ultimately requires one immutable header string. That runtime-owned
385
+ rendering cannot be zeroed by Python code; this carrier narrows it to the transport call,
386
+ drops every Harness reference immediately afterwards, and zeroes every mutable buffer it owns.
387
+ """
388
+
389
+ __slots__ = ("_closed", "_configuration", "_token", "_validity_check")
390
+
391
+ def __init__(
392
+ self,
393
+ *,
394
+ configuration: AuthenticatedApiKeyConfiguration,
395
+ token: bytes | bytearray | memoryview,
396
+ validity_check: Callable[[], None] | None = None,
397
+ ) -> None:
398
+ # Imported lazily because ``sources.__init__`` exports adapters that depend on this
399
+ # transport module. Runtime import at module load would close that established cycle.
400
+ from mostlyright.data_harness.sources.authenticated_https import (
401
+ AUTHENTICATED_API_KEY_MAX_TOKEN_BYTES,
402
+ AuthenticatedApiKeyConfiguration,
403
+ )
404
+
405
+ if not isinstance(configuration, AuthenticatedApiKeyConfiguration):
406
+ raise AcquisitionSecurityError(
407
+ "AUTHENTICATED_CONFIG",
408
+ "validated authenticated API-key configuration is required",
409
+ )
410
+ if not isinstance(token, (bytes, bytearray, memoryview)):
411
+ raise AcquisitionSecurityError(
412
+ "AUTHENTICATED_TOKEN",
413
+ "token must be bounded printable ASCII bytes",
414
+ )
415
+ borrowed = memoryview(token).cast("B")
416
+ try:
417
+ if (
418
+ not 1 <= len(borrowed) <= AUTHENTICATED_API_KEY_MAX_TOKEN_BYTES
419
+ or borrowed[0] == ord(" ")
420
+ or borrowed[-1] == ord(" ")
421
+ or any(byte < 0x20 or byte > 0x7E for byte in borrowed)
422
+ ):
423
+ raise AcquisitionSecurityError(
424
+ "AUTHENTICATED_TOKEN",
425
+ "token must be 1..4096 printable ASCII bytes without edge whitespace",
426
+ )
427
+ self._token = bytearray(borrowed)
428
+ finally:
429
+ borrowed.release()
430
+ self._configuration = configuration
431
+ self._closed = False
432
+ self._validity_check = validity_check
433
+
434
+ def __repr__(self) -> str:
435
+ return (
436
+ "AuthenticatedApiKeyAuthorization("
437
+ f"configuration_id={self._configuration.configuration_id!r}, token=<redacted>)"
438
+ )
439
+
440
+ __str__ = __repr__
441
+
442
+ def __reduce_ex__(self, _protocol: int) -> object:
443
+ raise TypeError("AuthenticatedApiKeyAuthorization is not serializable")
444
+
445
+ def __copy__(self) -> object:
446
+ raise TypeError("AuthenticatedApiKeyAuthorization is not copyable")
447
+
448
+ def __deepcopy__(self, _memo: object) -> object:
449
+ raise TypeError("AuthenticatedApiKeyAuthorization is not copyable")
450
+
451
+ @property
452
+ def closed(self) -> bool:
453
+ return self._closed
454
+
455
+ def close(self) -> None:
456
+ _zero_mutable_buffer(self._token)
457
+ self._closed = True
458
+
459
+ def validate_target(self, url: str) -> None:
460
+ """Check current authority and destination without rendering a header value."""
461
+
462
+ from mostlyright.data_harness.sources.authenticated_https import (
463
+ parse_authenticated_api_key_query,
464
+ )
465
+ from mostlyright.data_harness.sources.contracts import SourceContractError
466
+
467
+ if self._closed:
468
+ raise AcquisitionSecurityError(
469
+ "AUTHENTICATED_TOKEN",
470
+ "authorization has already been consumed",
471
+ )
472
+ if self._validity_check is not None:
473
+ self._validity_check()
474
+ token = memoryview(self._token).toreadonly()
475
+ try:
476
+ decoded_url = unquote_to_bytes(url)
477
+ except Exception:
478
+ decoded_url = b""
479
+ try:
480
+ if _contains_octets(url.encode("utf-8", errors="ignore"), token) or _contains_octets(
481
+ decoded_url, token
482
+ ):
483
+ raise AcquisitionSecurityError(
484
+ "AUTHENTICATED_SECRET",
485
+ "request target contains credential material",
486
+ )
487
+ finally:
488
+ token.release()
489
+ try:
490
+ parse_authenticated_api_key_query(
491
+ {"url": url, "data_format": "csv", "filename": "source.csv"},
492
+ configuration=self._configuration,
493
+ )
494
+ except SourceContractError as error:
495
+ code = (
496
+ "AUTHENTICATED_SECRET"
497
+ if error.code == "AUTHENTICATED_SECRET"
498
+ else "AUTHENTICATED_ORIGIN"
499
+ )
500
+ raise AcquisitionSecurityError(
501
+ code,
502
+ "request is outside the configured authenticated HTTPS origin",
503
+ ) from None
504
+
505
+ @contextlib.contextmanager
506
+ def render_header(self, url: str) -> Iterator[tuple[str, str]]:
507
+ """Render the unavoidable immutable header only for the surrounding transport call."""
508
+
509
+ self.validate_target(url)
510
+ rendered_octets = bytearray(b"Bearer " if self._configuration.scheme == "bearer" else b"")
511
+ rendered_octets.extend(self._token)
512
+ rendered = rendered_octets.decode("ascii", errors="strict")
513
+ name = "Authorization" if self._configuration.scheme == "bearer" else "X-API-Key"
514
+ try:
515
+ yield name, rendered
516
+ finally:
517
+ rendered = ""
518
+ _zero_mutable_buffer(rendered_octets)
519
+
520
+ def reject_echoed_headers(self, headers: tuple[tuple[str, str], ...]) -> None:
521
+ token = memoryview(self._token).toreadonly()
522
+ try:
523
+ for name, value in headers:
524
+ for text in (name, value):
525
+ candidate = bytearray(text, "utf-8")
526
+ try:
527
+ if _contains_json_equivalent_token(candidate, token):
528
+ raise AcquisitionSecurityError(
529
+ "AUTHENTICATED_SECRET_ECHO",
530
+ "authenticated response echoed credential material "
531
+ "and was not retained",
532
+ )
533
+ finally:
534
+ _zero_mutable_buffer(candidate)
535
+ finally:
536
+ token.release()
537
+
538
+ def reject_echoed_response(self, payload: bytes) -> None:
539
+ token = memoryview(self._token).toreadonly()
540
+ try:
541
+ if _contains_json_equivalent_token(payload, token):
542
+ raise AcquisitionSecurityError(
543
+ "AUTHENTICATED_SECRET_ECHO",
544
+ "authenticated response echoed credential material and was not retained",
545
+ )
546
+ finally:
547
+ token.release()
548
+
549
+
550
+ _JSON_SHORT_ESCAPES = {
551
+ ord('"'): ord('"'),
552
+ ord("/"): ord("/"),
553
+ ord("\\"): ord("\\"),
554
+ ord("b"): 0x08,
555
+ ord("f"): 0x0C,
556
+ ord("n"): 0x0A,
557
+ ord("r"): 0x0D,
558
+ ord("t"): 0x09,
559
+ }
560
+
561
+
562
+ def _zero_mutable_buffer(value: bytearray) -> None:
563
+ for index in range(len(value)):
564
+ value[index] = 0
565
+
566
+
567
+ def _contains_octets(
568
+ value: bytes | bytearray,
569
+ token: bytes | bytearray | memoryview,
570
+ ) -> bool:
571
+ """Linear-time subsequence search without materializing an immutable token copy."""
572
+
573
+ if not token or len(token) > len(value):
574
+ return False
575
+ prefix = [0] * len(token)
576
+ matched = 0
577
+ for index in range(1, len(token)):
578
+ while matched and token[index] != token[matched]:
579
+ matched = prefix[matched - 1]
580
+ if token[index] == token[matched]:
581
+ matched += 1
582
+ prefix[index] = matched
583
+ matched = 0
584
+ for byte in value:
585
+ while matched and byte != token[matched]:
586
+ matched = prefix[matched - 1]
587
+ if byte == token[matched]:
588
+ matched += 1
589
+ if matched == len(token):
590
+ return True
591
+ return False
592
+
593
+
594
+ def _contains_json_equivalent_token(
595
+ value: bytes | bytearray,
596
+ token: bytes | bytearray | memoryview,
597
+ ) -> bool:
598
+ """Find a token through every bounded reversible ASCII JSON-escape layer.
599
+
600
+ Each successful pass strictly shortens the already transport-bounded input. An additional
601
+ JSON layer must at least double the escaping backslashes, so ``bit_length + 1`` passes reach a
602
+ fixed point for every representable nesting depth without an attacker-controlled loop count.
603
+ Unknown and non-ASCII escapes remain literal. If that mathematical bound is ever exhausted
604
+ before a fixed point, fail closed and classify the value as an echo.
605
+ """
606
+
607
+ current: bytes | bytearray = value
608
+ owned: list[bytearray] = []
609
+ maximum_passes = max(1, len(value).bit_length() + 1)
610
+ try:
611
+ for _ in range(maximum_passes):
612
+ if _contains_octets(current, token):
613
+ return True
614
+ normalized = bytearray()
615
+ owned.append(normalized)
616
+ changed = False
617
+ index = 0
618
+ while index < len(current):
619
+ byte = current[index]
620
+ if byte != ord("\\") or index + 1 >= len(current):
621
+ normalized.append(byte)
622
+ index += 1
623
+ continue
624
+ escaped = current[index + 1]
625
+ short = _JSON_SHORT_ESCAPES.get(escaped)
626
+ if short is not None:
627
+ normalized.append(short)
628
+ index += 2
629
+ changed = True
630
+ continue
631
+ if escaped == ord("u") and index + 6 <= len(current):
632
+ digits = current[index + 2 : index + 6]
633
+ if all(digit in b"0123456789abcdefABCDEF" for digit in digits):
634
+ codepoint = int(digits, 16)
635
+ if codepoint <= 0x7F:
636
+ normalized.append(codepoint)
637
+ index += 6
638
+ changed = True
639
+ continue
640
+ normalized.append(byte)
641
+ index += 1
642
+ if not changed:
643
+ return False
644
+ current = normalized
645
+ return True
646
+ finally:
647
+ for buffer in owned:
648
+ _zero_mutable_buffer(buffer)
649
+
650
+
376
651
  def _require_datagov_key_stat(info: os.stat_result) -> None:
377
652
  if (
378
653
  not stat.S_ISREG(info.st_mode)
@@ -675,6 +950,8 @@ class PinnedTransport(Protocol):
675
950
  headers: Mapping[str, str],
676
951
  limits: RetrievalLimits,
677
952
  byte_range: ByteRange | None = None,
953
+ method: str = "GET",
954
+ body: bytes | None = None,
678
955
  ) -> TransportResponse:
679
956
  """Connect only to approved_ip while verifying target.hostname in TLS.
680
957
 
@@ -791,6 +1068,11 @@ class RetrievalHop:
791
1068
  etag: str | None = None
792
1069
  last_modified: str | None = None
793
1070
  peer_attempts: tuple[PeerAttempt, ...] = ()
1071
+ # The ordinary transport digest intentionally remains stable for every existing public
1072
+ # connector. Authenticated verification additionally needs the complete resolver-approved
1073
+ # set to rederive ``resolution_digest`` without either repeating the request or receiving the
1074
+ # credential, so the pinned retriever retains it alongside (but not inside) ``to_dict``.
1075
+ approved_ips: tuple[str, ...] = ()
794
1076
 
795
1077
  def to_dict(self) -> dict[str, object]:
796
1078
  # Both range keys are always present, ``None`` when the hop ordered no slice, so a hop
@@ -811,6 +1093,23 @@ class RetrievalHop:
811
1093
  "peer_attempts": [attempt.to_dict() for attempt in self.peer_attempts],
812
1094
  }
813
1095
 
1096
+ def authenticated_attestation_dict(self) -> dict[str, object]:
1097
+ """Return the complete secret-free facts proved by the pinned HTTPS boundary."""
1098
+
1099
+ if not self.approved_ips:
1100
+ raise AcquisitionSecurityError(
1101
+ "TRANSPORT_EVIDENCE",
1102
+ "authenticated hop omitted its resolver-approved address set",
1103
+ )
1104
+ return {
1105
+ **self.to_dict(),
1106
+ "approved_ips": list(self.approved_ips),
1107
+ # A hop is constructed only after both checks pass. Retaining the predicates makes
1108
+ # that invariant explicit and independently parseable in the verifier evidence.
1109
+ "tls_verified": True,
1110
+ "hostname_verified": True,
1111
+ }
1112
+
814
1113
 
815
1114
  @dataclass(frozen=True)
816
1115
  class ProbeTransport:
@@ -884,6 +1183,10 @@ class RetrievedBytes:
884
1183
  transport_evidence_digest: str
885
1184
  complete_size_bytes: int | None = None
886
1185
  rate_observation: DatagovRateObservation | None = None
1186
+ # Link pagination needs the terminal headers while it is in flight. They deliberately
1187
+ # remain outside ``RetrievalHop`` and its durable digest: publisher-controlled header text
1188
+ # is not receipt evidence and may never be persisted by the adapter.
1189
+ response_headers: tuple[tuple[str, str], ...] = ()
887
1190
 
888
1191
  @property
889
1192
  def total_response_body_size_bytes(self) -> int:
@@ -1189,6 +1492,67 @@ class PinnedHttpsRetriever:
1189
1492
  datagov_response_observed=on_response_observed,
1190
1493
  )
1191
1494
 
1495
+ def retrieve_authenticated(
1496
+ self,
1497
+ url: str,
1498
+ authorization: AuthenticatedApiKeyAuthorization,
1499
+ ) -> RetrievedBytes:
1500
+ """Perform one exact-origin CSV GET and consume ``authorization`` on every outcome."""
1501
+
1502
+ if not isinstance(authorization, AuthenticatedApiKeyAuthorization):
1503
+ raise AcquisitionSecurityError(
1504
+ "AUTHENTICATED_TOKEN",
1505
+ "strict authenticated API-key authorization is required",
1506
+ )
1507
+ try:
1508
+ authorization.validate_target(url)
1509
+ try:
1510
+ retrieved = self._fetch(
1511
+ url,
1512
+ byte_range=None,
1513
+ presence_probe=False,
1514
+ datagov_authorization=None,
1515
+ authenticated_authorization=authorization,
1516
+ )
1517
+ except AcquisitionSecurityError as error:
1518
+ if error.code.startswith("AUTHENTICATED_"):
1519
+ raise
1520
+ raise AcquisitionSecurityError(
1521
+ "AUTHENTICATED_RETRIEVAL",
1522
+ "authenticated retrieval failed before content could be retained",
1523
+ ) from None
1524
+ except Exception:
1525
+ raise AcquisitionSecurityError(
1526
+ "AUTHENTICATED_TRANSPORT",
1527
+ "authenticated transport failed before content could be retained",
1528
+ ) from None
1529
+ if retrieved.media_type not in DIRECT_FETCH_MEDIA_TYPES["csv"]:
1530
+ raise AcquisitionSecurityError(
1531
+ "AUTHENTICATED_MEDIA_TYPE",
1532
+ "authenticated response is not an admitted CSV media type",
1533
+ )
1534
+ return retrieved
1535
+ finally:
1536
+ authorization.close()
1537
+
1538
+ def retrieve_frozen_authenticated_request(
1539
+ self, url: str, *, method: str, headers: Mapping[str, str], body: bytes | None
1540
+ ) -> RetrievedBytes:
1541
+ """Run a prevalidated generic adapter request through the pinned HTTPS machinery."""
1542
+ if method not in {"GET", "POST"} or (method == "GET" and body is not None):
1543
+ raise AcquisitionSecurityError(
1544
+ "AUTHENTICATED_REQUEST", "frozen request method is invalid"
1545
+ )
1546
+ return self._fetch(
1547
+ url,
1548
+ byte_range=None,
1549
+ presence_probe=False,
1550
+ datagov_authorization=None,
1551
+ frozen_headers=headers,
1552
+ frozen_method=method,
1553
+ frozen_body=body,
1554
+ )
1555
+
1192
1556
  def probe_presence(self, url: str) -> bool:
1193
1557
  """Ask one address whether it is published, keep nothing, and answer yes or no.
1194
1558
 
@@ -1246,9 +1610,13 @@ class PinnedHttpsRetriever:
1246
1610
  byte_range: ByteRange | None,
1247
1611
  presence_probe: bool,
1248
1612
  datagov_authorization: DatagovV4Authorization | None,
1613
+ authenticated_authorization: AuthenticatedApiKeyAuthorization | None = None,
1249
1614
  datagov_response_observed: (
1250
1615
  Callable[[int, int, DatagovRateObservation | None], None] | None
1251
1616
  ) = None,
1617
+ frozen_headers: Mapping[str, str] | None = None,
1618
+ frozen_method: str = "GET",
1619
+ frozen_body: bytes | None = None,
1252
1620
  ) -> RetrievedBytes:
1253
1621
  started = float(self._clock())
1254
1622
  current_url = url
@@ -1256,7 +1624,11 @@ class PinnedHttpsRetriever:
1256
1624
  aggregate_response_bytes = 0
1257
1625
  requests = 0
1258
1626
  deadline = started + self._limits.total_timeout_seconds
1259
- redirect_budget = 0 if datagov_authorization is not None else self._limits.max_redirects
1627
+ redirect_budget = (
1628
+ 0
1629
+ if datagov_authorization is not None or authenticated_authorization is not None
1630
+ else self._limits.max_redirects
1631
+ )
1260
1632
  for redirect_count in range(redirect_budget + 1):
1261
1633
  self._check_total_timeout(started)
1262
1634
  target = validate_public_https_url(
@@ -1268,12 +1640,22 @@ class PinnedHttpsRetriever:
1268
1640
  # A presence probe asks for anything, because it admits anything: sending the
1269
1641
  # acquisition allowlist would invite a 406 for a run that is published and
1270
1642
  # fine, which is the same false failure the admission exemption removes.
1271
- "Accept": "*/*" if presence_probe else _accept_header(self._limits),
1643
+ "Accept": (
1644
+ "*/*"
1645
+ if presence_probe
1646
+ else (
1647
+ ", ".join(sorted(DIRECT_FETCH_MEDIA_TYPES["csv"]))
1648
+ if authenticated_authorization is not None
1649
+ else _accept_header(self._limits)
1650
+ )
1651
+ ),
1272
1652
  "Accept-Encoding": "identity",
1273
1653
  "Connection": "close",
1274
1654
  "Host": urlsplit(target.normalized_url).netloc,
1275
1655
  "User-Agent": self._limits.user_agent,
1276
1656
  }
1657
+ if frozen_headers is not None:
1658
+ headers.update(frozen_headers)
1277
1659
  if datagov_authorization is not None:
1278
1660
  name, value = datagov_authorization.header_for(target.normalized_url)
1279
1661
  headers[name] = value
@@ -1296,7 +1678,18 @@ class PinnedHttpsRetriever:
1296
1678
  deadline,
1297
1679
  remaining_aggregate_bytes=remaining_aggregate_bytes,
1298
1680
  )
1681
+ if authenticated_authorization is not None:
1682
+ attempt_limits = replace(
1683
+ attempt_limits,
1684
+ max_redirects=0,
1685
+ max_requests=1,
1686
+ )
1299
1687
  except AcquisitionSecurityError as exc:
1688
+ if authenticated_authorization is not None:
1689
+ raise AcquisitionSecurityError(
1690
+ "AUTHENTICATED_TRANSPORT",
1691
+ "authenticated transport failed before content could be retained",
1692
+ ) from None
1300
1693
  raise PeerAttemptError(
1301
1694
  exc.code,
1302
1695
  exc.detail,
@@ -1307,14 +1700,47 @@ class PinnedHttpsRetriever:
1307
1700
  # One budget, one clock: every peer and limiter wait is bounded by the
1308
1701
  # same absolute instant. A fallback never starts a second DNS epoch.
1309
1702
  with self._limiter.acquire(target.hostname, deadline=deadline):
1310
- response = self._transport.request(
1311
- target,
1312
- approved_ip=approved_ip,
1313
- headers=headers,
1314
- limits=attempt_limits,
1315
- byte_range=byte_range,
1316
- )
1703
+ request_headers = headers
1704
+ if authenticated_authorization is None:
1705
+ request_kwargs = {"byte_range": byte_range}
1706
+ if (
1707
+ frozen_method != "GET"
1708
+ or frozen_body is not None
1709
+ or frozen_headers is not None
1710
+ ):
1711
+ request_kwargs.update(
1712
+ {"method": frozen_method, "body": frozen_body}
1713
+ )
1714
+ response = self._transport.request(
1715
+ target,
1716
+ approved_ip=approved_ip,
1717
+ headers=headers,
1718
+ limits=attempt_limits,
1719
+ **request_kwargs,
1720
+ )
1721
+ else:
1722
+ request_headers = dict(headers)
1723
+ try:
1724
+ with authenticated_authorization.render_header(
1725
+ target.normalized_url
1726
+ ) as (name, value):
1727
+ request_headers[name] = value
1728
+ response = self._transport.request(
1729
+ target,
1730
+ approved_ip=approved_ip,
1731
+ headers=request_headers,
1732
+ limits=attempt_limits,
1733
+ byte_range=byte_range,
1734
+ )
1735
+ finally:
1736
+ request_headers.clear()
1737
+ name = value = ""
1317
1738
  except AcquisitionSecurityError as exc:
1739
+ if authenticated_authorization is not None:
1740
+ raise AcquisitionSecurityError(
1741
+ "AUTHENTICATED_TRANSPORT",
1742
+ "authenticated transport failed before content could be retained",
1743
+ ) from None
1318
1744
  if exc.code == "TRANSPORT_FAILURE" and not isinstance(
1319
1745
  exc, TransportFailureError
1320
1746
  ):
@@ -1370,6 +1796,13 @@ class PinnedHttpsRetriever:
1370
1796
  raise PeerAttemptError(
1371
1797
  failure_code, detail, tuple(peer_attempts), hops=tuple(hops)
1372
1798
  ) from None
1799
+ except Exception:
1800
+ if authenticated_authorization is not None:
1801
+ raise AcquisitionSecurityError(
1802
+ "AUTHENTICATED_TRANSPORT",
1803
+ "authenticated transport failed before content could be retained",
1804
+ ) from None
1805
+ raise
1373
1806
  peer_attempts.append(
1374
1807
  PeerAttempt(
1375
1808
  approved_ip=approved_ip,
@@ -1447,6 +1880,15 @@ class PinnedHttpsRetriever:
1447
1880
  aggregate_response_bytes,
1448
1881
  datagov_rate_observation,
1449
1882
  )
1883
+ elif authenticated_authorization is not None:
1884
+ authenticated_authorization.reject_echoed_headers(normalized_headers)
1885
+ if response.status in REDIRECT_STATUSES:
1886
+ raise AcquisitionSecurityError(
1887
+ "AUTHENTICATED_REDIRECT",
1888
+ "authenticated responses never follow redirects",
1889
+ )
1890
+ authenticated_authorization.reject_echoed_response(response.body)
1891
+ datagov_rate_observation = None
1450
1892
  else:
1451
1893
  datagov_rate_observation = None
1452
1894
  if len(response.body) > attempt_limits.max_response_bytes:
@@ -1520,6 +1962,7 @@ class PinnedHttpsRetriever:
1520
1962
  etag=self._response_header(response, "etag", peer_attempts, hops),
1521
1963
  last_modified=self._response_header(response, "last-modified", peer_attempts, hops),
1522
1964
  peer_attempts=tuple(peer_attempts),
1965
+ approved_ips=target.approved_ips,
1523
1966
  )
1524
1967
  hops.append(hop)
1525
1968
  # The delivery check. A slice is delivered only when the server answered 206,
@@ -1672,6 +2115,7 @@ class PinnedHttpsRetriever:
1672
2115
  transport_evidence_digest=evidence_digest,
1673
2116
  complete_size_bytes=complete_size_bytes,
1674
2117
  rate_observation=datagov_rate_observation,
2118
+ response_headers=tuple(normalized_headers),
1675
2119
  )
1676
2120
  raise AcquisitionSecurityError("REDIRECT_LIMIT", "redirect loop did not terminate")
1677
2121
 
@@ -1805,6 +2249,8 @@ class StdlibPinnedTransport:
1805
2249
  headers: Mapping[str, str],
1806
2250
  limits: RetrievalLimits,
1807
2251
  byte_range: ByteRange | None = None,
2252
+ method: str = "GET",
2253
+ body: bytes | None = None,
1808
2254
  ) -> TransportResponse:
1809
2255
  outgoing = dict(headers)
1810
2256
  if byte_range is not None:
@@ -1819,7 +2265,7 @@ class StdlibPinnedTransport:
1819
2265
  )
1820
2266
  total = 0
1821
2267
  try:
1822
- connection.request("GET", target.request_target, headers=outgoing)
2268
+ connection.request(method, target.request_target, body=body, headers=outgoing)
1823
2269
  if connection.sock is not None:
1824
2270
  connection.sock.settimeout(
1825
2271
  _remaining_socket_timeout(