roar-cli 0.4.0__tar.gz → 0.4.2__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 (461) hide show
  1. {roar_cli-0.4.0 → roar_cli-0.4.2}/PKG-INFO +2 -1
  2. {roar_cli-0.4.0 → roar_cli-0.4.2}/pyproject.toml +3 -1
  3. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/analyzers/experiment_trackers.py +103 -3
  4. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/get/requests.py +1 -0
  5. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/get/service.py +105 -16
  6. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/put_execution.py +51 -5
  7. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/put_preparation.py +3 -1
  8. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/registration.py +28 -8
  9. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/registration_package.py +34 -0
  10. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/service.py +12 -0
  11. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/reproduce/requests.py +5 -0
  12. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/reproduce/service.py +127 -1
  13. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/reproducibility/report.py +18 -0
  14. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/run/execution.py +26 -0
  15. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/run/service.py +5 -0
  16. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/system_labels.py +4 -0
  17. roar_cli-0.4.2/roar/backends/k8s/attach.py +402 -0
  18. roar_cli-0.4.2/roar/backends/k8s/bundles.py +135 -0
  19. roar_cli-0.4.2/roar/backends/k8s/config.py +194 -0
  20. roar_cli-0.4.2/roar/backends/k8s/fragment_reconstituter.py +261 -0
  21. roar_cli-0.4.2/roar/backends/k8s/host_execution.py +196 -0
  22. roar_cli-0.4.2/roar/backends/k8s/lineage.py +144 -0
  23. roar_cli-0.4.2/roar/backends/k8s/manifest.py +756 -0
  24. roar_cli-0.4.2/roar/backends/k8s/mount_map.py +182 -0
  25. roar_cli-0.4.2/roar/backends/k8s/object_io.py +220 -0
  26. roar_cli-0.4.2/roar/backends/k8s/plugin.py +114 -0
  27. roar_cli-0.4.2/roar/backends/k8s/pod_entry.py +366 -0
  28. roar_cli-0.4.2/roar/backends/k8s/rayjob.py +230 -0
  29. roar_cli-0.4.2/roar/backends/k8s/secret_cleanup.py +105 -0
  30. roar_cli-0.4.2/roar/backends/k8s/submit.py +440 -0
  31. roar_cli-0.4.2/roar/backends/k8s/webhook.py +313 -0
  32. roar_cli-0.4.2/roar/backends/k8s/workload_wait.py +133 -0
  33. roar_cli-0.4.2/roar/backends/osmo/export.py +48 -0
  34. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/ray/fragment_reconstituter.py +22 -0
  35. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/ray/roar_worker.py +86 -33
  36. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/ray/runtime_hooks.py +67 -3
  37. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/ray/submit.py +2 -1
  38. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/command_registry.py +3 -0
  39. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/get.py +11 -0
  40. roar_cli-0.4.2/roar/cli/commands/k8s.py +226 -0
  41. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/proxy.py +7 -3
  42. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/put.py +14 -2
  43. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/register.py +98 -31
  44. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/reproduce.py +16 -0
  45. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/scope.py +16 -6
  46. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/context.py +15 -0
  47. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/publish_intent.py +5 -0
  48. roar_cli-0.4.2/roar/cli/templates/agents/SKILL.md.tmpl +198 -0
  49. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/templates/agents/agents_section.md.tmpl +3 -0
  50. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/models/provenance.py +4 -0
  51. {roar_cli-0.4.0/roar/backends/osmo → roar_cli-0.4.2/roar/execution/fragments}/export.py +32 -13
  52. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/fragments/lineage.py +12 -6
  53. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/fragments/models.py +18 -0
  54. roar_cli-0.4.2/roar/execution/fragments/sessions.py +83 -0
  55. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/fragments/transport.py +19 -2
  56. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/framework/registry.py +63 -2
  57. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/provenance/assembler.py +5 -0
  58. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/provenance/runtime_collector.py +74 -0
  59. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/runtime/proxy_resource.py +22 -2
  60. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/runtime/tracer.py +1 -1
  61. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/runtime/worker_bootstrap.py +22 -0
  62. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/download/hf.py +9 -3
  63. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/glaas/__init__.py +1 -0
  64. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/glaas/client.py +5 -0
  65. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/glaas/fragment_streamer.py +66 -3
  66. roar_cli-0.4.2/roar/integrations/storage/hf.py +146 -0
  67. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/storage/publish.py +5 -0
  68. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/presenters/show_renderer.py +8 -0
  69. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/publish_auth.py +71 -5
  70. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/scope_config.py +4 -0
  71. roar_cli-0.4.2/roar/tui/screens/__init__.py +0 -0
  72. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/services/proxy/src/main.rs +12 -0
  73. roar_cli-0.4.0/roar/cli/templates/agents/SKILL.md.tmpl +0 -123
  74. roar_cli-0.4.0/roar/execution/fragments/sessions.py +0 -38
  75. {roar_cli-0.4.0 → roar_cli-0.4.2}/LICENSE +0 -0
  76. {roar_cli-0.4.0 → roar_cli-0.4.2}/README.md +0 -0
  77. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/__init__.py +0 -0
  78. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/__main__.py +0 -0
  79. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/analyzers/__init__.py +0 -0
  80. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/analyzers/base.py +0 -0
  81. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/__init__.py +0 -0
  82. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/composite/__init__.py +0 -0
  83. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/composite/canonical.py +0 -0
  84. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/composite/detect.py +0 -0
  85. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/composite/qualifying.py +0 -0
  86. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/get/__init__.py +0 -0
  87. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/get/results.py +0 -0
  88. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/get/transfer.py +0 -0
  89. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/git.py +0 -0
  90. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/label_rendering.py +0 -0
  91. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/labels.py +0 -0
  92. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/lookup/__init__.py +0 -0
  93. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/lookup/models.py +0 -0
  94. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/lookup/policy.py +0 -0
  95. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/lookup/refs.py +0 -0
  96. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/lookup/remote_artifacts.py +0 -0
  97. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/lookup/runner.py +0 -0
  98. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/__init__.py +0 -0
  99. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/anchor_attribution.py +0 -0
  100. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/blake3_upgrade.py +0 -0
  101. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/collection.py +0 -0
  102. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/composite_builder.py +0 -0
  103. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/composites.py +0 -0
  104. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/datasets.py +0 -0
  105. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/form_composites.py +0 -0
  106. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/git_remote.py +0 -0
  107. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/job_links.py +0 -0
  108. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/job_preparation.py +0 -0
  109. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/lineage.py +0 -0
  110. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/lineage_composite_formation.py +0 -0
  111. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/lineage_composites.py +0 -0
  112. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/metadata.py +0 -0
  113. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/put_composites.py +0 -0
  114. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/register_execution.py +0 -0
  115. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/register_preparation.py +0 -0
  116. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/register_preview_jobs.py +0 -0
  117. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/register_tag_push.py +0 -0
  118. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/remote_job_uids.py +0 -0
  119. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/remote_registry.py +0 -0
  120. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/requests.py +0 -0
  121. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/results.py +0 -0
  122. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/runtime.py +0 -0
  123. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/secrets.py +0 -0
  124. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/session.py +0 -0
  125. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/source_resolution.py +0 -0
  126. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/targets.py +0 -0
  127. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/publish/view_edges.py +0 -0
  128. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/query/__init__.py +0 -0
  129. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/query/dag.py +0 -0
  130. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/query/db_status.py +0 -0
  131. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/query/diff.py +0 -0
  132. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/query/diff_engine.py +0 -0
  133. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/query/diff_graph.py +0 -0
  134. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/query/diff_refs.py +0 -0
  135. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/query/git_readiness.py +0 -0
  136. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/query/inputs.py +0 -0
  137. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/query/label.py +0 -0
  138. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/query/lineage.py +0 -0
  139. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/query/log.py +0 -0
  140. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/query/requests.py +0 -0
  141. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/query/results.py +0 -0
  142. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/query/show.py +0 -0
  143. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/query/status.py +0 -0
  144. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/query/tag.py +0 -0
  145. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/reproduce/__init__.py +0 -0
  146. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/reproduce/environment.py +0 -0
  147. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/reproduce/lookup.py +0 -0
  148. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/reproduce/results.py +0 -0
  149. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/reproducibility/__init__.py +0 -0
  150. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/run/__init__.py +0 -0
  151. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/run/dag_references.py +0 -0
  152. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/run/dirty_tree_classify.py +0 -0
  153. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/run/dirty_tree_error.py +0 -0
  154. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/run/gitignore_suggest.py +0 -0
  155. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/run/output_followup.py +0 -0
  156. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/run/requests.py +0 -0
  157. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/run/verbosity.py +0 -0
  158. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/tags.py +0 -0
  159. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/workflow/__init__.py +0 -0
  160. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/workflow/requests.py +0 -0
  161. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/workflow/results.py +0 -0
  162. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/application/workflow/service.py +0 -0
  163. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/auth_store.py +0 -0
  164. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/__init__.py +0 -0
  165. {roar_cli-0.4.0/roar/tui/screens → roar_cli-0.4.2/roar/backends/k8s}/__init__.py +0 -0
  166. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/local/__init__.py +0 -0
  167. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/local/plugin.py +0 -0
  168. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/osmo/__init__.py +0 -0
  169. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/osmo/config.py +0 -0
  170. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/osmo/host_execution.py +0 -0
  171. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/osmo/lineage.py +0 -0
  172. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/osmo/plugin.py +0 -0
  173. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/osmo/runtime_bundle.py +0 -0
  174. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/osmo/submit.py +0 -0
  175. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/osmo/workflow.py +0 -0
  176. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/ray/__init__.py +0 -0
  177. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/ray/_agent_names.py +0 -0
  178. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/ray/collector.py +0 -0
  179. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/ray/config.py +0 -0
  180. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/ray/constants.py +0 -0
  181. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/ray/env_contract.py +0 -0
  182. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/ray/fragment.py +0 -0
  183. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/ray/node_agent.py +0 -0
  184. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/ray/plugin.py +0 -0
  185. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/ray/proxy_fragments.py +0 -0
  186. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/ray/s3_key_paths.py +0 -0
  187. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/backends/ray/submit_context.py +0 -0
  188. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/__init__.py +0 -0
  189. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/_format.py +0 -0
  190. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/_tag_kinds.py +0 -0
  191. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/__init__.py +0 -0
  192. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/auth.py +0 -0
  193. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/build.py +0 -0
  194. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/config.py +0 -0
  195. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/dag.py +0 -0
  196. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/db.py +0 -0
  197. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/diff.py +0 -0
  198. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/env.py +0 -0
  199. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/export_registration_package.py +0 -0
  200. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/filter.py +0 -0
  201. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/init.py +0 -0
  202. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/init_agents.py +0 -0
  203. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/inputs.py +0 -0
  204. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/label.py +0 -0
  205. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/lineage.py +0 -0
  206. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/log.py +0 -0
  207. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/login.py +0 -0
  208. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/logout.py +0 -0
  209. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/osmo.py +0 -0
  210. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/pop.py +0 -0
  211. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/projects.py +0 -0
  212. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/reset.py +0 -0
  213. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/run.py +0 -0
  214. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/session.py +0 -0
  215. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/show.py +0 -0
  216. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/status.py +0 -0
  217. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/tag.py +0 -0
  218. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/telemetry.py +0 -0
  219. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/tracer.py +0 -0
  220. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/tui.py +0 -0
  221. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/whoami.py +0 -0
  222. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/commands/workflow.py +0 -0
  223. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/cli/decorators.py +0 -0
  224. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/__init__.py +0 -0
  225. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/bootstrap.py +0 -0
  226. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/canonical_session.py +0 -0
  227. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/digests.py +0 -0
  228. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/dto/__init__.py +0 -0
  229. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/dto/registration.py +0 -0
  230. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/exceptions.py +0 -0
  231. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/interfaces/__init__.py +0 -0
  232. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/interfaces/config.py +0 -0
  233. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/interfaces/lineage.py +0 -0
  234. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/interfaces/logger.py +0 -0
  235. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/interfaces/presenter.py +0 -0
  236. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/interfaces/provenance.py +0 -0
  237. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/interfaces/registration.py +0 -0
  238. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/interfaces/repositories.py +0 -0
  239. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/interfaces/reproduction.py +0 -0
  240. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/interfaces/run.py +0 -0
  241. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/interfaces/services.py +0 -0
  242. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/interfaces/telemetry.py +0 -0
  243. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/interfaces/vcs.py +0 -0
  244. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/label_constants.py +0 -0
  245. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/label_origins.py +0 -0
  246. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/logging.py +0 -0
  247. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/models/__init__.py +0 -0
  248. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/models/artifact.py +0 -0
  249. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/models/base.py +0 -0
  250. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/models/dag.py +0 -0
  251. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/models/dataset_identifier.py +0 -0
  252. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/models/glaas.py +0 -0
  253. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/models/job.py +0 -0
  254. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/models/lineage.py +0 -0
  255. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/models/run.py +0 -0
  256. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/models/session.py +0 -0
  257. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/models/telemetry.py +0 -0
  258. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/models/vcs.py +0 -0
  259. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/operation_metadata.py +0 -0
  260. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/session_hash.py +0 -0
  261. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/step_name.py +0 -0
  262. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/tracer_modes.py +0 -0
  263. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/core/validation.py +0 -0
  264. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/db/__init__.py +0 -0
  265. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/db/context.py +0 -0
  266. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/db/engine.py +0 -0
  267. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/db/hashing/__init__.py +0 -0
  268. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/db/hashing/backend.py +0 -0
  269. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/db/hashing/blake3.py +0 -0
  270. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/db/models.py +0 -0
  271. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/db/query_context.py +0 -0
  272. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/db/repositories/__init__.py +0 -0
  273. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/db/repositories/artifact.py +0 -0
  274. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/db/repositories/collection.py +0 -0
  275. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/db/repositories/composite.py +0 -0
  276. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/db/repositories/hash_cache.py +0 -0
  277. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/db/repositories/job.py +0 -0
  278. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/db/repositories/label.py +0 -0
  279. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/db/repositories/session.py +0 -0
  280. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/db/schema.py +0 -0
  281. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/db/services/__init__.py +0 -0
  282. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/db/services/hashing.py +0 -0
  283. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/db/services/job_recording.py +0 -0
  284. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/db/services/lineage.py +0 -0
  285. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/db/services/session.py +0 -0
  286. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/db/step_priority.py +0 -0
  287. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/__init__.py +0 -0
  288. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/cluster/__init__.py +0 -0
  289. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/cluster/bridge.py +0 -0
  290. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/cluster/proxy.py +0 -0
  291. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/cluster/proxy_config.py +0 -0
  292. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/fragments/__init__.py +0 -0
  293. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/fragments/reconstitution.py +0 -0
  294. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/framework/__init__.py +0 -0
  295. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/framework/contract.py +0 -0
  296. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/framework/planning.py +0 -0
  297. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/framework/runtime_imports.py +0 -0
  298. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/provenance/__init__.py +0 -0
  299. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/provenance/build_pip_collector.py +0 -0
  300. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/provenance/build_tool_collector.py +0 -0
  301. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/provenance/data_loader.py +0 -0
  302. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/provenance/file_filter.py +0 -0
  303. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/provenance/package_collector.py +0 -0
  304. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/provenance/process_summarizer.py +0 -0
  305. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/provenance/service.py +0 -0
  306. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/recording/__init__.py +0 -0
  307. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/recording/dataset_identifier.py +0 -0
  308. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/recording/dataset_metadata.py +0 -0
  309. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/recording/dataset_profile.py +0 -0
  310. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/recording/job_recording.py +0 -0
  311. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/reproduction/__init__.py +0 -0
  312. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/reproduction/environment_setup.py +0 -0
  313. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/reproduction/installers.py +0 -0
  314. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/reproduction/pipeline_executor.py +0 -0
  315. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/reproduction/pipeline_metadata.py +0 -0
  316. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/runtime/__init__.py +0 -0
  317. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/runtime/abi_probe.py +0 -0
  318. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/runtime/active_runs.py +0 -0
  319. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/runtime/backup.py +0 -0
  320. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/runtime/coordinator.py +0 -0
  321. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/runtime/driver_entrypoint.py +0 -0
  322. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/runtime/errors.py +0 -0
  323. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/runtime/host_execution.py +0 -0
  324. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/runtime/inject/__init__.py +0 -0
  325. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/runtime/inject/sitecustomize.py +0 -0
  326. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/runtime/inject/support.py +0 -0
  327. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/runtime/inject/tracker.py +0 -0
  328. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/runtime/lazy_install.py +0 -0
  329. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/runtime/resources.py +0 -0
  330. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/runtime/signal_handler.py +0 -0
  331. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/runtime/tracer_backends.py +0 -0
  332. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/execution/runtime/tracer_banner.py +0 -0
  333. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/filters/__init__.py +0 -0
  334. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/filters/files.py +0 -0
  335. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/filters/omit.py +0 -0
  336. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/glaas_auth.py +0 -0
  337. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/glaas_client.py +0 -0
  338. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/__init__.py +0 -0
  339. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/bootstrap.py +0 -0
  340. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/config/__init__.py +0 -0
  341. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/config/access.py +0 -0
  342. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/config/loader.py +0 -0
  343. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/config/raw.py +0 -0
  344. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/config/schema.py +0 -0
  345. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/discovery.py +0 -0
  346. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/download/__init__.py +0 -0
  347. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/download/base.py +0 -0
  348. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/download/gcs.py +0 -0
  349. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/download/get.py +0 -0
  350. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/download/http.py +0 -0
  351. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/download/noop.py +0 -0
  352. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/download/s3.py +0 -0
  353. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/git/__init__.py +0 -0
  354. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/git/base.py +0 -0
  355. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/git/context.py +0 -0
  356. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/git/provider.py +0 -0
  357. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/glaas/auth.py +0 -0
  358. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/glaas/registration/__init__.py +0 -0
  359. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/glaas/registration/_artifact_ref.py +0 -0
  360. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/glaas/registration/artifact.py +0 -0
  361. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/glaas/registration/coordinator.py +0 -0
  362. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/glaas/registration/job.py +0 -0
  363. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/glaas/registration/session.py +0 -0
  364. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/glaas/transport.py +0 -0
  365. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/registry.py +0 -0
  366. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/resolution.py +0 -0
  367. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/storage/__init__.py +0 -0
  368. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/storage/base.py +0 -0
  369. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/storage/gcs.py +0 -0
  370. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/storage/memory.py +0 -0
  371. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/storage/noop.py +0 -0
  372. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/storage/s3.py +0 -0
  373. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/telemetry/__init__.py +0 -0
  374. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/telemetry/base.py +0 -0
  375. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/integrations/telemetry/wandb.py +0 -0
  376. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/presenters/__init__.py +0 -0
  377. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/presenters/console.py +0 -0
  378. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/presenters/dag_data_builder.py +0 -0
  379. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/presenters/dag_renderer.py +0 -0
  380. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/presenters/diff_renderer.py +0 -0
  381. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/presenters/formatting.py +0 -0
  382. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/presenters/null.py +0 -0
  383. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/presenters/run_report.py +0 -0
  384. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/presenters/spinner.py +0 -0
  385. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/presenters/terminal.py +0 -0
  386. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/require.py +0 -0
  387. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/telemetry/__init__.py +0 -0
  388. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/telemetry/_io.py +0 -0
  389. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/telemetry/capabilities.py +0 -0
  390. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/telemetry/config.py +0 -0
  391. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/telemetry/hooks.py +0 -0
  392. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/telemetry/install.py +0 -0
  393. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/telemetry/paths.py +0 -0
  394. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/telemetry/payload.py +0 -0
  395. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/telemetry/queue.py +0 -0
  396. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/telemetry/stats.py +0 -0
  397. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/telemetry/uploader.py +0 -0
  398. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/tui/__init__.py +0 -0
  399. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/tui/app.py +0 -0
  400. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/tui/data.py +0 -0
  401. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/tui/screens/config_editor.py +0 -0
  402. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/tui/screens/label_editor.py +0 -0
  403. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/tui/screens/launcher.py +0 -0
  404. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/tui/screens/log.py +0 -0
  405. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/tui/screens/main.py +0 -0
  406. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/tui/screens/search.py +0 -0
  407. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/tui/screens/session_picker.py +0 -0
  408. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/tui/tmux.py +0 -0
  409. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/tui/widgets/__init__.py +0 -0
  410. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/tui/widgets/detail.py +0 -0
  411. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/utils/__init__.py +0 -0
  412. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/utils/cloud.py +0 -0
  413. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/utils/git_url.py +0 -0
  414. {roar_cli-0.4.0 → roar_cli-0.4.2}/roar/version_check.py +0 -0
  415. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/Cargo.lock +0 -0
  416. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/Cargo.toml +0 -0
  417. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/crates/artifact-hash-core/Cargo.toml +0 -0
  418. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/crates/artifact-hash-core/src/lib.rs +0 -0
  419. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/crates/artifact-hash-py/Cargo.toml +0 -0
  420. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/crates/artifact-hash-py/src/lib.rs +0 -0
  421. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/crates/tracer-fd/Cargo.toml +0 -0
  422. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/crates/tracer-fd/src/lib.rs +0 -0
  423. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/crates/tracer-runtime/Cargo.toml +0 -0
  424. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/crates/tracer-runtime/src/lib.rs +0 -0
  425. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/crates/tracer-schema/Cargo.toml +0 -0
  426. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/crates/tracer-schema/src/lib.rs +0 -0
  427. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/services/proxy/Cargo.lock +0 -0
  428. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/services/proxy/Cargo.toml +0 -0
  429. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/services/proxy/src/forward.rs +0 -0
  430. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/services/proxy/src/s3.rs +0 -0
  431. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/ebpf/common/Cargo.toml +0 -0
  432. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/ebpf/common/src/lib.rs +0 -0
  433. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/ebpf/probe/Cargo.toml +0 -0
  434. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/ebpf/probe/rust-toolchain.toml +0 -0
  435. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/ebpf/probe/src/main.rs +0 -0
  436. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/ebpf/userspace/Cargo.toml +0 -0
  437. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/ebpf/userspace/build.rs +0 -0
  438. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/ebpf/userspace/src/attach.rs +0 -0
  439. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/ebpf/userspace/src/bin/roard.rs +0 -0
  440. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/ebpf/userspace/src/client.rs +0 -0
  441. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/ebpf/userspace/src/daemon.rs +0 -0
  442. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/ebpf/userspace/src/events.rs +0 -0
  443. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/ebpf/userspace/src/ipc.rs +0 -0
  444. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/ebpf/userspace/src/lib.rs +0 -0
  445. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/ebpf/userspace/src/main.rs +0 -0
  446. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/ebpf/userspace/src/state.rs +0 -0
  447. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/preload/Cargo.toml +0 -0
  448. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/preload/build.rs +0 -0
  449. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/preload/src/bin/io_fixture.rs +0 -0
  450. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/preload/src/interpose.c +0 -0
  451. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/preload/src/ipc.rs +0 -0
  452. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/preload/src/lib.rs +0 -0
  453. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/preload/src/main.rs +0 -0
  454. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/preload/tests/comprehensive.rs +0 -0
  455. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/preload/tests/standalone.rs +0 -0
  456. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/ptrace/Cargo.toml +0 -0
  457. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/ptrace/rustfmt.toml +0 -0
  458. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/ptrace/src/arch.rs +0 -0
  459. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/ptrace/src/main.rs +0 -0
  460. {roar_cli-0.4.0 → roar_cli-0.4.2}/rust/tracers/ptrace/src/seccomp.rs +0 -0
  461. {roar_cli-0.4.0 → roar_cli-0.4.2}/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.4.0
3
+ Version: 0.4.2
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.4.0"
8
+ version = "0.4.2"
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]
@@ -123,6 +124,7 @@ markers = [
123
124
  "diagnostic: Opt-in diagnostics or aspirational performance budgets outside the default gate",
124
125
  "large_pipeline: Stress-style pipeline coverage with larger DAG fixtures",
125
126
  "osmo_e2e: OSMO end-to-end tests requiring a Docker Compose managed KIND harness",
127
+ "k8s_e2e: Kubernetes end-to-end tests requiring the KIND harness (tests/backends/k8s)",
126
128
  "ray_e2e: Ray end-to-end tests requiring a running Docker cluster",
127
129
  "ray_contract: User-facing Ray contract tests using `roar run ray job submit ...`",
128
130
  "ray_diagnostic: Diagnostic Ray tests that intentionally inspect internal runtime details",
@@ -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:
@@ -9,6 +9,7 @@ roar put ALWAYS registers lineage with GLaaS. This is not optional.
9
9
 
10
10
  from __future__ import annotations
11
11
 
12
+ import shlex
12
13
  import time
13
14
  from dataclasses import dataclass, field
14
15
  from pathlib import Path
@@ -52,6 +53,47 @@ from .put_composites import (
52
53
  from .results import PutCompositeRegistration, PutDryRunItem, PutUploadedFile
53
54
 
54
55
 
56
+ def build_put_command(
57
+ sources: list[str],
58
+ destination: str | None,
59
+ *,
60
+ message: str,
61
+ public: bool = True,
62
+ anonymous: bool = False,
63
+ no_tag: bool = False,
64
+ as_dataset: bool = False,
65
+ step_name: str | None = None,
66
+ ) -> str:
67
+ """Reconstruct a faithful ``roar put`` command string for the job record.
68
+
69
+ The recorded command drives ``roar reproduce``, so it must include the
70
+ destination and every provenance-relevant flag — not just the sources and
71
+ message. Interaction/mode flags (``--yes``, ``--dry-run``) are intentionally
72
+ omitted: they control confirmation/preview, not the published result.
73
+ """
74
+ parts = ["roar", "put"]
75
+ if sources:
76
+ parts.extend(shlex.quote(s) for s in sources)
77
+ else:
78
+ parts.append("(session outputs)")
79
+ if destination:
80
+ parts.append(shlex.quote(destination))
81
+ if anonymous:
82
+ parts.append("--anonymous")
83
+ elif public is False:
84
+ parts.append("--private")
85
+ elif public:
86
+ parts.append("--public")
87
+ if no_tag:
88
+ parts.append("--no-tag")
89
+ if as_dataset:
90
+ parts.append("--as-dataset")
91
+ if step_name:
92
+ parts.extend(["--step-name", shlex.quote(step_name)])
93
+ parts.extend(["-m", shlex.quote(message)])
94
+ return " ".join(parts)
95
+
96
+
55
97
  def _upload_progress_message(done: int, total: int, uploaded_bytes: int) -> str:
56
98
  """Status line for the upload spinner, e.g. ``Uploading 12/100 files · 1.10 GB``."""
57
99
  return f"Uploading {done}/{total} files · {uploaded_bytes / 1e9:.2f} GB"
@@ -145,6 +187,7 @@ class PutService:
145
187
  git_commit: str | None = None,
146
188
  git_tag: str | None = None,
147
189
  declared: bool = False,
190
+ command: str | None = None,
148
191
  ) -> PutResult:
149
192
  """
150
193
  Execute a put operation.
@@ -294,6 +337,7 @@ class PutService:
294
337
  git_context=git_context,
295
338
  sources=sources,
296
339
  message=message,
340
+ command=command,
297
341
  uploads=uploads,
298
342
  uploaded_files=uploaded_files,
299
343
  artifacts_info=artifacts_info,
@@ -416,9 +460,10 @@ class PutService:
416
460
  for item in composite_registrations
417
461
  ]
418
462
 
419
- # Build command string
420
- source_str = " ".join(sources) if sources else "(session outputs)"
421
- command = f'roar put {source_str} -m "{message}"'
463
+ # Build command string. Prefer the faithful command (destination + flags)
464
+ # supplied by the caller; fall back to a destination-aware reconstruction.
465
+ if command is None:
466
+ command = build_put_command(sources, self._destination, message=message)
422
467
 
423
468
  # Build metadata
424
469
  metadata_json = build_put_operation_metadata_json(
@@ -551,6 +596,7 @@ class PutService:
551
596
  git_context: GitContext,
552
597
  sources: list[str],
553
598
  message: str,
599
+ command: str | None = None,
554
600
  uploads: list[_UploadedArtifact],
555
601
  uploaded_files: list[PutUploadedFile],
556
602
  artifacts_info: list[tuple[str, str]],
@@ -571,8 +617,8 @@ class PutService:
571
617
  registration_errors: list[str] = []
572
618
  lineage_composite_registrations: list[dict[str, Any]] = []
573
619
  composite_registrations: list[dict[str, Any]] = []
574
- source_str = " ".join(sources) if sources else "(session outputs)"
575
- command = f'roar put {source_str} -m "{message}"'
620
+ if command is None:
621
+ command = build_put_command(sources, self._destination, message=message)
576
622
  source_type = normalize_registration_source_type(destination_type)
577
623
 
578
624
  provisional_metadata_json = build_put_operation_metadata_json(
@@ -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,
@@ -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
 
@@ -206,6 +206,8 @@ def build_registration_package(
206
206
  if composites:
207
207
  package["composites"] = composites
208
208
 
209
+ if labels:
210
+ labels = _drop_labels_for_absent_jobs(labels, job_records)
209
211
  if labels:
210
212
  filtered_labels, label_detections = _filter_label_secrets(labels, omit_filter)
211
213
  package["labels"] = filtered_labels
@@ -292,6 +294,38 @@ def _apply_redaction(
292
294
  )
293
295
 
294
296
 
297
+ def _drop_labels_for_absent_jobs(
298
+ labels: list[dict[str, Any]],
299
+ job_records: list[dict[str, Any]],
300
+ ) -> list[dict[str, Any]]:
301
+ """Drop job-scoped labels whose target job is not in the package.
302
+
303
+ Labels are collected from the raw lineage, but the package's jobs are
304
+ noise-filtered by ``normalize_jobs_for_registration``. A job label left
305
+ pointing at a dropped job makes the package internally inconsistent — GLaaS
306
+ rejects it on publish with "Package label references a job not in the
307
+ package". The job label's target reaches the publish side through the job
308
+ record's ``job_uid`` (GLaaS's ``sourceUid``), so match on that. Non-job
309
+ labels (dag, artifact) are unaffected.
310
+ """
311
+ package_job_uids = {str(job.get("job_uid")) for job in job_records if job.get("job_uid")}
312
+ kept: list[dict[str, Any]] = []
313
+ dropped = 0
314
+ for label in labels:
315
+ if str(label.get("entity_type")) == "job":
316
+ job_uid = label.get("job_uid")
317
+ if not isinstance(job_uid, str) or job_uid not in package_job_uids:
318
+ dropped += 1
319
+ continue
320
+ kept.append(label)
321
+ if dropped:
322
+ get_logger().debug(
323
+ "Dropped %d job label(s) referencing jobs not in the registration package",
324
+ dropped,
325
+ )
326
+ return kept
327
+
328
+
295
329
  def _filter_label_secrets(
296
330
  labels: list[dict[str, Any]],
297
331
  omit_filter: OmitFilter | None,
@@ -894,6 +894,8 @@ def put_artifacts(request: PutRequest) -> PutResponse:
894
894
  )
895
895
  put_commit_on_remote = is_shareable_remote(prepared.git_context.repo)
896
896
 
897
+ from .put_execution import build_put_command
898
+
897
899
  result = service.put_prepared(
898
900
  prepared=prepared,
899
901
  sources=request.sources,
@@ -902,6 +904,16 @@ def put_artifacts(request: PutRequest) -> PutResponse:
902
904
  git_commit=git_commit,
903
905
  git_tag=expected_tag,
904
906
  declared=request.as_dataset,
907
+ command=build_put_command(
908
+ request.sources,
909
+ request.destination,
910
+ message=request.message,
911
+ public=request.public,
912
+ anonymous=request.anonymous,
913
+ no_tag=request.no_tag,
914
+ as_dataset=request.as_dataset,
915
+ step_name=request.step_name,
916
+ ),
905
917
  )
906
918
 
907
919
  # Apply step name label if provided.
@@ -20,3 +20,8 @@ class ReproduceRequest:
20
20
  package_sync: bool = False
21
21
  list_requirements: bool = False
22
22
  out_path: str | None = None
23
+ # Skip publish (`roar put`) steps — for third-party reproduction that
24
+ # rebuilds the artifact without re-publishing to the owner's destination.
25
+ no_puts: bool = False
26
+ # Emit an editable reproduction shell script instead of previewing/running.
27
+ emit_script: bool = False