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,1701 @@
1
+ """Authoring time: compute the four embedding layers once and seal them.
2
+
3
+ This module is the only place in the catalog where text becomes a vector. It runs when a catalog
4
+ is built, never when one is queried, and the query-side load path (``sealed.py``) computes
5
+ nothing at all. That split is the whole of "models at authoring time only": the runtime path can
6
+ read sealed integers and verify digests, and there is no code on it that could do anything else.
7
+
8
+ The layer projections below are fixed and documented because they are silently load-bearing --
9
+ changing how an entry is rendered into text changes every vector sealed from it, and a catalog
10
+ whose vectors were computed under an older projection would rank differently while looking
11
+ identical. Treat a projection change as a re-seal of the whole catalog.
12
+
13
+ Nothing here reads a tenant's data. ``declared_columns`` and ``declared_vocabulary`` hold
14
+ published names only, which is what makes the ``columns`` layer a fact about a public source
15
+ rather than a summary of somebody's rows.
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import os
21
+ import re
22
+ import secrets
23
+ import stat
24
+ import struct
25
+ import tempfile
26
+ from collections.abc import Iterable, Sequence
27
+ from dataclasses import dataclass, replace
28
+ from pathlib import Path
29
+
30
+ from mostlyright.data_harness.acquisition.url_policy import EgressPolicy
31
+ from mostlyright.data_harness.canonical import (
32
+ canonical_json_bytes,
33
+ parse_canonical_json,
34
+ sha256_bytes,
35
+ )
36
+ from mostlyright.data_harness.sources.catalog.admission import (
37
+ admit_public_fact_bytes,
38
+ require_public_source_evidence,
39
+ )
40
+ from mostlyright.data_harness.sources.catalog.contracts import (
41
+ CATALOG_INDEX_CONTRACT_VERSION,
42
+ EMBEDDING_LAYERS,
43
+ CatalogEntry,
44
+ LayerVectorReference,
45
+ SourceQuirk,
46
+ catalog_entry_from_dict,
47
+ )
48
+ from mostlyright.data_harness.sources.catalog.embedding import (
49
+ BackendDescriptor,
50
+ EmbeddingBackend,
51
+ )
52
+ from mostlyright.data_harness.sources.catalog.harvest.protocol import HarvestedRecord
53
+ from mostlyright.data_harness.sources.catalog.retrieval_manifest import (
54
+ LEXICAL_REPRESENTATION,
55
+ MAX_REPRESENTATION_DESCRIPTOR_BYTES,
56
+ NEURAL_REPRESENTATION,
57
+ REPRESENTATION_DESCRIPTOR_FILENAME,
58
+ RETRIEVAL_MANIFEST_FILENAME,
59
+ LoadedRetrievalCatalog,
60
+ LoadedRetrievalRepresentation,
61
+ RepresentationMember,
62
+ RetrievalManifestV2,
63
+ RetrievalRepresentation,
64
+ backend_descriptor_bytes,
65
+ backend_descriptor_sha256,
66
+ load_retrieval_catalog,
67
+ )
68
+ from mostlyright.data_harness.sources.contracts import (
69
+ RightsEvidence,
70
+ SourceContractError,
71
+ SourceObservation,
72
+ )
73
+
74
+ CATALOG_FILENAME = "catalog.json"
75
+ VECTORS_DIRNAME = "vectors"
76
+ VECTOR_SUFFIX = ".vec"
77
+ MAX_CATALOG_MANIFEST_BYTES = 16 * 1024 * 1024
78
+
79
+ _ENTRY_ID = re.compile(r"^[a-z][a-z0-9]*(?:[._-][a-z0-9]+)*$")
80
+
81
+
82
+ @dataclass(frozen=True)
83
+ class CatalogSealResult:
84
+ """Exact result of one incremental durable v1 catalog seal."""
85
+
86
+ entries: tuple[CatalogEntry, ...]
87
+ manifest_sha256: str
88
+ reused_vector_sha256s: tuple[str, ...]
89
+ created_vector_sha256s: tuple[str, ...]
90
+ encoder_invocations: int
91
+
92
+
93
+ @dataclass(frozen=True)
94
+ class RetrievalSealResult:
95
+ """Result of one atomic v2 outer-manifest publication."""
96
+
97
+ manifest: RetrievalManifestV2
98
+ manifest_sha256: str
99
+ lexical_entries: tuple[CatalogEntry, ...]
100
+ neural_entries: tuple[CatalogEntry, ...] | None
101
+ lexical_reused_vector_sha256s: tuple[str, ...]
102
+ lexical_created_vector_sha256s: tuple[str, ...]
103
+ neural_reused_vector_sha256s: tuple[str, ...]
104
+ neural_created_vector_sha256s: tuple[str, ...]
105
+ lexical_encoder_invocations: int
106
+ neural_encoder_invocations: int
107
+
108
+
109
+ def layer_text(entry: CatalogEntry, layer: str) -> str:
110
+ """Render one entry onto one retrieval layer, deterministically.
111
+
112
+ ``description`` is what the source calls itself. ``metadata`` is the facts a searcher would
113
+ phrase a filter with. ``columns`` is the published names a searcher would name a variable
114
+ with. ``profiles`` is the shape and cadence a searcher would sanity-check coverage against.
115
+ """
116
+
117
+ if not isinstance(entry, CatalogEntry):
118
+ raise SourceContractError("TYPE", "entry", "must be a CatalogEntry")
119
+ if layer not in EMBEDDING_LAYERS:
120
+ raise SourceContractError(
121
+ "ENUM",
122
+ "layer",
123
+ f"must be one of {list(EMBEDDING_LAYERS)}",
124
+ )
125
+ if layer == "description":
126
+ return f"{entry.title}\n{entry.description}"
127
+ if layer == "metadata":
128
+ return " ".join(
129
+ (
130
+ entry.publisher,
131
+ *entry.spatial_scope,
132
+ *entry.data_formats,
133
+ entry.access_kind,
134
+ entry.rights.status,
135
+ entry.rights.lawful_basis,
136
+ )
137
+ )
138
+ if layer == "columns":
139
+ parts: list[str] = [*entry.declared_columns, *entry.declared_vocabulary]
140
+ for quirk in entry.quirks:
141
+ parts.append(quirk.code)
142
+ parts.append(quirk.detail)
143
+ return " ".join(parts)
144
+ observation = entry.observation
145
+ row_count = "unknown" if entry.declared_row_count is None else str(entry.declared_row_count)
146
+ return " ".join(
147
+ (
148
+ observation.historical_start,
149
+ observation.historical_end,
150
+ observation.live_status,
151
+ f"update_frequency_seconds {observation.update_frequency_seconds}",
152
+ f"publication_delay_seconds {observation.publication_delay_seconds}",
153
+ *entry.data_formats,
154
+ f"rows {row_count}",
155
+ )
156
+ )
157
+
158
+
159
+ def seal_catalog(
160
+ entries: Iterable[CatalogEntry],
161
+ *,
162
+ backend: EmbeddingBackend,
163
+ directory: Path,
164
+ egress_policy: EgressPolicy,
165
+ schema_version: str = CATALOG_INDEX_CONTRACT_VERSION,
166
+ ) -> tuple[CatalogEntry, ...]:
167
+ """Encode every layer of every entry, write the sealed catalog, and return the sealed entries.
168
+
169
+ This function is the only writer of the shared cross-tenant artifact, so the public-source
170
+ check runs here too and ``egress_policy`` is required rather than optional. Composition
171
+ (:func:`compose_catalog_entry`) checks the harvest seam, but an entry can also reach a catalog
172
+ by being authored or reconstructed from a file, and a check that only one of two doors runs is
173
+ the "enforced by review" pattern the tenancy rule rejects. Every entry is checked before any
174
+ byte is written, so a refused entry cannot leave a half-written tree behind.
175
+
176
+ Vector files are content-addressed, so two entries whose layer text is identical share one
177
+ file. The index is sorted by ``(entry_id, entry_version)`` before serialisation, which is what
178
+ makes a re-seal byte-identical rather than merely equivalent.
179
+ """
180
+
181
+ supplied = tuple(entries)
182
+ canonical_entries: list[CatalogEntry] = []
183
+ for index, entry in enumerate(supplied):
184
+ # Exact type at the boundary, followed by one immutable snapshot of the whole graph. A
185
+ # nested contract may itself be a subclass with a stateful to_dict; reading the original
186
+ # graph again would let admission inspect one projection and sealing serialize another.
187
+ if type(entry) is not CatalogEntry:
188
+ raise SourceContractError("TYPE", f"entries[{index}]", "must be a CatalogEntry")
189
+ captured_bytes = canonical_json_bytes(entry.to_dict())
190
+ admit_public_fact_bytes(captured_bytes)
191
+ canonical_entry = catalog_entry_from_dict(parse_canonical_json(captured_bytes))
192
+ if canonical_json_bytes(canonical_entry.to_dict()) != captured_bytes:
193
+ raise SourceContractError(
194
+ "CATALOG_ENTRY_PROJECTION",
195
+ f"entries[{index}]",
196
+ "the entry's captured projection cannot be rebuilt byte-for-byte as an exact "
197
+ "CatalogEntry; admission and sealing must inspect the same exact facts",
198
+ )
199
+ if canonical_entry.vectors:
200
+ raise SourceContractError(
201
+ "CATALOG_ALREADY_SEALED",
202
+ f"entries[{index}].vectors",
203
+ f"{canonical_entry.coordinate} already carries sealed vectors; re-sealing must "
204
+ "be explicit so a stale vector cannot outlive a fact change",
205
+ )
206
+ canonical_entries.append(canonical_entry)
207
+ materialized: Sequence[CatalogEntry] = tuple(canonical_entries)
208
+ if not isinstance(directory, Path):
209
+ raise SourceContractError("TYPE", "directory", "must be a Path")
210
+ for entry in materialized:
211
+ require_public_source_evidence(entry, egress_policy=egress_policy)
212
+
213
+ descriptor = backend.descriptor
214
+ vector_directory = directory / VECTORS_DIRNAME
215
+ vector_directory.mkdir(parents=True, exist_ok=True)
216
+
217
+ sealed: list[CatalogEntry] = []
218
+ for entry in materialized:
219
+ references: list[LayerVectorReference] = []
220
+ # Taken once, before any vector is written. `facts_digest` excludes `vectors`, so this is
221
+ # the same value the sealed entry will carry and the same one `SealedEmbeddingIndex.load`
222
+ # will re-derive -- which is what makes the binding checkable without re-encoding anything.
223
+ facts_digest = entry.facts_digest
224
+ for layer in EMBEDDING_LAYERS:
225
+ vector = backend.encode(layer_text(entry, layer))
226
+ if len(vector) != descriptor.dimensions:
227
+ raise SourceContractError(
228
+ "EMBEDDING_DIMENSIONS",
229
+ f"{entry.coordinate}.{layer}",
230
+ f"backend returned {len(vector)} values, expected {descriptor.dimensions}",
231
+ )
232
+ packed = struct.pack(f">{descriptor.dimensions}i", *vector)
233
+ digest = sha256_bytes(packed)
234
+ _write_vector(vector_directory / f"{digest}{VECTOR_SUFFIX}", packed)
235
+ references.append(
236
+ LayerVectorReference(
237
+ layer=layer,
238
+ backend_id=descriptor.backend_id,
239
+ backend_version=descriptor.backend_version,
240
+ dimensions=descriptor.dimensions,
241
+ quantization=descriptor.quantization,
242
+ vector_sha256=digest,
243
+ entry_facts_digest=facts_digest,
244
+ )
245
+ )
246
+ sealed.append(replace(entry, vectors=tuple(references)))
247
+
248
+ ordered = tuple(sorted(sealed, key=lambda item: (item.entry_id, item.entry_version)))
249
+ index_bytes = canonical_json_bytes(
250
+ {
251
+ "schema_version": schema_version,
252
+ "entries": [item.to_dict() for item in ordered],
253
+ }
254
+ )
255
+ _atomic_write(directory / CATALOG_FILENAME, index_bytes)
256
+ return ordered
257
+
258
+
259
+ def seal_retrieval_catalog(
260
+ entries: Iterable[CatalogEntry],
261
+ *,
262
+ lexical_backend: EmbeddingBackend,
263
+ neural_backend: EmbeddingBackend | None,
264
+ directory: Path,
265
+ egress_policy: EgressPolicy,
266
+ fallback_reason: str | None = None,
267
+ expected_existing_manifest_sha256: str | None = None,
268
+ ) -> RetrievalSealResult:
269
+ """Seal independent v1 representations and publish one explicit v2 head.
270
+
271
+ Both representations are derived from one captured tuple of canonical facts. Their immutable
272
+ generations are complete and read back before ``retrieval.json`` is replaced, making the
273
+ outer replacement the sole public linearization point.
274
+ """
275
+
276
+ supplied = tuple(entries)
277
+ captured = tuple(
278
+ _capture_entry(entry, index=index, sealed=False) for index, entry in enumerate(supplied)
279
+ )
280
+ ordered = tuple(sorted(captured, key=_entry_key))
281
+ if len({entry.entry_id for entry in ordered}) != len(ordered):
282
+ raise SourceContractError(
283
+ "DUPLICATE", "retrieval.entries", "a retrieval catalog has one entry per source"
284
+ )
285
+ if neural_backend is None and fallback_reason is None:
286
+ fallback_reason = "NEURAL_NOT_REQUESTED"
287
+ if neural_backend is not None and fallback_reason is not None:
288
+ raise SourceContractError(
289
+ "RETRIEVAL_FALLBACK",
290
+ "fallback_reason",
291
+ "a hybrid seal cannot also claim lexical-only fallback",
292
+ )
293
+ for entry in ordered:
294
+ require_public_source_evidence(entry, egress_policy=egress_policy)
295
+
296
+ shared_facts_sha256 = _shared_facts_sha256(ordered)
297
+ trusted_resume = _load_trusted_resume_catalog(
298
+ directory=directory,
299
+ expected_manifest_sha256=expected_existing_manifest_sha256,
300
+ expected_facts=ordered,
301
+ lexical_backend=lexical_backend,
302
+ neural_backend=neural_backend,
303
+ fallback_reason=fallback_reason,
304
+ )
305
+ if trusted_resume is not None:
306
+ return _result_from_trusted_resume(trusted_resume)
307
+ lexical_generation = _representation_generation(shared_facts_sha256, lexical_backend.descriptor)
308
+ lexical_directory = directory / LEXICAL_REPRESENTATION / lexical_generation
309
+ lexical_result = _seal_representation_generation(
310
+ reused_entries=(),
311
+ fresh_entries=ordered,
312
+ backend=lexical_backend,
313
+ directory=lexical_directory,
314
+ predecessor_directory=None,
315
+ predecessor_manifest_sha256=None,
316
+ egress_policy=egress_policy,
317
+ )
318
+ lexical_representation = _representation_from_seal(
319
+ root=directory,
320
+ name=LEXICAL_REPRESENTATION,
321
+ generation=lexical_generation,
322
+ descriptor=lexical_backend.descriptor,
323
+ result=lexical_result,
324
+ )
325
+
326
+ neural_result: CatalogSealResult | None = None
327
+ representations = [lexical_representation]
328
+ if neural_backend is not None:
329
+ neural_generation = _representation_generation(
330
+ shared_facts_sha256, neural_backend.descriptor
331
+ )
332
+ neural_directory = directory / NEURAL_REPRESENTATION / neural_generation
333
+ neural_result = _seal_representation_generation(
334
+ reused_entries=(),
335
+ fresh_entries=ordered,
336
+ backend=neural_backend,
337
+ directory=neural_directory,
338
+ predecessor_directory=None,
339
+ predecessor_manifest_sha256=None,
340
+ egress_policy=egress_policy,
341
+ )
342
+ representations.append(
343
+ _representation_from_seal(
344
+ root=directory,
345
+ name=NEURAL_REPRESENTATION,
346
+ generation=neural_generation,
347
+ descriptor=neural_backend.descriptor,
348
+ result=neural_result,
349
+ )
350
+ )
351
+
352
+ manifest = RetrievalManifestV2(
353
+ shared_facts_sha256=shared_facts_sha256,
354
+ representations=tuple(representations),
355
+ fallback_reason=fallback_reason,
356
+ )
357
+ # Reparse before publication so a writer bug cannot create a public envelope the reader would
358
+ # reject. All referenced members have already been durably installed and read back.
359
+ if RetrievalManifestV2.from_bytes(manifest.canonical_bytes) != manifest:
360
+ raise SourceContractError(
361
+ "RETRIEVAL_MANIFEST_READBACK", RETRIEVAL_MANIFEST_FILENAME, "reparse differs"
362
+ )
363
+ _publish_retrieval_manifest(directory, manifest.canonical_bytes)
364
+ return RetrievalSealResult(
365
+ manifest=manifest,
366
+ manifest_sha256=manifest.digest,
367
+ lexical_entries=lexical_result.entries,
368
+ neural_entries=None if neural_result is None else neural_result.entries,
369
+ lexical_reused_vector_sha256s=lexical_result.reused_vector_sha256s,
370
+ lexical_created_vector_sha256s=lexical_result.created_vector_sha256s,
371
+ neural_reused_vector_sha256s=()
372
+ if neural_result is None
373
+ else neural_result.reused_vector_sha256s,
374
+ neural_created_vector_sha256s=()
375
+ if neural_result is None
376
+ else neural_result.created_vector_sha256s,
377
+ lexical_encoder_invocations=lexical_result.encoder_invocations,
378
+ neural_encoder_invocations=0
379
+ if neural_result is None
380
+ else neural_result.encoder_invocations,
381
+ )
382
+
383
+
384
+ def seal_retrieval_catalog_successor(
385
+ *,
386
+ lexical_reused_entries: tuple[CatalogEntry, ...],
387
+ fresh_entries: tuple[CatalogEntry, ...],
388
+ lexical_backend: EmbeddingBackend,
389
+ neural_reused_entries: tuple[CatalogEntry, ...],
390
+ neural_backend: EmbeddingBackend | None,
391
+ directory: Path,
392
+ predecessor_retrieval_directory: Path | None,
393
+ predecessor_retrieval_manifest_sha256: str | None,
394
+ egress_policy: EgressPolicy,
395
+ fallback_reason: str | None = None,
396
+ expected_existing_manifest_sha256: str | None = None,
397
+ ) -> RetrievalSealResult:
398
+ """Seal a v2 successor while preserving exact predecessor members for unchanged facts."""
399
+
400
+ if neural_backend is None:
401
+ if neural_reused_entries:
402
+ raise SourceContractError(
403
+ "RETRIEVAL_NEURAL_REUSE",
404
+ "retrieval.neural_reused_entries",
405
+ "neural reuse requires an explicit exact backend",
406
+ )
407
+ if fallback_reason is None:
408
+ fallback_reason = "NEURAL_NOT_REQUESTED"
409
+ elif fallback_reason is not None:
410
+ raise SourceContractError(
411
+ "RETRIEVAL_FALLBACK",
412
+ "fallback_reason",
413
+ "a hybrid successor cannot also claim lexical-only fallback",
414
+ )
415
+
416
+ lexical_facts = tuple(sorted((*lexical_reused_entries, *fresh_entries), key=_entry_key))
417
+ neural_reused_ids = {entry.entry_id for entry in neural_reused_entries}
418
+ neural_fresh = tuple(
419
+ replace(entry, vectors=())
420
+ for entry in lexical_facts
421
+ if entry.entry_id not in neural_reused_ids
422
+ )
423
+ if len(neural_reused_ids) != len(neural_reused_entries):
424
+ raise SourceContractError(
425
+ "DUPLICATE", "retrieval.neural_reused_entries", "entry ids must be unique"
426
+ )
427
+ lexical_reused_facts = tuple(
428
+ (entry.coordinate, entry.facts_digest) for entry in lexical_reused_entries
429
+ )
430
+ neural_reused_facts = tuple(
431
+ (entry.coordinate, entry.facts_digest) for entry in neural_reused_entries
432
+ )
433
+ if neural_reused_facts and neural_reused_facts != lexical_reused_facts:
434
+ raise SourceContractError(
435
+ "RETRIEVAL_SHARED_FACTS",
436
+ "retrieval.neural_reused_entries",
437
+ "neural reused entries must exactly match lexical reuse order and facts",
438
+ )
439
+ for entry in lexical_facts:
440
+ require_public_source_evidence(entry, egress_policy=egress_policy)
441
+ trusted_predecessor = None
442
+ if lexical_reused_entries or neural_reused_entries:
443
+ trusted_predecessor = _capture_trusted_retrieval_predecessor(
444
+ predecessor_directory=predecessor_retrieval_directory,
445
+ predecessor_manifest_sha256=predecessor_retrieval_manifest_sha256,
446
+ lexical_reused_entries=lexical_reused_entries,
447
+ neural_reused_entries=neural_reused_entries,
448
+ lexical_backend=lexical_backend,
449
+ neural_backend=neural_backend,
450
+ )
451
+ trusted_resume = _load_trusted_resume_catalog(
452
+ directory=directory,
453
+ expected_manifest_sha256=expected_existing_manifest_sha256,
454
+ expected_facts=lexical_facts,
455
+ lexical_backend=lexical_backend,
456
+ neural_backend=neural_backend,
457
+ fallback_reason=fallback_reason,
458
+ )
459
+ if trusted_resume is not None:
460
+ return _result_from_trusted_resume(trusted_resume)
461
+ shared_facts_sha256 = _shared_facts_sha256(lexical_facts)
462
+
463
+ lexical_generation = _representation_generation(shared_facts_sha256, lexical_backend.descriptor)
464
+ lexical_directory = directory / LEXICAL_REPRESENTATION / lexical_generation
465
+ if trusted_predecessor is None:
466
+ lexical_result = _seal_representation_generation(
467
+ reused_entries=(),
468
+ fresh_entries=fresh_entries,
469
+ backend=lexical_backend,
470
+ directory=lexical_directory,
471
+ predecessor_directory=None,
472
+ predecessor_manifest_sha256=None,
473
+ egress_policy=egress_policy,
474
+ )
475
+ else:
476
+ with tempfile.TemporaryDirectory(prefix="mr-lexical-predecessor-") as snapshot_raw:
477
+ snapshot_directory, snapshot_digest = _materialize_representation_snapshot(
478
+ trusted_predecessor.lexical,
479
+ directory=Path(snapshot_raw),
480
+ )
481
+ lexical_result = _seal_representation_generation(
482
+ reused_entries=lexical_reused_entries,
483
+ fresh_entries=fresh_entries,
484
+ backend=lexical_backend,
485
+ directory=lexical_directory,
486
+ predecessor_directory=snapshot_directory,
487
+ predecessor_manifest_sha256=snapshot_digest,
488
+ egress_policy=egress_policy,
489
+ )
490
+ representations = [
491
+ _representation_from_seal(
492
+ root=directory,
493
+ name=LEXICAL_REPRESENTATION,
494
+ generation=lexical_generation,
495
+ descriptor=lexical_backend.descriptor,
496
+ result=lexical_result,
497
+ )
498
+ ]
499
+
500
+ neural_result: CatalogSealResult | None = None
501
+ if neural_backend is not None:
502
+ neural_generation = _representation_generation(
503
+ shared_facts_sha256, neural_backend.descriptor
504
+ )
505
+ neural_directory = directory / NEURAL_REPRESENTATION / neural_generation
506
+ trusted_neural = None if trusted_predecessor is None else trusted_predecessor.neural
507
+ if trusted_neural is None:
508
+ neural_result = _seal_representation_generation(
509
+ reused_entries=(),
510
+ fresh_entries=neural_fresh,
511
+ backend=neural_backend,
512
+ directory=neural_directory,
513
+ predecessor_directory=None,
514
+ predecessor_manifest_sha256=None,
515
+ egress_policy=egress_policy,
516
+ )
517
+ else:
518
+ with tempfile.TemporaryDirectory(prefix="mr-neural-predecessor-") as snapshot_raw:
519
+ snapshot_directory, snapshot_digest = _materialize_representation_snapshot(
520
+ trusted_neural,
521
+ directory=Path(snapshot_raw),
522
+ )
523
+ neural_result = _seal_representation_generation(
524
+ reused_entries=neural_reused_entries,
525
+ fresh_entries=neural_fresh,
526
+ backend=neural_backend,
527
+ directory=neural_directory,
528
+ predecessor_directory=snapshot_directory,
529
+ predecessor_manifest_sha256=snapshot_digest,
530
+ egress_policy=egress_policy,
531
+ )
532
+ if tuple(
533
+ (entry.coordinate, entry.facts_digest) for entry in neural_result.entries
534
+ ) != tuple((entry.coordinate, entry.facts_digest) for entry in lexical_result.entries):
535
+ raise SourceContractError(
536
+ "RETRIEVAL_SHARED_FACTS",
537
+ "retrieval.neural",
538
+ "neural successor differs from lexical canonical facts",
539
+ )
540
+ representations.append(
541
+ _representation_from_seal(
542
+ root=directory,
543
+ name=NEURAL_REPRESENTATION,
544
+ generation=neural_generation,
545
+ descriptor=neural_backend.descriptor,
546
+ result=neural_result,
547
+ )
548
+ )
549
+
550
+ manifest = RetrievalManifestV2(
551
+ shared_facts_sha256=shared_facts_sha256,
552
+ representations=tuple(representations),
553
+ fallback_reason=fallback_reason,
554
+ )
555
+ if RetrievalManifestV2.from_bytes(manifest.canonical_bytes) != manifest:
556
+ raise SourceContractError(
557
+ "RETRIEVAL_MANIFEST_READBACK", RETRIEVAL_MANIFEST_FILENAME, "reparse differs"
558
+ )
559
+ _publish_retrieval_manifest(directory, manifest.canonical_bytes)
560
+ return RetrievalSealResult(
561
+ manifest=manifest,
562
+ manifest_sha256=manifest.digest,
563
+ lexical_entries=lexical_result.entries,
564
+ neural_entries=None if neural_result is None else neural_result.entries,
565
+ lexical_reused_vector_sha256s=lexical_result.reused_vector_sha256s,
566
+ lexical_created_vector_sha256s=lexical_result.created_vector_sha256s,
567
+ neural_reused_vector_sha256s=()
568
+ if neural_result is None
569
+ else neural_result.reused_vector_sha256s,
570
+ neural_created_vector_sha256s=()
571
+ if neural_result is None
572
+ else neural_result.created_vector_sha256s,
573
+ lexical_encoder_invocations=lexical_result.encoder_invocations,
574
+ neural_encoder_invocations=0
575
+ if neural_result is None
576
+ else neural_result.encoder_invocations,
577
+ )
578
+
579
+
580
+ def compose_catalog_entry(
581
+ *,
582
+ record: HarvestedRecord,
583
+ rights: RightsEvidence,
584
+ observation: SourceObservation,
585
+ spatial_scope: tuple[str, ...],
586
+ access_kind: str,
587
+ authentication_required: bool,
588
+ entry_id: str,
589
+ egress_policy: EgressPolicy,
590
+ data_formats: tuple[str, ...] | None = None,
591
+ quirks: tuple[SourceQuirk, ...] = (),
592
+ declared_columns: tuple[str, ...] = (),
593
+ declared_vocabulary: tuple[str, ...] = (),
594
+ declared_row_count: int | None = None,
595
+ ) -> CatalogEntry:
596
+ """Turn one harvested record into a first-version catalog entry, publicly cited.
597
+
598
+ This is the seam where a stranger's document becomes shared knowledge, so it is where the
599
+ public-source checks actually run. Returning an unchecked entry and expecting the caller to
600
+ validate it is the "enforced by review" pattern the tenancy rule rejects.
601
+
602
+ ``entry_id`` is supplied rather than derived from ``record.record_id``: publisher ids do not
603
+ satisfy the harness identifier grammar in general, and silently transliterating one would make
604
+ the ``faostat_qcl@v3`` coordinate unstable across harvests. The author chooses the id; the
605
+ record is the cited evidence for it.
606
+
607
+ ``data_formats`` defaults to what the record declares and exists because some protocols declare
608
+ nothing. An SDMX structure message describes dataflows, not payloads, so every SDMX record
609
+ carries ``data_formats=()``; a CKAN package whose resources name only formats outside the closed
610
+ vocabulary carries the same. Without an override those records could not be composed at all, and
611
+ the only remaining route into a catalog would be hand-building a ``CatalogEntry`` -- the
612
+ unchecked route this seam exists to replace. Supplying formats is an author's assertion about
613
+ what the source really publishes, and the record stays cited as the evidence for the rest of the
614
+ entry. When neither the record nor the author supplies one, composition refuses and says so.
615
+ """
616
+
617
+ if not isinstance(record, HarvestedRecord):
618
+ raise SourceContractError("TYPE", "record", "must be a HarvestedRecord")
619
+ if not isinstance(entry_id, str) or not _ENTRY_ID.fullmatch(entry_id):
620
+ raise SourceContractError(
621
+ "CATALOG_ENTRY_ID",
622
+ "entry_id",
623
+ f"{entry_id!r} is not a valid entry identifier for record {record.record_id!r}; "
624
+ "an entry id is chosen by the author, never transliterated from a publisher id",
625
+ )
626
+ if data_formats is not None and not isinstance(data_formats, tuple):
627
+ raise SourceContractError("TYPE", "data_formats", "must be a tuple of format names")
628
+ resolved_formats = record.data_formats if data_formats is None else data_formats
629
+ if not resolved_formats:
630
+ raise SourceContractError(
631
+ "CATALOG_ENTRY_FORMATS",
632
+ "data_formats",
633
+ f"record {record.record_id!r} on protocol {record.protocol!r} declares no payload "
634
+ "format the harness can read, so the author must supply data_formats explicitly; a "
635
+ "structure or metadata document describes a source without describing its payload",
636
+ )
637
+ entry = CatalogEntry(
638
+ entry_id=entry_id,
639
+ entry_version=1,
640
+ publisher=record.publisher,
641
+ title=record.title,
642
+ description=record.description,
643
+ spatial_scope=spatial_scope,
644
+ data_formats=resolved_formats,
645
+ access_kind=access_kind,
646
+ authentication_required=authentication_required,
647
+ observation=observation,
648
+ rights=rights,
649
+ quirks=quirks,
650
+ declared_columns=declared_columns,
651
+ declared_vocabulary=declared_vocabulary,
652
+ declared_row_count=declared_row_count,
653
+ evidence=(record.evidence,),
654
+ vectors=(),
655
+ previous_digest=None,
656
+ )
657
+ require_public_source_evidence(entry, egress_policy=egress_policy)
658
+ return entry
659
+
660
+
661
+ def seal_catalog_successor(
662
+ *,
663
+ reused_entries: tuple[CatalogEntry, ...],
664
+ fresh_entries: tuple[CatalogEntry, ...],
665
+ backend: EmbeddingBackend,
666
+ directory: Path,
667
+ predecessor_directory: Path | None,
668
+ predecessor_manifest_sha256: str | None,
669
+ egress_policy: EgressPolicy,
670
+ ) -> CatalogSealResult:
671
+ """Durably publish one complete v1 current-head manifest.
672
+
673
+ Existing sealed entries retain their exact vector references and bytes. New and changed
674
+ unsealed entries are encoded once per layer. Every member is installed through retained root
675
+ descriptors with exclusive no-follow creation, exact readback, and mode ``0444`` before the
676
+ manifest is atomically replaced and read back.
677
+ """
678
+
679
+ if not isinstance(directory, Path):
680
+ raise SourceContractError("TYPE", "directory", "must be a Path")
681
+ if predecessor_directory is not None and not isinstance(predecessor_directory, Path):
682
+ raise SourceContractError("TYPE", "predecessor_directory", "must be a Path or None")
683
+ if not isinstance(reused_entries, tuple) or not isinstance(fresh_entries, tuple):
684
+ raise SourceContractError(
685
+ "TYPE", "catalog.successor.entries", "entry collections must be tuples"
686
+ )
687
+ captured_reused = tuple(
688
+ _capture_entry(entry, index=index, sealed=True)
689
+ for index, entry in enumerate(reused_entries)
690
+ )
691
+ captured_fresh = tuple(
692
+ _capture_entry(entry, index=index, sealed=False)
693
+ for index, entry in enumerate(fresh_entries)
694
+ )
695
+ all_ids = [entry.entry_id for entry in (*captured_reused, *captured_fresh)]
696
+ if len(set(all_ids)) != len(all_ids):
697
+ raise SourceContractError(
698
+ "DUPLICATE", "catalog.entries", "a current-head catalog has one entry per source"
699
+ )
700
+ for entry in (*captured_reused, *captured_fresh):
701
+ require_public_source_evidence(entry, egress_policy=egress_policy)
702
+
703
+ _refuse_build_ancestor(directory)
704
+ root_fd, publication_fds, publication_chain = _open_or_create_catalog_root(directory)
705
+ source_root_fd = -1
706
+ vector_fd = -1
707
+ source_vector_fd = -1
708
+ try:
709
+ _verify_publication_chain(publication_chain)
710
+ _refuse_build_root(root_fd)
711
+ try:
712
+ os.mkdir(VECTORS_DIRNAME, mode=0o755, dir_fd=root_fd)
713
+ except FileExistsError:
714
+ pass
715
+ vector_fd = _open_directory_at(root_fd, VECTORS_DIRNAME, "catalog vectors")
716
+
717
+ if predecessor_manifest_sha256 is None:
718
+ if captured_reused:
719
+ raise SourceContractError(
720
+ "CATALOG_PREDECESSOR",
721
+ "catalog.predecessor",
722
+ "reused entries require an exact predecessor manifest digest",
723
+ )
724
+ else:
725
+ if predecessor_directory is None:
726
+ raise SourceContractError(
727
+ "CATALOG_PREDECESSOR",
728
+ "catalog.predecessor",
729
+ "an exact predecessor directory is required",
730
+ )
731
+ source_root_fd = _open_directory_nofollow(
732
+ predecessor_directory, "catalog predecessor root"
733
+ )
734
+ predecessor_raw = _read_regular_at(
735
+ source_root_fd,
736
+ CATALOG_FILENAME,
737
+ maximum=MAX_CATALOG_MANIFEST_BYTES,
738
+ label="catalog predecessor manifest",
739
+ )
740
+ if sha256_bytes(predecessor_raw) != predecessor_manifest_sha256:
741
+ raise SourceContractError(
742
+ "CATALOG_PREDECESSOR",
743
+ "catalog.predecessor",
744
+ "predecessor manifest digest differs",
745
+ )
746
+ previous = _entries_from_manifest(predecessor_raw)
747
+ previous_by_id = {entry.entry_id: entry for entry in previous}
748
+ for entry in captured_reused:
749
+ observed = previous_by_id.get(entry.entry_id)
750
+ if observed is None or observed.to_dict() != entry.to_dict():
751
+ raise SourceContractError(
752
+ "CATALOG_PREDECESSOR",
753
+ f"catalog.predecessor.{entry.entry_id}",
754
+ "reused entry is not the exact predecessor member",
755
+ )
756
+ source_vector_fd = _open_directory_at(
757
+ source_root_fd, VECTORS_DIRNAME, "catalog predecessor vectors"
758
+ )
759
+
760
+ descriptor = backend.descriptor
761
+ payloads: dict[str, bytes] = {}
762
+ reused_digests: set[str] = set()
763
+ for entry in captured_reused:
764
+ for reference in entry.vectors:
765
+ if (
766
+ reference.backend_id != descriptor.backend_id
767
+ or reference.backend_version != descriptor.backend_version
768
+ or reference.dimensions != descriptor.dimensions
769
+ or reference.quantization != descriptor.quantization
770
+ ):
771
+ raise SourceContractError(
772
+ "CATALOG_BACKEND_IDENTITY",
773
+ f"catalog.entries.{entry.entry_id}",
774
+ "reused vectors do not match the selected backend",
775
+ )
776
+ raw = _read_regular_at(
777
+ source_vector_fd,
778
+ f"{reference.vector_sha256}{VECTOR_SUFFIX}",
779
+ maximum=descriptor.dimensions * 4,
780
+ label=f"reused vector {reference.vector_sha256}",
781
+ )
782
+ if (
783
+ len(raw) != descriptor.dimensions * 4
784
+ or sha256_bytes(raw) != reference.vector_sha256
785
+ ):
786
+ raise SourceContractError(
787
+ "CATALOG_VECTOR_DIGEST",
788
+ reference.vector_sha256,
789
+ "reused vector bytes differ from their content address",
790
+ )
791
+ prior = payloads.setdefault(reference.vector_sha256, raw)
792
+ if prior != raw:
793
+ raise SourceContractError(
794
+ "CATALOG_VECTOR_COLLISION",
795
+ reference.vector_sha256,
796
+ "one content address resolved to different bytes",
797
+ )
798
+ reused_digests.add(reference.vector_sha256)
799
+
800
+ sealed_fresh: list[CatalogEntry] = []
801
+ encoder_invocations = 0
802
+ for entry in captured_fresh:
803
+ facts_digest = entry.facts_digest
804
+ references: list[LayerVectorReference] = []
805
+ for layer in EMBEDDING_LAYERS:
806
+ vector = backend.encode(layer_text(entry, layer))
807
+ encoder_invocations += 1
808
+ if len(vector) != descriptor.dimensions:
809
+ raise SourceContractError(
810
+ "EMBEDDING_DIMENSIONS",
811
+ f"{entry.coordinate}.{layer}",
812
+ f"backend returned {len(vector)} values, expected {descriptor.dimensions}",
813
+ )
814
+ packed = struct.pack(f">{descriptor.dimensions}i", *vector)
815
+ digest = sha256_bytes(packed)
816
+ prior = payloads.setdefault(digest, packed)
817
+ if prior != packed:
818
+ raise SourceContractError(
819
+ "CATALOG_VECTOR_COLLISION",
820
+ digest,
821
+ "one content address resolved to different bytes",
822
+ )
823
+ references.append(
824
+ LayerVectorReference(
825
+ layer=layer,
826
+ backend_id=descriptor.backend_id,
827
+ backend_version=descriptor.backend_version,
828
+ dimensions=descriptor.dimensions,
829
+ quantization=descriptor.quantization,
830
+ vector_sha256=digest,
831
+ entry_facts_digest=facts_digest,
832
+ )
833
+ )
834
+ sealed_fresh.append(replace(entry, vectors=tuple(references)))
835
+
836
+ ordered = tuple(
837
+ sorted((*captured_reused, *sealed_fresh), key=lambda item: _entry_key(item))
838
+ )
839
+ index_bytes = canonical_json_bytes(
840
+ {
841
+ "schema_version": CATALOG_INDEX_CONTRACT_VERSION,
842
+ "entries": [item.to_dict() for item in ordered],
843
+ }
844
+ )
845
+ # Strict reconstruction before the first output mutation makes the manifest a checked
846
+ # successor, not merely canonical bytes produced by this process.
847
+ if _entries_from_manifest(index_bytes) != ordered:
848
+ raise SourceContractError(
849
+ "CATALOG_ENTRY_PROJECTION", "catalog.entries", "manifest reconstruction differs"
850
+ )
851
+
852
+ for digest in sorted(payloads):
853
+ _install_immutable_member(
854
+ vector_fd,
855
+ f"{digest}{VECTOR_SUFFIX}",
856
+ payloads[digest],
857
+ digest=digest,
858
+ )
859
+ _catalog_durability_barrier(vector_fd, "vectors-directory")
860
+ manifest_digest = sha256_bytes(index_bytes)
861
+ temporary = f".{CATALOG_FILENAME}.tmp-{secrets.token_hex(16)}"
862
+ try:
863
+ manifest_fd = _create_regular_at(root_fd, temporary, mode=0o600)
864
+ try:
865
+ _write_all(manifest_fd, index_bytes)
866
+ _catalog_durability_barrier(manifest_fd, "manifest-temporary")
867
+ if _read_open_descriptor(manifest_fd, maximum=len(index_bytes)) != index_bytes:
868
+ raise SourceContractError(
869
+ "CATALOG_MANIFEST_READBACK",
870
+ CATALOG_FILENAME,
871
+ "temporary manifest readback differs",
872
+ )
873
+ finally:
874
+ os.close(manifest_fd)
875
+ os.replace(
876
+ temporary,
877
+ CATALOG_FILENAME,
878
+ src_dir_fd=root_fd,
879
+ dst_dir_fd=root_fd,
880
+ )
881
+ _verify_publication_chain(publication_chain)
882
+ _catalog_durability_barrier(root_fd, "manifest-replaced")
883
+ _catalog_durability_barrier(root_fd, "catalog-directory")
884
+ observed = _read_regular_at(
885
+ root_fd,
886
+ CATALOG_FILENAME,
887
+ maximum=len(index_bytes),
888
+ label="published catalog manifest",
889
+ )
890
+ if observed != index_bytes or sha256_bytes(observed) != manifest_digest:
891
+ raise SourceContractError(
892
+ "CATALOG_MANIFEST_READBACK",
893
+ CATALOG_FILENAME,
894
+ "published manifest readback differs",
895
+ )
896
+ _catalog_durability_barrier(root_fd, "manifest-readback")
897
+ finally:
898
+ try:
899
+ os.unlink(temporary, dir_fd=root_fd)
900
+ except FileNotFoundError:
901
+ pass
902
+ return CatalogSealResult(
903
+ entries=ordered,
904
+ manifest_sha256=manifest_digest,
905
+ reused_vector_sha256s=tuple(sorted(reused_digests)),
906
+ created_vector_sha256s=tuple(sorted(set(payloads) - reused_digests)),
907
+ encoder_invocations=encoder_invocations,
908
+ )
909
+ finally:
910
+ for descriptor_to_close in (
911
+ source_vector_fd,
912
+ vector_fd,
913
+ source_root_fd,
914
+ ):
915
+ if descriptor_to_close >= 0:
916
+ os.close(descriptor_to_close)
917
+ for descriptor_to_close in reversed(publication_fds):
918
+ os.close(descriptor_to_close)
919
+
920
+
921
+ def _capture_entry(entry: CatalogEntry, *, index: int, sealed: bool) -> CatalogEntry:
922
+ if type(entry) is not CatalogEntry:
923
+ raise SourceContractError("TYPE", f"entries[{index}]", "must be a CatalogEntry")
924
+ captured = canonical_json_bytes(entry.to_dict())
925
+ admit_public_fact_bytes(captured)
926
+ canonical_entry = catalog_entry_from_dict(parse_canonical_json(captured))
927
+ if canonical_json_bytes(canonical_entry.to_dict()) != captured:
928
+ raise SourceContractError(
929
+ "CATALOG_ENTRY_PROJECTION",
930
+ f"entries[{index}]",
931
+ "entry cannot be rebuilt byte-for-byte",
932
+ )
933
+ if sealed and not canonical_entry.vectors:
934
+ raise SourceContractError(
935
+ "CATALOG_REUSE_UNSEALED", f"entries[{index}]", "reused entry must be sealed"
936
+ )
937
+ if not sealed and canonical_entry.vectors:
938
+ raise SourceContractError(
939
+ "CATALOG_ALREADY_SEALED", f"entries[{index}]", "fresh entry must be unsealed"
940
+ )
941
+ return canonical_entry
942
+
943
+
944
+ def _shared_facts_sha256(entries: tuple[CatalogEntry, ...]) -> str:
945
+ return sha256_bytes(
946
+ canonical_json_bytes(
947
+ [
948
+ {"coordinate": entry.coordinate, "facts_sha256": entry.facts_digest}
949
+ for entry in entries
950
+ ]
951
+ )
952
+ )
953
+
954
+
955
+ def _seal_representation_generation(
956
+ *,
957
+ reused_entries: tuple[CatalogEntry, ...],
958
+ fresh_entries: tuple[CatalogEntry, ...],
959
+ backend: EmbeddingBackend,
960
+ directory: Path,
961
+ predecessor_directory: Path | None,
962
+ predecessor_manifest_sha256: str | None,
963
+ egress_policy: EgressPolicy,
964
+ ) -> CatalogSealResult:
965
+ """Seal a new generation; an existing one needs a trusted outer-head resume."""
966
+
967
+ _seal_generation_descriptor(directory, backend.descriptor)
968
+ if (directory / CATALOG_FILENAME).exists():
969
+ raise SourceContractError(
970
+ "RETRIEVAL_GENERATION_UNTRUSTED",
971
+ str(directory),
972
+ "existing generation requires an explicit authenticated outer manifest digest",
973
+ )
974
+ return seal_catalog_successor(
975
+ reused_entries=reused_entries,
976
+ fresh_entries=fresh_entries,
977
+ backend=backend,
978
+ directory=directory,
979
+ predecessor_directory=predecessor_directory,
980
+ predecessor_manifest_sha256=predecessor_manifest_sha256,
981
+ egress_policy=egress_policy,
982
+ )
983
+
984
+
985
+ def _representation_generation(shared_facts_sha256: str, descriptor: BackendDescriptor) -> str:
986
+ return sha256_bytes(
987
+ canonical_json_bytes(
988
+ {
989
+ "backend_descriptor_sha256": backend_descriptor_sha256(descriptor),
990
+ "shared_facts_sha256": shared_facts_sha256,
991
+ }
992
+ )
993
+ )
994
+
995
+
996
+ def _capture_trusted_retrieval_predecessor(
997
+ *,
998
+ predecessor_directory: Path | None,
999
+ predecessor_manifest_sha256: str | None,
1000
+ lexical_reused_entries: tuple[CatalogEntry, ...],
1001
+ neural_reused_entries: tuple[CatalogEntry, ...],
1002
+ lexical_backend: EmbeddingBackend,
1003
+ neural_backend: EmbeddingBackend | None,
1004
+ ) -> LoadedRetrievalCatalog:
1005
+ if predecessor_directory is None or predecessor_manifest_sha256 is None:
1006
+ raise SourceContractError(
1007
+ "CATALOG_PREDECESSOR",
1008
+ "retrieval.predecessor",
1009
+ "representation reuse requires an exact predecessor outer root and manifest digest",
1010
+ )
1011
+ loaded = load_retrieval_catalog(
1012
+ predecessor_directory,
1013
+ expected_manifest_sha256=predecessor_manifest_sha256,
1014
+ neural_backend=neural_backend,
1015
+ )
1016
+ if backend_descriptor_bytes(loaded.lexical.backend.descriptor) != backend_descriptor_bytes(
1017
+ lexical_backend.descriptor
1018
+ ):
1019
+ raise SourceContractError(
1020
+ "RETRIEVAL_BACKEND_MISMATCH",
1021
+ "retrieval.lexical_predecessor",
1022
+ "trusted predecessor uses a different lexical backend descriptor",
1023
+ )
1024
+ previous_lexical = {entry.entry_id: entry for entry in loaded.lexical.entries}
1025
+ for entry in lexical_reused_entries:
1026
+ observed = previous_lexical.get(entry.entry_id)
1027
+ if observed is None or observed.to_dict() != entry.to_dict():
1028
+ raise SourceContractError(
1029
+ "CATALOG_PREDECESSOR",
1030
+ f"retrieval.lexical_predecessor.{entry.entry_id}",
1031
+ "reused lexical entry is not the exact authenticated predecessor member",
1032
+ )
1033
+ if neural_reused_entries and loaded.neural is None:
1034
+ raise SourceContractError(
1035
+ "CATALOG_PREDECESSOR",
1036
+ "retrieval.neural_predecessor",
1037
+ "trusted predecessor has no resolved neural representation",
1038
+ )
1039
+ previous_neural = (
1040
+ {} if loaded.neural is None else {entry.entry_id: entry for entry in loaded.neural.entries}
1041
+ )
1042
+ for entry in neural_reused_entries:
1043
+ observed = previous_neural.get(entry.entry_id)
1044
+ if observed is None or observed.to_dict() != entry.to_dict():
1045
+ raise SourceContractError(
1046
+ "CATALOG_PREDECESSOR",
1047
+ f"retrieval.neural_predecessor.{entry.entry_id}",
1048
+ "reused neural entry is not the exact authenticated predecessor member",
1049
+ )
1050
+ return loaded
1051
+
1052
+
1053
+ def _materialize_representation_snapshot(
1054
+ snapshot: LoadedRetrievalRepresentation,
1055
+ *,
1056
+ directory: Path,
1057
+ ) -> tuple[Path, str]:
1058
+ vectors_directory = directory / VECTORS_DIRNAME
1059
+ vectors_directory.mkdir(parents=True)
1060
+ catalog_raw = canonical_json_bytes(
1061
+ {
1062
+ "entries": [entry.to_dict() for entry in snapshot.entries],
1063
+ "schema_version": CATALOG_INDEX_CONTRACT_VERSION,
1064
+ }
1065
+ )
1066
+ _atomic_write(directory / CATALOG_FILENAME, catalog_raw)
1067
+ written: set[str] = set()
1068
+ for entry in snapshot.entries:
1069
+ for reference in entry.vectors:
1070
+ if reference.vector_sha256 in written:
1071
+ continue
1072
+ vector = snapshot.vectors[(entry.entry_id, reference.layer)]
1073
+ raw = struct.pack(f">{reference.dimensions}i", *vector)
1074
+ if sha256_bytes(raw) != reference.vector_sha256:
1075
+ raise SourceContractError(
1076
+ "CATALOG_VECTOR_DIGEST",
1077
+ reference.vector_sha256,
1078
+ "authenticated snapshot vector no longer matches its content address",
1079
+ )
1080
+ _atomic_write(vectors_directory / f"{reference.vector_sha256}{VECTOR_SUFFIX}", raw)
1081
+ written.add(reference.vector_sha256)
1082
+ return directory, sha256_bytes(catalog_raw)
1083
+
1084
+
1085
+ def _load_trusted_resume_catalog(
1086
+ *,
1087
+ directory: Path,
1088
+ expected_manifest_sha256: str | None,
1089
+ expected_facts: tuple[CatalogEntry, ...],
1090
+ lexical_backend: EmbeddingBackend,
1091
+ neural_backend: EmbeddingBackend | None,
1092
+ fallback_reason: str | None,
1093
+ ) -> LoadedRetrievalCatalog | None:
1094
+ if expected_manifest_sha256 is None:
1095
+ return None
1096
+ loaded = load_retrieval_catalog(
1097
+ directory,
1098
+ expected_manifest_sha256=expected_manifest_sha256,
1099
+ neural_backend=neural_backend,
1100
+ )
1101
+ expected = tuple((entry.coordinate, entry.facts_digest) for entry in expected_facts)
1102
+ observed = tuple((entry.coordinate, entry.facts_digest) for entry in loaded.lexical.entries)
1103
+ if observed != expected:
1104
+ raise SourceContractError(
1105
+ "RETRIEVAL_GENERATION_COLLISION",
1106
+ str(directory),
1107
+ "authenticated existing head differs from the requested canonical facts",
1108
+ )
1109
+ if backend_descriptor_bytes(loaded.lexical.backend.descriptor) != backend_descriptor_bytes(
1110
+ lexical_backend.descriptor
1111
+ ):
1112
+ raise SourceContractError(
1113
+ "RETRIEVAL_BACKEND_MISMATCH",
1114
+ str(directory),
1115
+ "authenticated existing head uses a different lexical backend",
1116
+ )
1117
+ requested_hybrid = neural_backend is not None
1118
+ loaded_hybrid = loaded.manifest.neural is not None
1119
+ if requested_hybrid != loaded_hybrid:
1120
+ raise SourceContractError(
1121
+ "RETRIEVAL_BACKEND_MISMATCH",
1122
+ str(directory),
1123
+ "authenticated existing head has a different representation set",
1124
+ )
1125
+ if loaded.manifest.fallback_reason != fallback_reason:
1126
+ raise SourceContractError(
1127
+ "RETRIEVAL_MANIFEST_FALLBACK",
1128
+ str(directory),
1129
+ "authenticated existing head has a different fallback reason",
1130
+ )
1131
+ if requested_hybrid:
1132
+ assert neural_backend is not None
1133
+ assert loaded.neural is not None
1134
+ if backend_descriptor_bytes(loaded.neural.backend.descriptor) != backend_descriptor_bytes(
1135
+ neural_backend.descriptor
1136
+ ):
1137
+ raise SourceContractError(
1138
+ "RETRIEVAL_BACKEND_MISMATCH",
1139
+ str(directory),
1140
+ "authenticated existing head uses a different complete neural descriptor",
1141
+ )
1142
+ return loaded
1143
+
1144
+
1145
+ def _result_from_trusted_resume(loaded: LoadedRetrievalCatalog) -> RetrievalSealResult:
1146
+ lexical_digests = tuple(
1147
+ sorted(
1148
+ {
1149
+ reference.vector_sha256
1150
+ for entry in loaded.lexical.entries
1151
+ for reference in entry.vectors
1152
+ }
1153
+ )
1154
+ )
1155
+ neural_digests: tuple[str, ...] = ()
1156
+ if loaded.neural is not None:
1157
+ neural_digests = tuple(
1158
+ sorted(
1159
+ {
1160
+ reference.vector_sha256
1161
+ for entry in loaded.neural.entries
1162
+ for reference in entry.vectors
1163
+ }
1164
+ )
1165
+ )
1166
+ return RetrievalSealResult(
1167
+ manifest=loaded.manifest,
1168
+ manifest_sha256=loaded.manifest.digest,
1169
+ lexical_entries=loaded.lexical.entries,
1170
+ neural_entries=None if loaded.neural is None else loaded.neural.entries,
1171
+ lexical_reused_vector_sha256s=lexical_digests,
1172
+ lexical_created_vector_sha256s=(),
1173
+ neural_reused_vector_sha256s=neural_digests,
1174
+ neural_created_vector_sha256s=(),
1175
+ lexical_encoder_invocations=0,
1176
+ neural_encoder_invocations=0,
1177
+ )
1178
+
1179
+
1180
+ def _seal_generation_descriptor(directory: Path, descriptor: BackendDescriptor) -> None:
1181
+ raw = backend_descriptor_bytes(descriptor)
1182
+ digest = sha256_bytes(raw)
1183
+ generation_fd, owned, chain = _open_or_create_catalog_root(directory)
1184
+ try:
1185
+ _verify_publication_chain(chain)
1186
+ try:
1187
+ os.stat(CATALOG_FILENAME, dir_fd=generation_fd, follow_symlinks=False)
1188
+ catalog_exists = True
1189
+ except FileNotFoundError:
1190
+ catalog_exists = False
1191
+ try:
1192
+ os.stat(
1193
+ REPRESENTATION_DESCRIPTOR_FILENAME,
1194
+ dir_fd=generation_fd,
1195
+ follow_symlinks=False,
1196
+ )
1197
+ descriptor_exists = True
1198
+ except FileNotFoundError:
1199
+ descriptor_exists = False
1200
+ if catalog_exists and not descriptor_exists:
1201
+ raise SourceContractError(
1202
+ "RETRIEVAL_BACKEND_MISMATCH",
1203
+ str(directory),
1204
+ "existing generation has no authenticated backend descriptor",
1205
+ )
1206
+ try:
1207
+ _install_immutable_member(
1208
+ generation_fd,
1209
+ REPRESENTATION_DESCRIPTOR_FILENAME,
1210
+ raw,
1211
+ digest=digest,
1212
+ )
1213
+ except SourceContractError as error:
1214
+ raise SourceContractError(
1215
+ "RETRIEVAL_BACKEND_MISMATCH",
1216
+ str(directory),
1217
+ "existing generation backend descriptor differs",
1218
+ ) from error
1219
+ finally:
1220
+ for owned_fd in reversed(owned):
1221
+ os.close(owned_fd)
1222
+
1223
+
1224
+ def _representation_from_seal(
1225
+ *,
1226
+ root: Path,
1227
+ name: str,
1228
+ generation: str,
1229
+ descriptor: BackendDescriptor,
1230
+ result: CatalogSealResult,
1231
+ ) -> RetrievalRepresentation:
1232
+ root_fd = _open_directory_nofollow(root, "retrieval publication root")
1233
+ name_fd = -1
1234
+ generation_fd = -1
1235
+ vectors_fd = -1
1236
+ try:
1237
+ name_fd = _open_directory_at(root_fd, name, f"{name} representation")
1238
+ generation_fd = _open_directory_at(name_fd, generation, f"{name} generation")
1239
+ catalog_raw = _read_regular_at(
1240
+ generation_fd,
1241
+ CATALOG_FILENAME,
1242
+ maximum=MAX_CATALOG_MANIFEST_BYTES,
1243
+ label=f"{name} catalog manifest",
1244
+ )
1245
+ if sha256_bytes(catalog_raw) != result.manifest_sha256:
1246
+ raise SourceContractError(
1247
+ "RETRIEVAL_MEMBER_READBACK",
1248
+ f"{name}/{generation}/{CATALOG_FILENAME}",
1249
+ "inner manifest differs after durable sealing",
1250
+ )
1251
+ prefix = f"{name}/{generation}"
1252
+ members = [
1253
+ RepresentationMember(
1254
+ path=f"{prefix}/{CATALOG_FILENAME}",
1255
+ size=len(catalog_raw),
1256
+ sha256=result.manifest_sha256,
1257
+ )
1258
+ ]
1259
+ descriptor_raw = _read_regular_at(
1260
+ generation_fd,
1261
+ REPRESENTATION_DESCRIPTOR_FILENAME,
1262
+ maximum=MAX_REPRESENTATION_DESCRIPTOR_BYTES,
1263
+ label=f"{name} backend descriptor",
1264
+ )
1265
+ if descriptor_raw != backend_descriptor_bytes(descriptor):
1266
+ raise SourceContractError(
1267
+ "RETRIEVAL_BACKEND_MISMATCH",
1268
+ f"{prefix}/{REPRESENTATION_DESCRIPTOR_FILENAME}",
1269
+ "generation descriptor differs after durable sealing",
1270
+ )
1271
+ members.append(
1272
+ RepresentationMember(
1273
+ path=f"{prefix}/{REPRESENTATION_DESCRIPTOR_FILENAME}",
1274
+ size=len(descriptor_raw),
1275
+ sha256=sha256_bytes(descriptor_raw),
1276
+ )
1277
+ )
1278
+ vectors_fd = _open_directory_at(generation_fd, VECTORS_DIRNAME, f"{name} vectors")
1279
+ vector_digests = sorted(
1280
+ {reference.vector_sha256 for entry in result.entries for reference in entry.vectors}
1281
+ )
1282
+ for digest in vector_digests:
1283
+ raw = _read_regular_at(
1284
+ vectors_fd,
1285
+ f"{digest}{VECTOR_SUFFIX}",
1286
+ maximum=descriptor.dimensions * 4,
1287
+ label=f"{name} vector {digest}",
1288
+ )
1289
+ if len(raw) != descriptor.dimensions * 4 or sha256_bytes(raw) != digest:
1290
+ raise SourceContractError(
1291
+ "RETRIEVAL_MEMBER_READBACK",
1292
+ f"{prefix}/{VECTORS_DIRNAME}/{digest}{VECTOR_SUFFIX}",
1293
+ "sealed vector differs after durable sealing",
1294
+ )
1295
+ members.append(
1296
+ RepresentationMember(
1297
+ path=f"{prefix}/{VECTORS_DIRNAME}/{digest}{VECTOR_SUFFIX}",
1298
+ size=len(raw),
1299
+ sha256=digest,
1300
+ )
1301
+ )
1302
+ return RetrievalRepresentation.create(
1303
+ name=name,
1304
+ descriptor=descriptor,
1305
+ members=tuple(members),
1306
+ )
1307
+ finally:
1308
+ for descriptor_to_close in (vectors_fd, generation_fd, name_fd, root_fd):
1309
+ if descriptor_to_close >= 0:
1310
+ os.close(descriptor_to_close)
1311
+
1312
+
1313
+ def _publish_retrieval_manifest(directory: Path, raw: bytes) -> None:
1314
+ root_fd, owned, chain = _open_or_create_catalog_root(directory)
1315
+ temporary = f".{RETRIEVAL_MANIFEST_FILENAME}.tmp-{secrets.token_hex(16)}"
1316
+ try:
1317
+ _verify_publication_chain(chain)
1318
+ descriptor = _create_regular_at(root_fd, temporary, mode=0o600)
1319
+ try:
1320
+ _write_all(descriptor, raw)
1321
+ _catalog_durability_barrier(descriptor, "retrieval-manifest-temporary")
1322
+ if _read_open_descriptor(descriptor, maximum=len(raw)) != raw:
1323
+ raise SourceContractError(
1324
+ "RETRIEVAL_MANIFEST_READBACK",
1325
+ RETRIEVAL_MANIFEST_FILENAME,
1326
+ "temporary manifest readback differs",
1327
+ )
1328
+ os.fchmod(descriptor, 0o444)
1329
+ finally:
1330
+ os.close(descriptor)
1331
+ _verify_publication_chain(chain)
1332
+ os.replace(
1333
+ temporary,
1334
+ RETRIEVAL_MANIFEST_FILENAME,
1335
+ src_dir_fd=root_fd,
1336
+ dst_dir_fd=root_fd,
1337
+ )
1338
+ _catalog_durability_barrier(root_fd, "retrieval-manifest-replaced")
1339
+ observed = _read_regular_at(
1340
+ root_fd,
1341
+ RETRIEVAL_MANIFEST_FILENAME,
1342
+ maximum=len(raw),
1343
+ label="published retrieval manifest",
1344
+ )
1345
+ if observed != raw:
1346
+ raise SourceContractError(
1347
+ "RETRIEVAL_MANIFEST_READBACK",
1348
+ RETRIEVAL_MANIFEST_FILENAME,
1349
+ "published manifest readback differs",
1350
+ )
1351
+ _catalog_durability_barrier(root_fd, "retrieval-manifest-readback")
1352
+ finally:
1353
+ try:
1354
+ os.unlink(temporary, dir_fd=root_fd)
1355
+ except FileNotFoundError:
1356
+ pass
1357
+ for descriptor_to_close in reversed(owned):
1358
+ os.close(descriptor_to_close)
1359
+
1360
+
1361
+ def _entries_from_manifest(raw: bytes) -> tuple[CatalogEntry, ...]:
1362
+ try:
1363
+ payload = parse_canonical_json(raw)
1364
+ except ValueError as error:
1365
+ raise SourceContractError(
1366
+ "CATALOG_MANIFEST", CATALOG_FILENAME, "manifest is not canonical"
1367
+ ) from error
1368
+ if (
1369
+ not isinstance(payload, dict)
1370
+ or set(payload) != {"schema_version", "entries"}
1371
+ or payload["schema_version"] != CATALOG_INDEX_CONTRACT_VERSION
1372
+ or not isinstance(payload["entries"], list)
1373
+ ):
1374
+ raise SourceContractError(
1375
+ "CATALOG_MANIFEST", CATALOG_FILENAME, "manifest fields or version differ"
1376
+ )
1377
+ entries = tuple(catalog_entry_from_dict(item) for item in payload["entries"])
1378
+ if tuple(sorted(entries, key=_entry_key)) != entries:
1379
+ raise SourceContractError(
1380
+ "CATALOG_MANIFEST", CATALOG_FILENAME, "manifest entries are not sorted"
1381
+ )
1382
+ if len({entry.entry_id for entry in entries}) != len(entries):
1383
+ raise SourceContractError(
1384
+ "CATALOG_MANIFEST", CATALOG_FILENAME, "manifest entry ids are not unique"
1385
+ )
1386
+ return entries
1387
+
1388
+
1389
+ def _open_directory_nofollow(path: Path, label: str) -> int:
1390
+ flags = os.O_RDONLY | getattr(os, "O_DIRECTORY", 0) | getattr(os, "O_NOFOLLOW", 0)
1391
+ try:
1392
+ descriptor = os.open(path, flags)
1393
+ except OSError as error:
1394
+ raise SourceContractError(
1395
+ "CATALOG_PUBLICATION_ROOT", label, "directory cannot be opened safely"
1396
+ ) from error
1397
+ info = os.fstat(descriptor)
1398
+ if not stat.S_ISDIR(info.st_mode):
1399
+ os.close(descriptor)
1400
+ raise SourceContractError("CATALOG_PUBLICATION_ROOT", label, "must be a directory")
1401
+ return descriptor
1402
+
1403
+
1404
+ def _open_or_create_catalog_root(
1405
+ directory: Path,
1406
+ ) -> tuple[int, list[int], list[tuple[int, str, int, tuple[int, int, int]]]]:
1407
+ """Create/open a catalog only through one retained no-follow ancestor chain."""
1408
+
1409
+ owned: list[int] = []
1410
+ chain: list[tuple[int, str, int, tuple[int, int, int]]] = []
1411
+ try:
1412
+ parent_fd = os.open(
1413
+ "/", os.O_RDONLY | getattr(os, "O_DIRECTORY", 0) | getattr(os, "O_NOFOLLOW", 0)
1414
+ )
1415
+ owned.append(parent_fd)
1416
+ for part in Path(os.path.abspath(directory)).parts[1:]:
1417
+ if _directory_contains_build_manifest(parent_fd):
1418
+ raise SourceContractError(
1419
+ "CATALOG_PUBLICATION_ROOT",
1420
+ "catalog.directory",
1421
+ "a catalog may not be written through or inside a sealed Build root",
1422
+ )
1423
+ try:
1424
+ named = os.stat(part, dir_fd=parent_fd, follow_symlinks=False)
1425
+ except FileNotFoundError:
1426
+ os.mkdir(part, mode=0o755, dir_fd=parent_fd)
1427
+ os.fsync(parent_fd)
1428
+ named = os.stat(part, dir_fd=parent_fd, follow_symlinks=False)
1429
+ child_fd = os.open(
1430
+ part,
1431
+ os.O_RDONLY | getattr(os, "O_DIRECTORY", 0) | getattr(os, "O_NOFOLLOW", 0),
1432
+ dir_fd=parent_fd,
1433
+ )
1434
+ owned.append(child_fd)
1435
+ opened = os.fstat(child_fd)
1436
+ identity = _directory_identity(opened)
1437
+ if not stat.S_ISDIR(named.st_mode) or _directory_identity(named) != identity:
1438
+ raise SourceContractError(
1439
+ "CATALOG_PUBLICATION_ROOT",
1440
+ "catalog.directory",
1441
+ "named and opened ancestor identities differ",
1442
+ )
1443
+ chain.append((parent_fd, part, child_fd, identity))
1444
+ parent_fd = child_fd
1445
+ _verify_publication_chain(chain)
1446
+ if _directory_contains_build_manifest(parent_fd):
1447
+ raise SourceContractError(
1448
+ "CATALOG_PUBLICATION_ROOT",
1449
+ "catalog.directory",
1450
+ "a catalog may not be written through or inside a sealed Build root",
1451
+ )
1452
+ return parent_fd, owned, chain
1453
+ except BaseException:
1454
+ for descriptor in reversed(owned):
1455
+ os.close(descriptor)
1456
+ raise
1457
+
1458
+
1459
+ def _verify_publication_chain(
1460
+ chain: list[tuple[int, str, int, tuple[int, int, int]]],
1461
+ ) -> None:
1462
+ for parent_fd, name, child_fd, identity in chain:
1463
+ try:
1464
+ named = os.stat(name, dir_fd=parent_fd, follow_symlinks=False)
1465
+ opened = os.fstat(child_fd)
1466
+ except OSError as error:
1467
+ raise SourceContractError(
1468
+ "CATALOG_PUBLICATION_ROOT",
1469
+ "catalog.directory",
1470
+ "retained publication ancestor disappeared",
1471
+ ) from error
1472
+ if _directory_identity(named) != identity or _directory_identity(opened) != identity:
1473
+ raise SourceContractError(
1474
+ "CATALOG_PUBLICATION_ROOT",
1475
+ "catalog.directory",
1476
+ "retained publication ancestor was replaced",
1477
+ )
1478
+
1479
+
1480
+ def _directory_identity(info: os.stat_result) -> tuple[int, int, int]:
1481
+ return (info.st_dev, info.st_ino, stat.S_IFMT(info.st_mode))
1482
+
1483
+
1484
+ def _open_directory_at(parent_fd: int, name: str, label: str) -> int:
1485
+ flags = os.O_RDONLY | getattr(os, "O_DIRECTORY", 0) | getattr(os, "O_NOFOLLOW", 0)
1486
+ try:
1487
+ descriptor = os.open(name, flags, dir_fd=parent_fd)
1488
+ except OSError as error:
1489
+ raise SourceContractError(
1490
+ "CATALOG_PUBLICATION_ROOT", label, "directory cannot be opened safely"
1491
+ ) from error
1492
+ info = os.fstat(descriptor)
1493
+ if not stat.S_ISDIR(info.st_mode):
1494
+ os.close(descriptor)
1495
+ raise SourceContractError("CATALOG_PUBLICATION_ROOT", label, "must be a directory")
1496
+ return descriptor
1497
+
1498
+
1499
+ def _refuse_build_root(root_fd: int) -> None:
1500
+ if _directory_contains_build_manifest(root_fd):
1501
+ raise SourceContractError(
1502
+ "CATALOG_PUBLICATION_ROOT",
1503
+ "catalog.directory",
1504
+ "a catalog may not be written through or inside a sealed Build root",
1505
+ )
1506
+
1507
+
1508
+ def _refuse_build_ancestor(directory: Path) -> None:
1509
+ absolute = directory.absolute()
1510
+ for candidate in (absolute, *absolute.parents):
1511
+ try:
1512
+ info = candidate.lstat()
1513
+ except FileNotFoundError:
1514
+ continue
1515
+ if not stat.S_ISDIR(info.st_mode) or stat.S_ISLNK(info.st_mode):
1516
+ raise SourceContractError(
1517
+ "CATALOG_PUBLICATION_ROOT",
1518
+ "catalog.directory",
1519
+ "catalog path ancestors must be real directories",
1520
+ )
1521
+ descriptor = _open_directory_nofollow(candidate, "catalog path ancestor")
1522
+ try:
1523
+ if _directory_contains_build_manifest(descriptor):
1524
+ raise SourceContractError(
1525
+ "CATALOG_PUBLICATION_ROOT",
1526
+ "catalog.directory",
1527
+ "a catalog may not be written through or inside a sealed Build root",
1528
+ )
1529
+ finally:
1530
+ os.close(descriptor)
1531
+
1532
+
1533
+ def _directory_contains_build_manifest(root_fd: int) -> bool:
1534
+ try:
1535
+ info = os.stat("manifest.json", dir_fd=root_fd, follow_symlinks=False)
1536
+ except FileNotFoundError:
1537
+ return False
1538
+ if not stat.S_ISREG(info.st_mode) or stat.S_ISLNK(info.st_mode) or info.st_nlink != 1:
1539
+ return False
1540
+ try:
1541
+ raw = _read_regular_at(
1542
+ root_fd,
1543
+ "manifest.json",
1544
+ maximum=MAX_CATALOG_MANIFEST_BYTES,
1545
+ label="possible Build manifest",
1546
+ )
1547
+ payload = parse_canonical_json(raw)
1548
+ except (SourceContractError, ValueError):
1549
+ return False
1550
+ return (
1551
+ isinstance(payload, dict)
1552
+ and isinstance(payload.get("schema_version"), str)
1553
+ and payload["schema_version"].startswith("candidate-manifest.")
1554
+ )
1555
+
1556
+
1557
+ def _create_regular_at(parent_fd: int, name: str, *, mode: int) -> int:
1558
+ flags = (
1559
+ os.O_RDWR
1560
+ | os.O_CREAT
1561
+ | os.O_EXCL
1562
+ | getattr(os, "O_NOFOLLOW", 0)
1563
+ | getattr(os, "O_CLOEXEC", 0)
1564
+ )
1565
+ return os.open(name, flags, mode, dir_fd=parent_fd)
1566
+
1567
+
1568
+ def _install_immutable_member(parent_fd: int, name: str, raw: bytes, *, digest: str) -> None:
1569
+ created = False
1570
+ try:
1571
+ descriptor = _create_regular_at(parent_fd, name, mode=0o600)
1572
+ created = True
1573
+ except FileExistsError:
1574
+ flags = os.O_RDONLY | getattr(os, "O_NOFOLLOW", 0) | getattr(os, "O_CLOEXEC", 0)
1575
+ try:
1576
+ descriptor = os.open(name, flags, dir_fd=parent_fd)
1577
+ except OSError as error:
1578
+ raise SourceContractError(
1579
+ "CATALOG_VECTOR_COLLISION", name, "existing member cannot be opened safely"
1580
+ ) from error
1581
+ try:
1582
+ before = os.fstat(descriptor)
1583
+ if not stat.S_ISREG(before.st_mode) or before.st_nlink != 1:
1584
+ raise SourceContractError(
1585
+ "CATALOG_VECTOR_COLLISION", name, "member is not single-link regular"
1586
+ )
1587
+ if created:
1588
+ _write_all(descriptor, raw)
1589
+ os.fsync(descriptor)
1590
+ stable_before = os.fstat(descriptor)
1591
+ observed = _read_open_descriptor(descriptor, maximum=len(raw))
1592
+ after_read = os.fstat(descriptor)
1593
+ if (
1594
+ observed != raw
1595
+ or sha256_bytes(observed) != digest
1596
+ or after_read.st_size != len(raw)
1597
+ or _identity(stable_before) != _identity(after_read)
1598
+ ):
1599
+ raise SourceContractError(
1600
+ "CATALOG_VECTOR_COLLISION", name, "member readback or identity differs"
1601
+ )
1602
+ os.fchmod(descriptor, 0o444)
1603
+ _catalog_durability_barrier(descriptor, "vector-member")
1604
+ sealed = os.fstat(descriptor)
1605
+ if stat.S_IMODE(sealed.st_mode) != 0o444:
1606
+ raise SourceContractError(
1607
+ "CATALOG_VECTOR_MODE", name, "member did not become immutable"
1608
+ )
1609
+ except BaseException:
1610
+ if created:
1611
+ try:
1612
+ os.unlink(name, dir_fd=parent_fd)
1613
+ except FileNotFoundError:
1614
+ pass
1615
+ raise
1616
+ finally:
1617
+ os.close(descriptor)
1618
+
1619
+
1620
+ def _read_regular_at(parent_fd: int, name: str, *, maximum: int, label: str) -> bytes:
1621
+ flags = os.O_RDONLY | getattr(os, "O_NOFOLLOW", 0) | getattr(os, "O_CLOEXEC", 0)
1622
+ try:
1623
+ descriptor = os.open(name, flags, dir_fd=parent_fd)
1624
+ except OSError as error:
1625
+ raise SourceContractError(
1626
+ "CATALOG_MEMBER", label, "member cannot be opened safely"
1627
+ ) from error
1628
+ try:
1629
+ before = os.fstat(descriptor)
1630
+ if not stat.S_ISREG(before.st_mode) or before.st_nlink != 1 or before.st_size > maximum:
1631
+ raise SourceContractError(
1632
+ "CATALOG_MEMBER", label, "member is not bounded single-link regular"
1633
+ )
1634
+ raw = _read_open_descriptor(descriptor, maximum=maximum)
1635
+ after = os.fstat(descriptor)
1636
+ if _identity(before) != _identity(after) or len(raw) != after.st_size:
1637
+ raise SourceContractError("CATALOG_MEMBER", label, "member changed during read")
1638
+ return raw
1639
+ finally:
1640
+ os.close(descriptor)
1641
+
1642
+
1643
+ def _read_open_descriptor(descriptor: int, *, maximum: int) -> bytes:
1644
+ os.lseek(descriptor, 0, os.SEEK_SET)
1645
+ observed = bytearray()
1646
+ while len(observed) <= maximum:
1647
+ chunk = os.read(descriptor, min(1024 * 1024, maximum + 1 - len(observed)))
1648
+ if not chunk:
1649
+ break
1650
+ observed.extend(chunk)
1651
+ if len(observed) > maximum:
1652
+ raise SourceContractError("CATALOG_MEMBER", "catalog.member", "member exceeds its bound")
1653
+ return bytes(observed)
1654
+
1655
+
1656
+ def _write_all(descriptor: int, raw: bytes) -> None:
1657
+ offset = 0
1658
+ while offset < len(raw):
1659
+ written = os.write(descriptor, raw[offset:])
1660
+ if written < 1:
1661
+ raise SourceContractError(
1662
+ "CATALOG_PUBLICATION", "catalog.member", "write made no progress"
1663
+ )
1664
+ offset += written
1665
+
1666
+
1667
+ def _identity(info: os.stat_result) -> tuple[int, int, int, int, int, int]:
1668
+ base = (info.st_dev, info.st_ino, info.st_mode, info.st_nlink, info.st_mtime_ns)
1669
+ return (*base, info.st_size)
1670
+
1671
+
1672
+ def _entry_key(entry: CatalogEntry) -> tuple[str, int]:
1673
+ return (entry.entry_id, entry.entry_version)
1674
+
1675
+
1676
+ def _catalog_durability_barrier(descriptor: int, boundary: str) -> None:
1677
+ """Persist one publication boundary; the label supports deterministic crash injection."""
1678
+
1679
+ del boundary
1680
+ os.fsync(descriptor)
1681
+
1682
+
1683
+ def _write_vector(path: Path, payload: bytes) -> None:
1684
+ if path.exists():
1685
+ existing = path.read_bytes()
1686
+ if existing != payload:
1687
+ # Content addressing must hold. A mismatch means a corrupted tree (or, absurdly, a
1688
+ # sha256 collision). Either way, overwriting would destroy the evidence.
1689
+ raise SourceContractError(
1690
+ "CATALOG_VECTOR_COLLISION",
1691
+ str(path.name),
1692
+ "an existing vector file with this digest holds different bytes",
1693
+ )
1694
+ return
1695
+ _atomic_write(path, payload)
1696
+
1697
+
1698
+ def _atomic_write(path: Path, payload: bytes) -> None:
1699
+ temporary = path.with_name(f".{path.name}.partial")
1700
+ temporary.write_bytes(payload)
1701
+ os.replace(temporary, path)