roar-cli 0.3.7__tar.gz → 0.4.1__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 (441) hide show
  1. {roar_cli-0.3.7 → roar_cli-0.4.1}/PKG-INFO +2 -1
  2. {roar_cli-0.3.7 → roar_cli-0.4.1}/pyproject.toml +2 -1
  3. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/analyzers/experiment_trackers.py +103 -3
  4. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/get/requests.py +1 -0
  5. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/get/service.py +105 -16
  6. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/put_preparation.py +3 -1
  7. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/register_execution.py +19 -6
  8. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/registration.py +28 -8
  9. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/service.py +17 -7
  10. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/view_edges.py +15 -6
  11. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/__init__.py +12 -0
  12. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/requests.py +52 -0
  13. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/results.py +74 -0
  14. roar_cli-0.4.1/roar/application/query/tag.py +224 -0
  15. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/reproducibility/report.py +18 -0
  16. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/run/execution.py +4 -0
  17. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/run/requests.py +2 -0
  18. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/run/service.py +6 -0
  19. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/system_labels.py +7 -1
  20. roar_cli-0.4.1/roar/application/tags.py +746 -0
  21. roar_cli-0.4.1/roar/cli/_tag_kinds.py +69 -0
  22. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/command_registry.py +7 -0
  23. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/__init__.py +1 -0
  24. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/get.py +11 -0
  25. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/proxy.py +7 -3
  26. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/put.py +14 -2
  27. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/register.py +161 -21
  28. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/run.py +39 -0
  29. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/scope.py +16 -6
  30. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/status.py +10 -0
  31. roar_cli-0.4.1/roar/cli/commands/tag.py +241 -0
  32. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/publish_intent.py +21 -1
  33. roar_cli-0.4.1/roar/cli/templates/agents/SKILL.md.tmpl +198 -0
  34. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/templates/agents/agents_section.md.tmpl +3 -0
  35. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/label_constants.py +12 -0
  36. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/run.py +2 -0
  37. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/services/job_recording.py +75 -5
  38. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/recording/job_recording.py +2 -0
  39. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/reproduction/pipeline_executor.py +29 -19
  40. roar_cli-0.4.1/roar/execution/runtime/active_runs.py +144 -0
  41. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/coordinator.py +9 -0
  42. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/proxy_resource.py +22 -2
  43. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/tracer.py +1 -1
  44. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/config/access.py +8 -0
  45. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/config/schema.py +12 -0
  46. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/download/hf.py +9 -3
  47. roar_cli-0.4.1/roar/integrations/storage/hf.py +146 -0
  48. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/storage/publish.py +5 -0
  49. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/presenters/show_renderer.py +30 -2
  50. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/publish_auth.py +71 -5
  51. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/scope_config.py +4 -0
  52. roar_cli-0.3.7/roar/cli/templates/agents/SKILL.md.tmpl +0 -123
  53. {roar_cli-0.3.7 → roar_cli-0.4.1}/LICENSE +0 -0
  54. {roar_cli-0.3.7 → roar_cli-0.4.1}/README.md +0 -0
  55. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/__init__.py +0 -0
  56. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/__main__.py +0 -0
  57. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/analyzers/__init__.py +0 -0
  58. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/analyzers/base.py +0 -0
  59. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/__init__.py +0 -0
  60. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/composite/__init__.py +0 -0
  61. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/composite/canonical.py +0 -0
  62. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/composite/detect.py +0 -0
  63. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/composite/qualifying.py +0 -0
  64. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/get/__init__.py +0 -0
  65. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/get/results.py +0 -0
  66. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/get/transfer.py +0 -0
  67. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/git.py +0 -0
  68. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/label_rendering.py +0 -0
  69. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/labels.py +0 -0
  70. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/lookup/__init__.py +0 -0
  71. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/lookup/models.py +0 -0
  72. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/lookup/policy.py +0 -0
  73. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/lookup/refs.py +0 -0
  74. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/lookup/remote_artifacts.py +0 -0
  75. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/lookup/runner.py +0 -0
  76. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/__init__.py +0 -0
  77. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/anchor_attribution.py +0 -0
  78. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/blake3_upgrade.py +0 -0
  79. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/collection.py +0 -0
  80. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/composite_builder.py +0 -0
  81. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/composites.py +0 -0
  82. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/datasets.py +0 -0
  83. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/form_composites.py +0 -0
  84. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/git_remote.py +0 -0
  85. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/job_links.py +0 -0
  86. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/job_preparation.py +0 -0
  87. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/lineage.py +0 -0
  88. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/lineage_composite_formation.py +0 -0
  89. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/lineage_composites.py +0 -0
  90. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/metadata.py +0 -0
  91. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/put_composites.py +0 -0
  92. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/put_execution.py +0 -0
  93. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/register_preparation.py +0 -0
  94. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/register_preview_jobs.py +0 -0
  95. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/register_tag_push.py +0 -0
  96. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/registration_package.py +0 -0
  97. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/remote_job_uids.py +0 -0
  98. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/remote_registry.py +0 -0
  99. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/requests.py +0 -0
  100. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/results.py +0 -0
  101. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/runtime.py +0 -0
  102. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/secrets.py +0 -0
  103. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/session.py +0 -0
  104. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/source_resolution.py +0 -0
  105. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/targets.py +0 -0
  106. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/dag.py +0 -0
  107. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/db_status.py +0 -0
  108. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/diff.py +0 -0
  109. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/diff_engine.py +0 -0
  110. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/diff_graph.py +0 -0
  111. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/diff_refs.py +0 -0
  112. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/git_readiness.py +0 -0
  113. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/inputs.py +0 -0
  114. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/label.py +0 -0
  115. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/lineage.py +0 -0
  116. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/log.py +0 -0
  117. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/show.py +0 -0
  118. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/status.py +0 -0
  119. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/reproduce/__init__.py +0 -0
  120. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/reproduce/environment.py +0 -0
  121. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/reproduce/lookup.py +0 -0
  122. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/reproduce/requests.py +0 -0
  123. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/reproduce/results.py +0 -0
  124. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/reproduce/service.py +0 -0
  125. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/reproducibility/__init__.py +0 -0
  126. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/run/__init__.py +0 -0
  127. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/run/dag_references.py +0 -0
  128. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/run/dirty_tree_classify.py +0 -0
  129. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/run/dirty_tree_error.py +0 -0
  130. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/run/gitignore_suggest.py +0 -0
  131. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/run/output_followup.py +0 -0
  132. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/run/verbosity.py +0 -0
  133. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/workflow/__init__.py +0 -0
  134. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/workflow/requests.py +0 -0
  135. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/workflow/results.py +0 -0
  136. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/workflow/service.py +0 -0
  137. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/auth_store.py +0 -0
  138. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/__init__.py +0 -0
  139. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/local/__init__.py +0 -0
  140. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/local/plugin.py +0 -0
  141. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/osmo/__init__.py +0 -0
  142. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/osmo/config.py +0 -0
  143. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/osmo/export.py +0 -0
  144. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/osmo/host_execution.py +0 -0
  145. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/osmo/lineage.py +0 -0
  146. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/osmo/plugin.py +0 -0
  147. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/osmo/runtime_bundle.py +0 -0
  148. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/osmo/submit.py +0 -0
  149. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/osmo/workflow.py +0 -0
  150. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/__init__.py +0 -0
  151. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/_agent_names.py +0 -0
  152. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/collector.py +0 -0
  153. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/config.py +0 -0
  154. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/constants.py +0 -0
  155. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/env_contract.py +0 -0
  156. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/fragment.py +0 -0
  157. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/fragment_reconstituter.py +0 -0
  158. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/node_agent.py +0 -0
  159. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/plugin.py +0 -0
  160. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/proxy_fragments.py +0 -0
  161. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/roar_worker.py +0 -0
  162. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/runtime_hooks.py +0 -0
  163. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/s3_key_paths.py +0 -0
  164. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/submit.py +0 -0
  165. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/submit_context.py +0 -0
  166. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/__init__.py +0 -0
  167. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/_format.py +0 -0
  168. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/auth.py +0 -0
  169. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/build.py +0 -0
  170. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/config.py +0 -0
  171. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/dag.py +0 -0
  172. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/db.py +0 -0
  173. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/diff.py +0 -0
  174. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/env.py +0 -0
  175. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/export_registration_package.py +0 -0
  176. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/filter.py +0 -0
  177. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/init.py +0 -0
  178. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/init_agents.py +0 -0
  179. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/inputs.py +0 -0
  180. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/label.py +0 -0
  181. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/lineage.py +0 -0
  182. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/log.py +0 -0
  183. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/login.py +0 -0
  184. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/logout.py +0 -0
  185. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/osmo.py +0 -0
  186. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/pop.py +0 -0
  187. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/projects.py +0 -0
  188. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/reproduce.py +0 -0
  189. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/reset.py +0 -0
  190. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/session.py +0 -0
  191. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/show.py +0 -0
  192. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/telemetry.py +0 -0
  193. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/tracer.py +0 -0
  194. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/tui.py +0 -0
  195. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/whoami.py +0 -0
  196. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/workflow.py +0 -0
  197. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/context.py +0 -0
  198. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/decorators.py +0 -0
  199. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/__init__.py +0 -0
  200. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/bootstrap.py +0 -0
  201. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/canonical_session.py +0 -0
  202. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/digests.py +0 -0
  203. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/dto/__init__.py +0 -0
  204. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/dto/registration.py +0 -0
  205. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/exceptions.py +0 -0
  206. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/__init__.py +0 -0
  207. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/config.py +0 -0
  208. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/lineage.py +0 -0
  209. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/logger.py +0 -0
  210. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/presenter.py +0 -0
  211. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/provenance.py +0 -0
  212. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/registration.py +0 -0
  213. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/repositories.py +0 -0
  214. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/reproduction.py +0 -0
  215. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/run.py +0 -0
  216. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/services.py +0 -0
  217. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/telemetry.py +0 -0
  218. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/vcs.py +0 -0
  219. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/label_origins.py +0 -0
  220. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/logging.py +0 -0
  221. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/__init__.py +0 -0
  222. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/artifact.py +0 -0
  223. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/base.py +0 -0
  224. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/dag.py +0 -0
  225. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/dataset_identifier.py +0 -0
  226. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/glaas.py +0 -0
  227. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/job.py +0 -0
  228. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/lineage.py +0 -0
  229. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/provenance.py +0 -0
  230. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/session.py +0 -0
  231. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/telemetry.py +0 -0
  232. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/vcs.py +0 -0
  233. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/operation_metadata.py +0 -0
  234. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/session_hash.py +0 -0
  235. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/step_name.py +0 -0
  236. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/tracer_modes.py +0 -0
  237. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/validation.py +0 -0
  238. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/__init__.py +0 -0
  239. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/context.py +0 -0
  240. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/engine.py +0 -0
  241. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/hashing/__init__.py +0 -0
  242. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/hashing/backend.py +0 -0
  243. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/hashing/blake3.py +0 -0
  244. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/models.py +0 -0
  245. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/query_context.py +0 -0
  246. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/repositories/__init__.py +0 -0
  247. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/repositories/artifact.py +0 -0
  248. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/repositories/collection.py +0 -0
  249. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/repositories/composite.py +0 -0
  250. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/repositories/hash_cache.py +0 -0
  251. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/repositories/job.py +0 -0
  252. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/repositories/label.py +0 -0
  253. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/repositories/session.py +0 -0
  254. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/schema.py +0 -0
  255. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/services/__init__.py +0 -0
  256. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/services/hashing.py +0 -0
  257. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/services/lineage.py +0 -0
  258. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/services/session.py +0 -0
  259. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/step_priority.py +0 -0
  260. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/__init__.py +0 -0
  261. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/cluster/__init__.py +0 -0
  262. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/cluster/bridge.py +0 -0
  263. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/cluster/proxy.py +0 -0
  264. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/cluster/proxy_config.py +0 -0
  265. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/fragments/__init__.py +0 -0
  266. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/fragments/lineage.py +0 -0
  267. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/fragments/models.py +0 -0
  268. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/fragments/reconstitution.py +0 -0
  269. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/fragments/sessions.py +0 -0
  270. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/fragments/transport.py +0 -0
  271. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/framework/__init__.py +0 -0
  272. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/framework/contract.py +0 -0
  273. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/framework/planning.py +0 -0
  274. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/framework/registry.py +0 -0
  275. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/framework/runtime_imports.py +0 -0
  276. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/provenance/__init__.py +0 -0
  277. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/provenance/assembler.py +0 -0
  278. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/provenance/build_pip_collector.py +0 -0
  279. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/provenance/build_tool_collector.py +0 -0
  280. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/provenance/data_loader.py +0 -0
  281. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/provenance/file_filter.py +0 -0
  282. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/provenance/package_collector.py +0 -0
  283. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/provenance/process_summarizer.py +0 -0
  284. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/provenance/runtime_collector.py +0 -0
  285. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/provenance/service.py +0 -0
  286. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/recording/__init__.py +0 -0
  287. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/recording/dataset_identifier.py +0 -0
  288. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/recording/dataset_metadata.py +0 -0
  289. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/recording/dataset_profile.py +0 -0
  290. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/reproduction/__init__.py +0 -0
  291. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/reproduction/environment_setup.py +0 -0
  292. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/reproduction/installers.py +0 -0
  293. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/reproduction/pipeline_metadata.py +0 -0
  294. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/__init__.py +0 -0
  295. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/abi_probe.py +0 -0
  296. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/backup.py +0 -0
  297. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/driver_entrypoint.py +0 -0
  298. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/errors.py +0 -0
  299. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/host_execution.py +0 -0
  300. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/inject/__init__.py +0 -0
  301. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/inject/sitecustomize.py +0 -0
  302. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/inject/support.py +0 -0
  303. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/inject/tracker.py +0 -0
  304. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/lazy_install.py +0 -0
  305. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/resources.py +0 -0
  306. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/signal_handler.py +0 -0
  307. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/tracer_backends.py +0 -0
  308. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/tracer_banner.py +0 -0
  309. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/worker_bootstrap.py +0 -0
  310. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/filters/__init__.py +0 -0
  311. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/filters/files.py +0 -0
  312. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/filters/omit.py +0 -0
  313. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/glaas_auth.py +0 -0
  314. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/glaas_client.py +0 -0
  315. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/__init__.py +0 -0
  316. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/bootstrap.py +0 -0
  317. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/config/__init__.py +0 -0
  318. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/config/loader.py +0 -0
  319. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/config/raw.py +0 -0
  320. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/discovery.py +0 -0
  321. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/download/__init__.py +0 -0
  322. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/download/base.py +0 -0
  323. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/download/gcs.py +0 -0
  324. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/download/get.py +0 -0
  325. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/download/http.py +0 -0
  326. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/download/noop.py +0 -0
  327. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/download/s3.py +0 -0
  328. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/git/__init__.py +0 -0
  329. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/git/base.py +0 -0
  330. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/git/context.py +0 -0
  331. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/git/provider.py +0 -0
  332. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/glaas/__init__.py +0 -0
  333. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/glaas/auth.py +0 -0
  334. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/glaas/client.py +0 -0
  335. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/glaas/fragment_streamer.py +0 -0
  336. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/glaas/registration/__init__.py +0 -0
  337. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/glaas/registration/_artifact_ref.py +0 -0
  338. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/glaas/registration/artifact.py +0 -0
  339. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/glaas/registration/coordinator.py +0 -0
  340. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/glaas/registration/job.py +0 -0
  341. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/glaas/registration/session.py +0 -0
  342. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/glaas/transport.py +0 -0
  343. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/registry.py +0 -0
  344. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/resolution.py +0 -0
  345. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/storage/__init__.py +0 -0
  346. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/storage/base.py +0 -0
  347. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/storage/gcs.py +0 -0
  348. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/storage/memory.py +0 -0
  349. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/storage/noop.py +0 -0
  350. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/storage/s3.py +0 -0
  351. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/telemetry/__init__.py +0 -0
  352. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/telemetry/base.py +0 -0
  353. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/telemetry/wandb.py +0 -0
  354. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/presenters/__init__.py +0 -0
  355. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/presenters/console.py +0 -0
  356. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/presenters/dag_data_builder.py +0 -0
  357. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/presenters/dag_renderer.py +0 -0
  358. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/presenters/diff_renderer.py +0 -0
  359. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/presenters/formatting.py +0 -0
  360. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/presenters/null.py +0 -0
  361. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/presenters/run_report.py +0 -0
  362. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/presenters/spinner.py +0 -0
  363. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/presenters/terminal.py +0 -0
  364. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/require.py +0 -0
  365. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/telemetry/__init__.py +0 -0
  366. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/telemetry/_io.py +0 -0
  367. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/telemetry/capabilities.py +0 -0
  368. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/telemetry/config.py +0 -0
  369. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/telemetry/hooks.py +0 -0
  370. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/telemetry/install.py +0 -0
  371. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/telemetry/paths.py +0 -0
  372. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/telemetry/payload.py +0 -0
  373. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/telemetry/queue.py +0 -0
  374. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/telemetry/stats.py +0 -0
  375. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/telemetry/uploader.py +0 -0
  376. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/__init__.py +0 -0
  377. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/app.py +0 -0
  378. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/data.py +0 -0
  379. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/screens/__init__.py +0 -0
  380. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/screens/config_editor.py +0 -0
  381. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/screens/label_editor.py +0 -0
  382. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/screens/launcher.py +0 -0
  383. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/screens/log.py +0 -0
  384. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/screens/main.py +0 -0
  385. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/screens/search.py +0 -0
  386. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/screens/session_picker.py +0 -0
  387. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/tmux.py +0 -0
  388. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/widgets/__init__.py +0 -0
  389. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/widgets/detail.py +0 -0
  390. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/utils/__init__.py +0 -0
  391. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/utils/cloud.py +0 -0
  392. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/utils/git_url.py +0 -0
  393. {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/version_check.py +0 -0
  394. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/Cargo.lock +0 -0
  395. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/Cargo.toml +0 -0
  396. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/crates/artifact-hash-core/Cargo.toml +0 -0
  397. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/crates/artifact-hash-core/src/lib.rs +0 -0
  398. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/crates/artifact-hash-py/Cargo.toml +0 -0
  399. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/crates/artifact-hash-py/src/lib.rs +0 -0
  400. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/crates/tracer-fd/Cargo.toml +0 -0
  401. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/crates/tracer-fd/src/lib.rs +0 -0
  402. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/crates/tracer-runtime/Cargo.toml +0 -0
  403. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/crates/tracer-runtime/src/lib.rs +0 -0
  404. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/crates/tracer-schema/Cargo.toml +0 -0
  405. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/crates/tracer-schema/src/lib.rs +0 -0
  406. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/services/proxy/Cargo.lock +0 -0
  407. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/services/proxy/Cargo.toml +0 -0
  408. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/services/proxy/src/forward.rs +0 -0
  409. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/services/proxy/src/main.rs +0 -0
  410. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/services/proxy/src/s3.rs +0 -0
  411. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/common/Cargo.toml +0 -0
  412. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/common/src/lib.rs +0 -0
  413. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/probe/Cargo.toml +0 -0
  414. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/probe/rust-toolchain.toml +0 -0
  415. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/probe/src/main.rs +0 -0
  416. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/userspace/Cargo.toml +0 -0
  417. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/userspace/build.rs +0 -0
  418. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/userspace/src/attach.rs +0 -0
  419. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/userspace/src/bin/roard.rs +0 -0
  420. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/userspace/src/client.rs +0 -0
  421. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/userspace/src/daemon.rs +0 -0
  422. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/userspace/src/events.rs +0 -0
  423. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/userspace/src/ipc.rs +0 -0
  424. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/userspace/src/lib.rs +0 -0
  425. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/userspace/src/main.rs +0 -0
  426. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/userspace/src/state.rs +0 -0
  427. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/preload/Cargo.toml +0 -0
  428. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/preload/build.rs +0 -0
  429. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/preload/src/bin/io_fixture.rs +0 -0
  430. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/preload/src/interpose.c +0 -0
  431. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/preload/src/ipc.rs +0 -0
  432. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/preload/src/lib.rs +0 -0
  433. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/preload/src/main.rs +0 -0
  434. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/preload/tests/comprehensive.rs +0 -0
  435. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/preload/tests/standalone.rs +0 -0
  436. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ptrace/Cargo.toml +0 -0
  437. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ptrace/rustfmt.toml +0 -0
  438. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ptrace/src/arch.rs +0 -0
  439. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ptrace/src/main.rs +0 -0
  440. {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ptrace/src/seccomp.rs +0 -0
  441. {roar_cli-0.3.7 → roar_cli-0.4.1}/scripts/sync_packaged_rust_artifacts.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: roar-cli
3
- Version: 0.3.7
3
+ Version: 0.4.1
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: Intended Audience :: Science/Research
@@ -34,6 +34,7 @@ Requires-Dist: ruff>=0.8.0 ; extra == 'dev'
34
34
  Requires-Dist: mypy>=1.13.0 ; extra == 'dev'
35
35
  Requires-Dist: boto3>=1.28.0 ; extra == 'dev'
36
36
  Requires-Dist: google-cloud-storage>=2.10.0 ; extra == 'dev'
37
+ Requires-Dist: huggingface-hub>=0.20.0 ; extra == 'dev'
37
38
  Provides-Extra: dev
38
39
  License-File: LICENSE
39
40
  Summary: Reproducibility and provenance tracker for ML training pipelines
@@ -5,7 +5,7 @@ build-backend = "maturin"
5
5
 
6
6
  [project]
7
7
  name = "roar-cli"
8
- version = "0.3.7"
8
+ version = "0.4.1"
9
9
  description = "Reproducibility and provenance tracker for ML training pipelines"
10
10
  authors = [
11
11
  { name="TReqs Team", email="info@treqs.ai" }
@@ -68,6 +68,7 @@ dev = [
68
68
  "mypy>=1.13.0",
69
69
  "boto3>=1.28.0",
70
70
  "google-cloud-storage>=2.10.0",
71
+ "huggingface_hub>=0.20.0",
71
72
  ]
72
73
 
73
74
  [project.scripts]
@@ -2,6 +2,7 @@
2
2
 
3
3
  import json
4
4
  import re
5
+ import sqlite3
5
6
  from pathlib import Path
6
7
  from typing import Any, ClassVar
7
8
 
@@ -18,6 +19,7 @@ class ExperimentTrackerAnalyzer(Analyzer):
18
19
  TRACKER_PATTERNS: ClassVar[dict[str, list[str]]] = {
19
20
  "wandb": ["wandb/", ".wandb"],
20
21
  "mlflow": ["mlruns/", "mlartifacts/"],
22
+ "trackio": ["huggingface/trackio", "/trackio/"],
21
23
  "neptune": [".neptune/"],
22
24
  "tensorboard": ["/runs/", "events.out.tfevents"],
23
25
  }
@@ -72,7 +74,12 @@ class ExperimentTrackerAnalyzer(Analyzer):
72
74
  for tracker in trackers_found:
73
75
  run_info = self._extract_run_info(tracker, written, env)
74
76
  if run_info:
75
- results["runs"].append(run_info)
77
+ # trackio reports one run per project DB (a run may touch
78
+ # several); the other trackers return a single run dict.
79
+ if isinstance(run_info, list):
80
+ results["runs"].extend(run_info)
81
+ else:
82
+ results["runs"].append(run_info)
76
83
 
77
84
  # Add ignore patterns for this tracker
78
85
  for pattern in self.IGNORE_PATTERNS:
@@ -88,18 +95,26 @@ class ExperimentTrackerAnalyzer(Analyzer):
88
95
  results["ignore_patterns"].extend(["mlruns/*", "mlartifacts/*"])
89
96
  if "neptune" in trackers_found:
90
97
  results["ignore_patterns"].append(".neptune/*")
98
+ if "trackio" in trackers_found:
99
+ results["ignore_patterns"].append("*/trackio/*")
91
100
 
92
101
  # Dedupe
93
102
  results["ignore_patterns"] = sorted(set(results["ignore_patterns"]))
94
103
 
95
104
  return results if results["trackers_detected"] else None
96
105
 
97
- def _extract_run_info(self, tracker: str, written_files: list, env: dict) -> dict | None:
98
- """Extract run URL and metadata for a specific tracker."""
106
+ def _extract_run_info(self, tracker: str, written_files: list, env: dict) -> dict | list | None:
107
+ """Extract run URL and metadata for a specific tracker.
108
+
109
+ Most trackers return a single run dict; ``trackio`` returns a list of
110
+ per-project run dicts (or ``None`` when nothing usable was found).
111
+ """
99
112
  if tracker == "wandb":
100
113
  return self._extract_wandb_info(written_files, env)
101
114
  elif tracker == "mlflow":
102
115
  return self._extract_mlflow_info(written_files, env)
116
+ elif tracker == "trackio":
117
+ return self._extract_trackio_info(written_files, env)
103
118
  elif tracker == "neptune":
104
119
  return self._extract_neptune_info(written_files, env)
105
120
  return None
@@ -198,6 +213,91 @@ class ExperimentTrackerAnalyzer(Analyzer):
198
213
 
199
214
  return info if len(info) > 1 else None
200
215
 
216
+ def _extract_trackio_info(self, written_files: list, env: dict) -> list | None:
217
+ """Extract trackio run info + the hosted-dashboard URL — scrape only.
218
+
219
+ trackio stores one SQLite DB per project at ``.../huggingface/trackio/
220
+ <project>.db`` and, when a run syncs to a HF Space, records the Space in
221
+ ``project_metadata`` (``key='space_id'``). We read that link + the run
222
+ identity, exactly as the W&B extractor reads wandb's on-disk run URL — no
223
+ roar-side config, no env, and **never the metrics**: TReqs stores no
224
+ customer data, so the DAG carries a link to the externally-hosted
225
+ experiment, and the metrics live on the dashboard.
226
+
227
+ Returns ONE record per project DB (never splicing one project's identity
228
+ onto another's Space), or ``None`` if no DB yielded anything usable. Each
229
+ record's URL is ``https://huggingface.co/spaces/<space_id>?project=<project>``.
230
+ (``env`` is unused — the space comes from what trackio itself persisted.)
231
+ """
232
+ del env
233
+ db_paths = sorted({p for p in written_files if "trackio/" in p and p.endswith(".db")})
234
+
235
+ runs: list[dict[str, Any]] = []
236
+ for db_path in db_paths:
237
+ path = Path(db_path)
238
+ if not path.exists():
239
+ continue
240
+ info: dict[str, Any] = {"tracker": "trackio", "project": path.stem}
241
+ try:
242
+ con = sqlite3.connect(f"file:{db_path}?mode=ro", uri=True)
243
+ except sqlite3.Error:
244
+ continue
245
+ try:
246
+ # Two INDEPENDENT lookups: an older/imported trackio schema may
247
+ # lack a ``run_id`` column or the ``project_metadata`` table, so
248
+ # a failure of one must not discard the other.
249
+ run = self._trackio_run_identity(con)
250
+ space = self._trackio_space_id(con)
251
+ finally:
252
+ con.close()
253
+
254
+ if run:
255
+ info["run_id"], info["run_name"] = run
256
+ if space:
257
+ info["space_id"] = space
258
+ info["url"] = f"https://huggingface.co/spaces/{space}?project={info['project']}"
259
+
260
+ # Keep only DBs that yielded a run identity and/or a hosted Space
261
+ # (more than the always-present tracker+project keys).
262
+ if len(info) > 2:
263
+ runs.append(info)
264
+
265
+ return runs or None
266
+
267
+ @staticmethod
268
+ def _trackio_run_identity(con: "sqlite3.Connection") -> tuple | None:
269
+ """``(run_id, run_name)`` of the most recent metric row, tolerating
270
+ older schemas whose ``metrics`` table lacks a ``run_id`` column (trackio
271
+ produces these when importing TensorBoard/older runs)."""
272
+ try:
273
+ cols = {row[1] for row in con.execute("PRAGMA table_info(metrics)").fetchall()}
274
+ except sqlite3.Error:
275
+ return None
276
+ if not cols or not ({"run_id", "run_name"} & cols):
277
+ return None
278
+ run_id_expr = "run_id" if "run_id" in cols else "NULL"
279
+ run_name_expr = "run_name" if "run_name" in cols else "NULL"
280
+ try:
281
+ row = con.execute(
282
+ f"SELECT {run_id_expr}, {run_name_expr} FROM metrics ORDER BY rowid DESC LIMIT 1"
283
+ ).fetchone()
284
+ except sqlite3.Error:
285
+ return None
286
+ if not row or (row[0] is None and row[1] is None):
287
+ return None
288
+ return row[0], row[1]
289
+
290
+ @staticmethod
291
+ def _trackio_space_id(con: "sqlite3.Connection") -> str | None:
292
+ """The hosted HF Space id trackio persisted once a run synced, or None."""
293
+ try:
294
+ row = con.execute(
295
+ "SELECT value FROM project_metadata WHERE key = 'space_id' LIMIT 1"
296
+ ).fetchone()
297
+ except sqlite3.Error:
298
+ return None
299
+ return row[0] if row and row[0] else None
300
+
201
301
  def _extract_mlflow_info(self, written_files: list, env: dict) -> dict | None:
202
302
  """Extract MLflow run info from local files."""
203
303
  info = {"tracker": "mlflow"}
@@ -23,3 +23,4 @@ class GetRequest:
23
23
  step_name: str | None = None
24
24
  limit: int | None = None # download only the first N data files (subset get)
25
25
  full_anchor: bool = False # re-hash non-LFS identity files past the budget
26
+ cache: str | None = None # fetch bytes from this mirror; record `source` as canonical
@@ -12,6 +12,7 @@ from ...core.operation_metadata import build_operation_metadata_json
12
12
  from ...db.context import create_database_context
13
13
  from ...execution.recording import LocalJobRecorder, LocalRecordedArtifact
14
14
  from ...integrations.download import parse_source, resolve_download_backend
15
+ from ...integrations.download.base import DownloadError
15
16
  from .requests import GetRequest
16
17
  from .results import GetDownloadedFile, GetResponse
17
18
  from .transfer import GetService, GetTransferResult
@@ -22,10 +23,27 @@ def get_artifacts(request: GetRequest) -> GetResponse:
22
23
  bootstrap(request.roar_dir)
23
24
  logger = get_logger()
24
25
 
25
- parsed_source = parse_source(request.source)
26
- backend = resolve_download_backend(request.source)
26
+ parsed_source = parse_source(request.source) # canonical — always what we RECORD
27
+ # Fetch location: the mirror (`--cache`) when given, else the canonical source.
28
+ # Recording below always uses the canonical `parsed_source`, so the artifact's
29
+ # source_url / the AI-BOM downloadLocation stay the public URL, not the mirror.
30
+ fetch_url = request.cache or request.source
31
+ backend = resolve_download_backend(fetch_url)
32
+ fetch_parsed = parse_source(fetch_url)
27
33
  repo_root = request.repo_root or request.cwd
28
- is_prefix = request.source.rstrip("/") != request.source or parsed_source.is_prefix
34
+ is_prefix = fetch_url.rstrip("/") != fetch_url or fetch_parsed.is_prefix
35
+
36
+ # A `--cache` mirror is only integrity-bound to the canonical identity when a
37
+ # `--hash` is given. Without it, the mirror's bytes are recorded under the
38
+ # canonical source_url unverified — warn so provenance isn't silently trusted.
39
+ if request.cache and not request.expected_hash:
40
+ logger.warning(
41
+ "--cache %s used without --hash: the mirror's bytes are not integrity-checked "
42
+ "against the canonical source %s, yet are recorded under it. Pass --hash "
43
+ "<digest> to bind the download to a known hash.",
44
+ request.cache,
45
+ request.source,
46
+ )
29
47
 
30
48
  git_commit = None
31
49
  git_branch = None
@@ -88,20 +106,57 @@ def get_artifacts(request: GetRequest) -> GetResponse:
88
106
  pass
89
107
 
90
108
  with create_database_context(request.roar_dir) as db_ctx:
91
- service = GetService(
92
- backend=backend,
93
- source=parsed_source,
94
- repo_root=repo_root,
95
- )
96
109
  t0 = time.time()
97
- transfer_result = service.get(
98
- destination=request.destination,
99
- expected_hash=request.expected_hash,
100
- dry_run=request.dry_run,
101
- force=request.force,
102
- is_prefix=is_prefix,
103
- limit=request.limit,
104
- )
110
+ fetched_from_cache = False
111
+ try:
112
+ transfer_result = GetService(
113
+ backend=backend,
114
+ source=fetch_parsed,
115
+ repo_root=repo_root,
116
+ ).get(
117
+ destination=request.destination,
118
+ expected_hash=request.expected_hash,
119
+ dry_run=request.dry_run,
120
+ force=request.force,
121
+ is_prefix=is_prefix,
122
+ limit=request.limit,
123
+ )
124
+ fetched_from_cache = bool(request.cache)
125
+ # The transfer layer REPORTS a hash mismatch (and other soft failures)
126
+ # as success=False rather than raising, so trigger the same cache
127
+ # fallback here — otherwise a corrupt mirror hard-fails the whole get
128
+ # even when the canonical source would succeed (the documented behavior).
129
+ if request.cache and not transfer_result.dry_run and not transfer_result.success:
130
+ raise DownloadError(transfer_result.error or "cache fetch was unsuccessful")
131
+ except (DownloadError, FileNotFoundError, ValueError, OSError) as exc:
132
+ # A `--cache` mirror is best-effort: on miss / unreachable / hash
133
+ # mismatch, fall back to the canonical source (still hash-verified via
134
+ # --hash if given, and by content-addressing at reproduce time). A get
135
+ # without a cache re-raises unchanged.
136
+ if not request.cache:
137
+ raise
138
+ logger.warning(
139
+ "cache fetch from %s failed (%s); falling back to canonical source %s",
140
+ request.cache,
141
+ exc,
142
+ request.source,
143
+ )
144
+ fetched_from_cache = False
145
+ canonical_is_prefix = (
146
+ request.source.rstrip("/") != request.source or parsed_source.is_prefix
147
+ )
148
+ transfer_result = GetService(
149
+ backend=resolve_download_backend(request.source),
150
+ source=parsed_source,
151
+ repo_root=repo_root,
152
+ ).get(
153
+ destination=request.destination,
154
+ expected_hash=request.expected_hash,
155
+ dry_run=request.dry_run,
156
+ force=request.force,
157
+ is_prefix=canonical_is_prefix,
158
+ limit=request.limit,
159
+ )
105
160
  download_duration = time.time() - t0
106
161
 
107
162
  result = _materialize_get_result(
@@ -114,6 +169,8 @@ def get_artifacts(request: GetRequest) -> GetResponse:
114
169
  git_repo=git_repo_url,
115
170
  duration_seconds=download_duration,
116
171
  backend=backend,
172
+ fetched_from_cache=fetched_from_cache,
173
+ fetch_url=fetch_url,
117
174
  )
118
175
 
119
176
  git_tag_name = None
@@ -145,6 +202,26 @@ def get_artifacts(request: GetRequest) -> GetResponse:
145
202
  )
146
203
 
147
204
 
205
+ def _canonical_source_url(file_info, request: GetRequest, fetch_url, fetched_from_cache: bool):
206
+ """The canonical (recorded) URL for one downloaded file.
207
+
208
+ When the bytes came from the canonical source (no ``--cache``, or a cache
209
+ miss/mismatch that fell back), each file's own fetch URL is already canonical.
210
+ When they came from a ``--cache`` mirror, remap each file's mirror URL back
211
+ onto the canonical prefix, so a PREFIX get records each file's own canonical
212
+ object (``s3://canon/data/a.pt``) rather than the bare prefix for every file.
213
+ """
214
+ remote_url = file_info.remote_url or ""
215
+ if not fetched_from_cache:
216
+ return remote_url or request.source
217
+ # Fetched from the mirror: swap the mirror prefix for the canonical one.
218
+ if fetch_url and remote_url.startswith(fetch_url) and remote_url != fetch_url:
219
+ suffix = remote_url[len(fetch_url) :]
220
+ return request.source.rstrip("/") + "/" + suffix.lstrip("/")
221
+ # Single-file cache (or an unmappable URL): the file itself IS the canonical source.
222
+ return request.source
223
+
224
+
148
225
  def _materialize_get_result(
149
226
  *,
150
227
  db_ctx,
@@ -156,6 +233,8 @@ def _materialize_get_result(
156
233
  git_repo: str | None = None,
157
234
  duration_seconds: float = 0.0,
158
235
  backend=None,
236
+ fetched_from_cache: bool = False,
237
+ fetch_url: str | None = None,
159
238
  ) -> GetResponse:
160
239
  if transfer_result.dry_run or not transfer_result.success:
161
240
  return GetResponse(
@@ -204,11 +283,18 @@ def _materialize_get_result(
204
283
  # downloaded files are the composite's components.
205
284
  output_artifacts: list[LocalRecordedArtifact] = []
206
285
  else:
286
+ # Record the canonical source on each downloaded artifact so it is a
287
+ # SOURCE node with a known origin (source_type/source_url), not a bare
288
+ # local file. This is what a downstream AI-BOM derives `downloadLocation`
289
+ # from — so it must be each file's OWN canonical URL, not a shared prefix.
290
+ source_type = parsed_source.scheme or None
207
291
  output_artifacts = [
208
292
  LocalRecordedArtifact(
209
293
  path=file_info.local_path,
210
294
  hashes={"blake3": str(file_info.hash)},
211
295
  size=int(file_info.size or 0),
296
+ source_type=source_type,
297
+ source_url=_canonical_source_url(file_info, request, fetch_url, fetched_from_cache),
212
298
  )
213
299
  for file_info in transfer_result.downloaded_files
214
300
  ]
@@ -427,6 +513,9 @@ def _build_get_command(request: GetRequest) -> str:
427
513
  user typed.
428
514
  """
429
515
  parts = ["roar get", request.source]
516
+ if request.cache:
517
+ # Record the mirror so a reproduce replays cache-first-then-canonical.
518
+ parts.append(f"--cache {request.cache}")
430
519
  if request.limit is not None:
431
520
  parts.append(f"--limit {request.limit}")
432
521
  if request.step_name:
@@ -100,7 +100,9 @@ def prepare_put_execution(
100
100
  )
101
101
 
102
102
  destination_type = _destination_type(destination)
103
- composite_source_type = destination_type if destination_type in {"s3", "gs", "https"} else None
103
+ composite_source_type = (
104
+ destination_type if destination_type in {"s3", "gs", "https", "hf"} else None
105
+ )
104
106
 
105
107
  return PreparedPutExecution(
106
108
  glaas_client=runtime.glaas_client,
@@ -222,8 +222,15 @@ class RegisterService:
222
222
  skip_confirmation: bool,
223
223
  confirm_callback: Callable[[list[str]], bool] | None,
224
224
  prepared: PreparedRegisterExecution,
225
+ composite_leaf_hashes: frozenset[str] = frozenset(),
225
226
  ) -> RegisterResult:
226
- """Register already-collected local lineage with GLaaS."""
227
+ """Register already-collected local lineage with GLaaS.
228
+
229
+ ``composite_leaf_hashes`` are true composite-member hashes subsumed into a view
230
+ edge (see ``_prepare_view_edges_for_lineage``) — they have no session-scoped edge
231
+ on GLaaS, so they're excluded from label sync even though they still appear in
232
+ ``lineage.artifacts`` for ordinary artifact registration.
233
+ """
227
234
  self._logger.debug(
228
235
  "Collected lineage: %d jobs, %d artifacts",
229
236
  len(lineage.jobs),
@@ -276,6 +283,12 @@ class RegisterService:
276
283
  omit_filter=omit_filter,
277
284
  )
278
285
 
286
+ label_artifacts = (
287
+ [a for a in lineage.artifacts if a.get("hash") not in composite_leaf_hashes]
288
+ if composite_leaf_hashes
289
+ else lineage.artifacts
290
+ )
291
+
279
292
  registration_jobs = order_jobs_for_registration(
280
293
  normalize_jobs_for_registration(lineage.jobs)
281
294
  )
@@ -344,7 +357,7 @@ class RegisterService:
344
357
  session_id=session_id,
345
358
  session_hash=finalized_session_hash,
346
359
  jobs=remote_registration_jobs,
347
- artifacts=lineage.artifacts,
360
+ artifacts=label_artifacts,
348
361
  errors=registration_errors,
349
362
  )
350
363
  elif batch_result.jobs_failed == 0 and batch_result.links_failed == 0:
@@ -391,7 +404,7 @@ class RegisterService:
391
404
  session_id=session_id,
392
405
  session_hash=finalized_session_hash,
393
406
  jobs=remote_registration_jobs,
394
- artifacts=lineage.artifacts,
407
+ artifacts=label_artifacts,
395
408
  errors=registration_errors,
396
409
  )
397
410
  except Exception as e:
@@ -411,7 +424,7 @@ class RegisterService:
411
424
  session_id=session_id,
412
425
  session_hash=finalized_session_hash,
413
426
  jobs=remote_registration_jobs,
414
- artifacts=lineage.artifacts,
427
+ artifacts=label_artifacts,
415
428
  errors=registration_errors,
416
429
  )
417
430
  else:
@@ -456,7 +469,7 @@ class RegisterService:
456
469
  ),
457
470
  db_ctx=db_ctx,
458
471
  session_id=session_id,
459
- label_artifacts=lineage.artifacts,
472
+ label_artifacts=label_artifacts,
460
473
  )
461
474
  else:
462
475
  batch_result = register_publish_lineage(
@@ -473,7 +486,7 @@ class RegisterService:
473
486
  ),
474
487
  db_ctx=None,
475
488
  session_id=None,
476
- label_artifacts=lineage.artifacts,
489
+ label_artifacts=label_artifacts,
477
490
  )
478
491
  registration_errors.extend(batch_result.errors)
479
492
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import json
5
6
  import time
6
7
  from dataclasses import dataclass
7
8
  from typing import Any
@@ -329,14 +330,33 @@ def prepare_batch_registration_artifacts(
329
330
  except (TypeError, ValueError):
330
331
  size = 0
331
332
 
332
- prepared.append(
333
- {
334
- "hashes": hashes,
335
- "size": size,
336
- "source_type": normalize_registration_source_type(artifact.get("source_type")),
337
- "session_hash": session_hash,
338
- }
339
- )
333
+ entry = {
334
+ "hashes": hashes,
335
+ "size": size,
336
+ "source_type": normalize_registration_source_type(artifact.get("source_type")),
337
+ "session_hash": session_hash,
338
+ }
339
+
340
+ # Carry the artifact's source URL into its registration metadata so GLaaS
341
+ # can emit the AI-BOM `downloadLocation` external reference. The batch
342
+ # payload previously dropped `source_url`, so source-tracked inputs
343
+ # (e.g. s3://…) reached GLaaS with a sourceType but no distribution URL.
344
+ source_url = artifact.get("source_url")
345
+ if source_url and entry["source_type"]:
346
+ existing = artifact.get("metadata")
347
+ if isinstance(existing, str):
348
+ try:
349
+ meta = json.loads(existing)
350
+ except (ValueError, TypeError):
351
+ meta = {}
352
+ elif isinstance(existing, dict):
353
+ meta = dict(existing)
354
+ else:
355
+ meta = {}
356
+ meta.setdefault("source_url", source_url)
357
+ entry["metadata"] = json.dumps(meta)
358
+
359
+ prepared.append(entry)
340
360
 
341
361
  return prepared
342
362
 
@@ -496,7 +496,7 @@ def _load_remote_job_uid_mapping(*, roar_dir: Path, session_id: Any) -> dict[str
496
496
 
497
497
  def _prepare_view_edges_for_lineage(
498
498
  *, roar_dir: Path, lineage: Any, logger: Any
499
- ) -> dict[str, list[Any]]:
499
+ ) -> tuple[dict[str, list[Any]], set[str]]:
500
500
  """Compute consumes/produces view edges per job and prune the subsumed leaves in-place.
501
501
 
502
502
  A job that read part of a dataset gets a ``consumes`` view edge over its inputs; a job
@@ -505,15 +505,21 @@ def _prepare_view_edges_for_lineage(
505
505
  and any anchor linked as a plain input/output — are removed from the bundle so the job
506
506
  links the dataset *view* (job -> view -> anchor -> leaves), not the loose leaves or the
507
507
  anchor directly. The anchor composite stays in ``lineage.artifacts`` (already
508
- collected) so it is still registered. Returns ``{job_uid: [view_edge, ...]}`` to push
509
- after the main registration.
508
+ collected) so it is still registered.
509
+
510
+ Returns ``({job_uid: [view_edge, ...]}, composite_leaf_hashes)``: the view edges to
511
+ push after the main registration, and the union of true component/leaf hashes (never
512
+ the anchor's own hash) subsumed across all jobs — a leaf has no session-scoped edge on
513
+ GLaaS, so the caller uses this set to keep leaf label/tag documents out of publish-time
514
+ label sync too.
510
515
  """
511
516
  from .view_edges import resolve_view_edges_for_job
512
517
 
513
518
  jobs = getattr(lineage, "jobs", []) or []
514
519
  if not jobs:
515
- return {}
520
+ return {}, set()
516
521
  view_edges_by_job: dict[str, list[Any]] = {}
522
+ composite_leaf_hashes: set[str] = set()
517
523
  with create_database_context(roar_dir) as db:
518
524
  for job in jobs:
519
525
  if not isinstance(job, dict):
@@ -530,7 +536,7 @@ def _prepare_view_edges_for_lineage(
530
536
  hashes = list(job.get(hashes_key) or [])
531
537
  if not hashes:
532
538
  continue
533
- resolved, prune = resolve_view_edges_for_job(
539
+ resolved, prune, leaf_hashes = resolve_view_edges_for_job(
534
540
  db_ctx=db, input_hashes=hashes, relation=relation
535
541
  )
536
542
  if not resolved:
@@ -539,9 +545,10 @@ def _prepare_view_edges_for_lineage(
539
545
  job[hashes_key] = [h for h in hashes if h not in prune]
540
546
  if isinstance(job.get(items_key), list):
541
547
  job[items_key] = [i for i in job[items_key] if i.get("hash") not in prune]
548
+ composite_leaf_hashes |= leaf_hashes
542
549
  if edges:
543
550
  view_edges_by_job[str(job_uid)] = edges
544
- return view_edges_by_job
551
+ return view_edges_by_job, composite_leaf_hashes
545
552
 
546
553
 
547
554
  def register_lineage_target(request: RegisterLineageRequest) -> RegisterLineageResponse:
@@ -628,13 +635,15 @@ def register_lineage_target(request: RegisterLineageRequest) -> RegisterLineageR
628
635
  # bloom over the touched leaves) and prune the subsumed leaves from the bundle.
629
636
  # Pushed after the main registration. Best-effort.
630
637
  view_edges_by_job: dict[str, list[Any]] = {}
638
+ composite_leaf_hashes: frozenset[str] = frozenset()
631
639
  if not request.dry_run:
632
640
  try:
633
- view_edges_by_job = _prepare_view_edges_for_lineage(
641
+ view_edges_by_job, leaf_hashes = _prepare_view_edges_for_lineage(
634
642
  roar_dir=request.roar_dir,
635
643
  lineage=collected_lineage.lineage,
636
644
  logger=logger,
637
645
  )
646
+ composite_leaf_hashes = frozenset(leaf_hashes)
638
647
  except Exception as exc: # view-edge prep is best-effort
639
648
  logger.debug("view-edge preparation skipped: %s", exc)
640
649
 
@@ -728,6 +737,7 @@ def register_lineage_target(request: RegisterLineageRequest) -> RegisterLineageR
728
737
  skip_confirmation=request.skip_confirmation,
729
738
  confirm_callback=request.confirm_callback,
730
739
  prepared=prepared,
740
+ composite_leaf_hashes=composite_leaf_hashes,
731
741
  )
732
742
 
733
743
  # Push the consumes view edges now that the jobs + the anchor composite are
@@ -115,16 +115,23 @@ def resolve_view_edges_for_job(
115
115
  db_ctx: Any,
116
116
  input_hashes: list[str],
117
117
  relation: Literal["consumes", "produces"] = "consumes",
118
- ) -> tuple[list[dict[str, Any]], set[str]]:
118
+ ) -> tuple[list[dict[str, Any]], set[str], set[str]]:
119
119
  """Resolve a job's leaf *hashes* into view edges + hashes to prune.
120
120
 
121
121
  Works from the collected-lineage hashes (not artifact ids). ``relation`` is the side
122
122
  being resolved: ``consumes`` over a job's input hashes (a run that read part of a
123
123
  dataset) or ``produces`` over its output hashes (a run that wrote one). The resolution
124
124
  is identical either way — each leaf is matched to the anchor composite(s) that carry
125
- it as a component. Returns ``(view_edges, prune_hashes)`` — the second being the leaf
126
- hashes that collapse into a view edge plus any anchor composite hash linked as a plain
127
- input/output (the view edge replaces it).
125
+ it as a component. Returns ``(view_edges, prune_hashes, leaf_hashes)``:
126
+
127
+ - ``prune_hashes``: the leaf hashes that collapse into a view edge plus any anchor
128
+ composite hash linked as a plain input/output (the view edge replaces it). Used to
129
+ drop these from a job's plain input/output edges.
130
+ - ``leaf_hashes``: strictly the true component/leaf hashes subsumed into a view edge
131
+ (a subset of ``prune_hashes`` that excludes a directly-linked anchor's own hash).
132
+ A composite member never has its own session-scoped edge on GLaaS — it has no
133
+ standing to carry its own labels/tags either, so callers use this set to keep
134
+ per-leaf label/tag documents out of publish-time label sync.
128
135
 
129
136
  BOUNDARY: matching uses ``find_by_component_digest``, which only knows the anchor's
130
137
  *stored* components (capped at ``_MAX_STORED_COMPONENTS`` = 1000). For a dataset with
@@ -138,7 +145,7 @@ def resolve_view_edges_for_job(
138
145
  artifacts_repo: Any = optional_repo(db_ctx, "artifacts")
139
146
  composites_repo: Any = optional_repo(db_ctx, "composites")
140
147
  if artifacts_repo is None or composites_repo is None:
141
- return [], set()
148
+ return [], set(), set()
142
149
 
143
150
  # anchor_id -> {"algorithm": str, "leaves": set, "shards": set}
144
151
  by_anchor: dict[str, dict[str, Any]] = {}
@@ -174,6 +181,7 @@ def resolve_view_edges_for_job(
174
181
  _attribute(blake3_digest, "blake3", digest)
175
182
 
176
183
  view_edges: list[dict[str, Any]] = []
184
+ leaf_hashes: set[str] = set()
177
185
  for anchor_id, bucket in by_anchor.items():
178
186
  anchor = artifacts_repo.get(anchor_id)
179
187
  anchor_digest = _primary_composite_digest(anchor)
@@ -189,8 +197,9 @@ def resolve_view_edges_for_job(
189
197
  )
190
198
  )
191
199
  prune |= bucket["shards"]
200
+ leaf_hashes |= bucket["shards"]
192
201
 
193
- return view_edges, prune
202
+ return view_edges, prune, leaf_hashes
194
203
 
195
204
 
196
205
  def _primary_composite_digest(artifact: dict[str, Any] | None) -> str | None: