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.
- {roar_cli-0.3.7 → roar_cli-0.4.1}/PKG-INFO +2 -1
- {roar_cli-0.3.7 → roar_cli-0.4.1}/pyproject.toml +2 -1
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/analyzers/experiment_trackers.py +103 -3
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/get/requests.py +1 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/get/service.py +105 -16
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/put_preparation.py +3 -1
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/register_execution.py +19 -6
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/registration.py +28 -8
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/service.py +17 -7
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/view_edges.py +15 -6
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/__init__.py +12 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/requests.py +52 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/results.py +74 -0
- roar_cli-0.4.1/roar/application/query/tag.py +224 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/reproducibility/report.py +18 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/run/execution.py +4 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/run/requests.py +2 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/run/service.py +6 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/system_labels.py +7 -1
- roar_cli-0.4.1/roar/application/tags.py +746 -0
- roar_cli-0.4.1/roar/cli/_tag_kinds.py +69 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/command_registry.py +7 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/__init__.py +1 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/get.py +11 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/proxy.py +7 -3
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/put.py +14 -2
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/register.py +161 -21
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/run.py +39 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/scope.py +16 -6
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/status.py +10 -0
- roar_cli-0.4.1/roar/cli/commands/tag.py +241 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/publish_intent.py +21 -1
- roar_cli-0.4.1/roar/cli/templates/agents/SKILL.md.tmpl +198 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/templates/agents/agents_section.md.tmpl +3 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/label_constants.py +12 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/run.py +2 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/services/job_recording.py +75 -5
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/recording/job_recording.py +2 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/reproduction/pipeline_executor.py +29 -19
- roar_cli-0.4.1/roar/execution/runtime/active_runs.py +144 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/coordinator.py +9 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/proxy_resource.py +22 -2
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/tracer.py +1 -1
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/config/access.py +8 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/config/schema.py +12 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/download/hf.py +9 -3
- roar_cli-0.4.1/roar/integrations/storage/hf.py +146 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/storage/publish.py +5 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/presenters/show_renderer.py +30 -2
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/publish_auth.py +71 -5
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/scope_config.py +4 -0
- roar_cli-0.3.7/roar/cli/templates/agents/SKILL.md.tmpl +0 -123
- {roar_cli-0.3.7 → roar_cli-0.4.1}/LICENSE +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/README.md +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/__main__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/analyzers/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/analyzers/base.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/composite/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/composite/canonical.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/composite/detect.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/composite/qualifying.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/get/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/get/results.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/get/transfer.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/git.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/label_rendering.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/labels.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/lookup/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/lookup/models.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/lookup/policy.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/lookup/refs.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/lookup/remote_artifacts.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/lookup/runner.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/anchor_attribution.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/blake3_upgrade.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/collection.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/composite_builder.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/composites.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/datasets.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/form_composites.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/git_remote.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/job_links.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/job_preparation.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/lineage.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/lineage_composite_formation.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/lineage_composites.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/metadata.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/put_composites.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/put_execution.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/register_preparation.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/register_preview_jobs.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/register_tag_push.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/registration_package.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/remote_job_uids.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/remote_registry.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/requests.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/results.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/runtime.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/secrets.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/session.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/source_resolution.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/publish/targets.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/dag.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/db_status.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/diff.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/diff_engine.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/diff_graph.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/diff_refs.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/git_readiness.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/inputs.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/label.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/lineage.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/log.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/show.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/query/status.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/reproduce/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/reproduce/environment.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/reproduce/lookup.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/reproduce/requests.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/reproduce/results.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/reproduce/service.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/reproducibility/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/run/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/run/dag_references.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/run/dirty_tree_classify.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/run/dirty_tree_error.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/run/gitignore_suggest.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/run/output_followup.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/run/verbosity.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/workflow/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/workflow/requests.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/workflow/results.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/application/workflow/service.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/auth_store.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/local/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/local/plugin.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/osmo/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/osmo/config.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/osmo/export.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/osmo/host_execution.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/osmo/lineage.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/osmo/plugin.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/osmo/runtime_bundle.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/osmo/submit.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/osmo/workflow.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/_agent_names.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/collector.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/config.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/constants.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/env_contract.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/fragment.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/fragment_reconstituter.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/node_agent.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/plugin.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/proxy_fragments.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/roar_worker.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/runtime_hooks.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/s3_key_paths.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/submit.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/backends/ray/submit_context.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/_format.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/auth.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/build.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/config.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/dag.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/db.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/diff.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/env.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/export_registration_package.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/filter.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/init.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/init_agents.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/inputs.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/label.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/lineage.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/log.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/login.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/logout.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/osmo.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/pop.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/projects.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/reproduce.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/reset.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/session.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/show.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/telemetry.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/tracer.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/tui.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/whoami.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/commands/workflow.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/context.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/cli/decorators.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/bootstrap.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/canonical_session.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/digests.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/dto/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/dto/registration.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/exceptions.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/config.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/lineage.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/logger.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/presenter.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/provenance.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/registration.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/repositories.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/reproduction.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/run.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/services.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/telemetry.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/interfaces/vcs.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/label_origins.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/logging.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/artifact.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/base.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/dag.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/dataset_identifier.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/glaas.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/job.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/lineage.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/provenance.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/session.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/telemetry.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/models/vcs.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/operation_metadata.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/session_hash.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/step_name.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/tracer_modes.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/core/validation.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/context.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/engine.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/hashing/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/hashing/backend.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/hashing/blake3.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/models.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/query_context.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/repositories/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/repositories/artifact.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/repositories/collection.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/repositories/composite.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/repositories/hash_cache.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/repositories/job.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/repositories/label.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/repositories/session.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/schema.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/services/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/services/hashing.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/services/lineage.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/services/session.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/db/step_priority.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/cluster/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/cluster/bridge.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/cluster/proxy.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/cluster/proxy_config.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/fragments/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/fragments/lineage.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/fragments/models.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/fragments/reconstitution.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/fragments/sessions.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/fragments/transport.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/framework/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/framework/contract.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/framework/planning.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/framework/registry.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/framework/runtime_imports.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/provenance/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/provenance/assembler.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/provenance/build_pip_collector.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/provenance/build_tool_collector.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/provenance/data_loader.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/provenance/file_filter.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/provenance/package_collector.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/provenance/process_summarizer.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/provenance/runtime_collector.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/provenance/service.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/recording/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/recording/dataset_identifier.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/recording/dataset_metadata.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/recording/dataset_profile.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/reproduction/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/reproduction/environment_setup.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/reproduction/installers.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/reproduction/pipeline_metadata.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/abi_probe.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/backup.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/driver_entrypoint.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/errors.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/host_execution.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/inject/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/inject/sitecustomize.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/inject/support.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/inject/tracker.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/lazy_install.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/resources.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/signal_handler.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/tracer_backends.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/tracer_banner.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/execution/runtime/worker_bootstrap.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/filters/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/filters/files.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/filters/omit.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/glaas_auth.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/glaas_client.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/bootstrap.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/config/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/config/loader.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/config/raw.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/discovery.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/download/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/download/base.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/download/gcs.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/download/get.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/download/http.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/download/noop.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/download/s3.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/git/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/git/base.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/git/context.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/git/provider.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/glaas/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/glaas/auth.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/glaas/client.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/glaas/fragment_streamer.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/glaas/registration/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/glaas/registration/_artifact_ref.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/glaas/registration/artifact.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/glaas/registration/coordinator.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/glaas/registration/job.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/glaas/registration/session.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/glaas/transport.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/registry.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/resolution.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/storage/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/storage/base.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/storage/gcs.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/storage/memory.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/storage/noop.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/storage/s3.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/telemetry/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/telemetry/base.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/integrations/telemetry/wandb.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/presenters/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/presenters/console.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/presenters/dag_data_builder.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/presenters/dag_renderer.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/presenters/diff_renderer.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/presenters/formatting.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/presenters/null.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/presenters/run_report.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/presenters/spinner.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/presenters/terminal.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/require.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/telemetry/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/telemetry/_io.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/telemetry/capabilities.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/telemetry/config.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/telemetry/hooks.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/telemetry/install.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/telemetry/paths.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/telemetry/payload.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/telemetry/queue.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/telemetry/stats.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/telemetry/uploader.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/app.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/data.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/screens/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/screens/config_editor.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/screens/label_editor.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/screens/launcher.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/screens/log.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/screens/main.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/screens/search.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/screens/session_picker.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/tmux.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/widgets/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/tui/widgets/detail.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/utils/__init__.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/utils/cloud.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/utils/git_url.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/roar/version_check.py +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/Cargo.lock +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/Cargo.toml +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/crates/artifact-hash-core/Cargo.toml +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/crates/artifact-hash-core/src/lib.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/crates/artifact-hash-py/Cargo.toml +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/crates/artifact-hash-py/src/lib.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/crates/tracer-fd/Cargo.toml +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/crates/tracer-fd/src/lib.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/crates/tracer-runtime/Cargo.toml +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/crates/tracer-runtime/src/lib.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/crates/tracer-schema/Cargo.toml +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/crates/tracer-schema/src/lib.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/services/proxy/Cargo.lock +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/services/proxy/Cargo.toml +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/services/proxy/src/forward.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/services/proxy/src/main.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/services/proxy/src/s3.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/common/Cargo.toml +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/common/src/lib.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/probe/Cargo.toml +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/probe/rust-toolchain.toml +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/probe/src/main.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/userspace/Cargo.toml +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/userspace/build.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/userspace/src/attach.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/userspace/src/bin/roard.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/userspace/src/client.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/userspace/src/daemon.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/userspace/src/events.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/userspace/src/ipc.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/userspace/src/lib.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/userspace/src/main.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ebpf/userspace/src/state.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/preload/Cargo.toml +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/preload/build.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/preload/src/bin/io_fixture.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/preload/src/interpose.c +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/preload/src/ipc.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/preload/src/lib.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/preload/src/main.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/preload/tests/comprehensive.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/preload/tests/standalone.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ptrace/Cargo.toml +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ptrace/rustfmt.toml +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ptrace/src/arch.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ptrace/src/main.rs +0 -0
- {roar_cli-0.3.7 → roar_cli-0.4.1}/rust/tracers/ptrace/src/seccomp.rs +0 -0
- {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
|
+
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.
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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 =
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
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.
|
|
509
|
-
|
|
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)
|
|
126
|
-
|
|
127
|
-
|
|
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:
|