roar-cli 0.3.5__tar.gz → 0.3.6__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.5 → roar_cli-0.3.6}/PKG-INFO +1 -1
- {roar_cli-0.3.5 → roar_cli-0.3.6}/pyproject.toml +1 -1
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/git.py +13 -1
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/git_remote.py +6 -1
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/register_execution.py +11 -1
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/register_tag_push.py +16 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/registration_package.py +24 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/results.py +10 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/service.py +71 -26
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/query/inputs.py +122 -19
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/query/requests.py +2 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/query/results.py +4 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/query/status.py +53 -0
- roar_cli-0.3.6/roar/application/reproduce/environment.py +208 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/reproduce/lookup.py +65 -8
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/reproduce/service.py +164 -12
- roar_cli-0.3.6/roar/application/reproducibility/report.py +315 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/run/execution.py +22 -1
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/run/output_followup.py +47 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/init.py +8 -10
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/inputs.py +16 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/put.py +48 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/register.py +115 -18
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/status.py +15 -2
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/publish_intent.py +47 -7
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/templates/agents/SKILL.md.tmpl +21 -1
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/templates/agents/agents_section.md.tmpl +2 -1
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/interfaces/reproduction.py +4 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/provenance/file_filter.py +13 -1
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/provenance/service.py +49 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/reproduction/environment_setup.py +113 -19
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/reproduction/pipeline_executor.py +5 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/runtime/coordinator.py +1 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/runtime/tracer.py +32 -20
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/glaas/registration/artifact.py +18 -9
- roar_cli-0.3.6/roar/tui/screens/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/utils/git_url.py +19 -0
- roar_cli-0.3.5/roar/application/reproduce/environment.py +0 -91
- {roar_cli-0.3.5 → roar_cli-0.3.6}/LICENSE +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/README.md +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/__main__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/analyzers/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/analyzers/base.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/analyzers/experiment_trackers.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/composite/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/composite/canonical.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/composite/detect.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/composite/qualifying.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/get/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/get/requests.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/get/results.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/get/service.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/get/transfer.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/label_rendering.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/labels.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/lookup/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/lookup/models.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/lookup/policy.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/lookup/refs.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/lookup/remote_artifacts.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/lookup/runner.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/anchor_attribution.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/blake3_upgrade.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/collection.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/composite_builder.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/composites.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/datasets.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/form_composites.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/job_links.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/job_preparation.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/lineage.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/lineage_composite_formation.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/lineage_composites.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/metadata.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/put_composites.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/put_execution.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/put_preparation.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/register_preparation.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/register_preview_jobs.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/registration.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/remote_job_uids.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/remote_registry.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/requests.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/runtime.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/secrets.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/session.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/source_resolution.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/targets.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/publish/view_edges.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/query/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/query/dag.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/query/db_status.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/query/diff.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/query/diff_engine.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/query/diff_graph.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/query/diff_refs.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/query/git_readiness.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/query/label.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/query/lineage.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/query/log.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/query/show.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/reproduce/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/reproduce/requests.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/reproduce/results.py +0 -0
- {roar_cli-0.3.5/roar/tui/screens → roar_cli-0.3.6/roar/application/reproducibility}/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/run/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/run/dag_references.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/run/dirty_tree_classify.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/run/dirty_tree_error.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/run/gitignore_suggest.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/run/requests.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/run/service.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/run/verbosity.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/system_labels.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/workflow/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/workflow/requests.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/workflow/results.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/application/workflow/service.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/auth_store.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/local/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/local/plugin.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/osmo/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/osmo/config.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/osmo/export.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/osmo/host_execution.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/osmo/lineage.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/osmo/plugin.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/osmo/runtime_bundle.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/osmo/submit.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/osmo/workflow.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/ray/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/ray/_agent_names.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/ray/collector.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/ray/config.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/ray/constants.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/ray/env_contract.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/ray/fragment.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/ray/fragment_reconstituter.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/ray/node_agent.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/ray/plugin.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/ray/proxy_fragments.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/ray/roar_worker.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/ray/runtime_hooks.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/ray/s3_key_paths.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/ray/submit.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/backends/ray/submit_context.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/_format.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/command_registry.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/auth.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/build.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/config.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/dag.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/db.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/diff.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/env.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/export_registration_package.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/filter.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/get.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/init_agents.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/label.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/lineage.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/log.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/login.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/logout.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/osmo.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/pop.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/projects.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/proxy.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/reproduce.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/reset.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/run.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/scope.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/show.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/telemetry.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/tracer.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/tui.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/whoami.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/commands/workflow.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/context.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/cli/decorators.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/bootstrap.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/canonical_session.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/digests.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/dto/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/dto/registration.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/exceptions.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/interfaces/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/interfaces/config.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/interfaces/lineage.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/interfaces/logger.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/interfaces/presenter.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/interfaces/provenance.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/interfaces/registration.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/interfaces/repositories.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/interfaces/run.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/interfaces/services.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/interfaces/telemetry.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/interfaces/vcs.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/label_constants.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/label_origins.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/logging.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/models/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/models/artifact.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/models/base.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/models/dag.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/models/dataset_identifier.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/models/glaas.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/models/job.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/models/lineage.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/models/provenance.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/models/run.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/models/session.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/models/telemetry.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/models/vcs.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/operation_metadata.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/session_hash.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/step_name.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/tracer_modes.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/core/validation.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/db/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/db/context.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/db/engine.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/db/hashing/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/db/hashing/backend.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/db/hashing/blake3.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/db/models.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/db/query_context.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/db/repositories/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/db/repositories/artifact.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/db/repositories/collection.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/db/repositories/composite.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/db/repositories/hash_cache.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/db/repositories/job.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/db/repositories/label.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/db/repositories/session.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/db/schema.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/db/services/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/db/services/hashing.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/db/services/job_recording.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/db/services/lineage.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/db/services/session.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/db/step_priority.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/cluster/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/cluster/bridge.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/cluster/proxy.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/cluster/proxy_config.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/fragments/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/fragments/lineage.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/fragments/models.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/fragments/reconstitution.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/fragments/sessions.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/fragments/transport.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/framework/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/framework/contract.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/framework/planning.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/framework/registry.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/framework/runtime_imports.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/provenance/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/provenance/assembler.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/provenance/build_pip_collector.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/provenance/build_tool_collector.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/provenance/data_loader.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/provenance/package_collector.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/provenance/process_summarizer.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/provenance/runtime_collector.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/recording/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/recording/dataset_identifier.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/recording/dataset_metadata.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/recording/dataset_profile.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/recording/job_recording.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/reproduction/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/reproduction/installers.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/reproduction/pipeline_metadata.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/runtime/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/runtime/abi_probe.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/runtime/backup.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/runtime/driver_entrypoint.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/runtime/errors.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/runtime/host_execution.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/runtime/inject/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/runtime/inject/sitecustomize.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/runtime/inject/support.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/runtime/inject/tracker.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/runtime/lazy_install.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/runtime/proxy_resource.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/runtime/resources.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/runtime/signal_handler.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/runtime/tracer_backends.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/runtime/tracer_banner.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/execution/runtime/worker_bootstrap.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/filters/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/filters/files.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/filters/omit.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/glaas_auth.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/glaas_client.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/bootstrap.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/config/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/config/access.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/config/loader.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/config/raw.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/config/schema.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/discovery.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/download/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/download/base.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/download/gcs.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/download/get.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/download/hf.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/download/http.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/download/noop.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/download/s3.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/git/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/git/base.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/git/context.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/git/provider.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/glaas/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/glaas/auth.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/glaas/client.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/glaas/fragment_streamer.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/glaas/registration/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/glaas/registration/_artifact_ref.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/glaas/registration/coordinator.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/glaas/registration/job.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/glaas/registration/session.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/glaas/transport.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/registry.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/resolution.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/storage/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/storage/base.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/storage/gcs.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/storage/memory.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/storage/noop.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/storage/publish.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/storage/s3.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/telemetry/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/telemetry/base.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/integrations/telemetry/wandb.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/presenters/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/presenters/console.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/presenters/dag_data_builder.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/presenters/dag_renderer.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/presenters/diff_renderer.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/presenters/formatting.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/presenters/null.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/presenters/run_report.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/presenters/show_renderer.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/presenters/spinner.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/presenters/terminal.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/publish_auth.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/require.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/scope_config.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/telemetry/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/telemetry/_io.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/telemetry/capabilities.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/telemetry/config.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/telemetry/hooks.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/telemetry/install.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/telemetry/paths.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/telemetry/payload.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/telemetry/queue.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/telemetry/stats.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/telemetry/uploader.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/tui/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/tui/app.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/tui/data.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/tui/screens/config_editor.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/tui/screens/label_editor.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/tui/screens/launcher.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/tui/screens/log.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/tui/screens/main.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/tui/screens/search.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/tui/screens/session_picker.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/tui/tmux.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/tui/widgets/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/tui/widgets/detail.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/utils/__init__.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/utils/cloud.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/roar/version_check.py +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/Cargo.lock +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/Cargo.toml +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/crates/artifact-hash-core/Cargo.toml +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/crates/artifact-hash-core/src/lib.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/crates/artifact-hash-py/Cargo.toml +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/crates/artifact-hash-py/src/lib.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/crates/tracer-fd/Cargo.toml +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/crates/tracer-fd/src/lib.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/crates/tracer-runtime/Cargo.toml +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/crates/tracer-runtime/src/lib.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/crates/tracer-schema/Cargo.toml +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/crates/tracer-schema/src/lib.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/services/proxy/Cargo.lock +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/services/proxy/Cargo.toml +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/services/proxy/src/forward.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/services/proxy/src/main.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/services/proxy/src/s3.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/ebpf/common/Cargo.toml +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/ebpf/common/src/lib.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/ebpf/probe/Cargo.toml +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/ebpf/probe/rust-toolchain.toml +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/ebpf/probe/src/main.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/ebpf/userspace/Cargo.toml +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/ebpf/userspace/build.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/ebpf/userspace/src/attach.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/ebpf/userspace/src/bin/roard.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/ebpf/userspace/src/client.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/ebpf/userspace/src/daemon.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/ebpf/userspace/src/events.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/ebpf/userspace/src/ipc.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/ebpf/userspace/src/lib.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/ebpf/userspace/src/main.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/ebpf/userspace/src/state.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/preload/Cargo.toml +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/preload/build.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/preload/src/bin/io_fixture.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/preload/src/interpose.c +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/preload/src/ipc.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/preload/src/lib.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/preload/src/main.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/preload/tests/comprehensive.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/preload/tests/standalone.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/ptrace/Cargo.toml +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/ptrace/rustfmt.toml +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/ptrace/src/arch.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/ptrace/src/main.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/rust/tracers/ptrace/src/seccomp.rs +0 -0
- {roar_cli-0.3.5 → roar_cli-0.3.6}/scripts/sync_packaged_rust_artifacts.py +0 -0
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import subprocess
|
|
6
|
-
from dataclasses import dataclass
|
|
6
|
+
from dataclasses import dataclass, replace
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
9
|
from ..core.interfaces.logger import ILogger
|
|
10
10
|
from ..core.interfaces.registration import GitContext
|
|
11
11
|
from ..integrations.git import GitVCSProvider, resolve_git_context
|
|
12
|
+
from ..utils.git_url import is_shareable_remote
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
@dataclass(frozen=True)
|
|
@@ -68,6 +69,17 @@ def resolve_roar_git_context(
|
|
|
68
69
|
"""
|
|
69
70
|
logger.debug("Resolving git context from %s", path)
|
|
70
71
|
ctx = resolve_git_context(path, git_commit, configured_remote=configured_remote)
|
|
72
|
+
# A repo with no real remote records its own ``file://`` path as the URL.
|
|
73
|
+
# That resolves only on this machine, so publishing it both leaks the
|
|
74
|
+
# user's local filesystem layout to GLaaS and is useless to anyone else.
|
|
75
|
+
# This resolver is publish-only (register/put/package prep), so drop the
|
|
76
|
+
# non-shareable URL here — the publish record then honestly shows "no
|
|
77
|
+
# remote", matching the reproducibility checklist. (Local recording uses
|
|
78
|
+
# ``resolve_git_context`` directly and keeps the ``file://`` URI, which
|
|
79
|
+
# in-place reproduce relies on.)
|
|
80
|
+
if ctx.repo and not is_shareable_remote(ctx.repo):
|
|
81
|
+
logger.debug("Dropping non-shareable git repo URL from publish context: %s", ctx.repo)
|
|
82
|
+
ctx = replace(ctx, repo=None)
|
|
71
83
|
logger.debug(
|
|
72
84
|
"Git context resolved: repo=%s, commit=%s, branch=%s",
|
|
73
85
|
ctx.repo,
|
|
@@ -60,7 +60,8 @@ def _git_check_output(repo_root: Path | str, *args: str, capture_stderr: bool) -
|
|
|
60
60
|
)
|
|
61
61
|
|
|
62
62
|
|
|
63
|
-
def
|
|
63
|
+
def list_remote_names(repo_root: Path | str) -> list[str]:
|
|
64
|
+
"""Return the names of git remotes configured in this repo (empty if none)."""
|
|
64
65
|
try:
|
|
65
66
|
raw = _git_check_output(repo_root, "remote", capture_stderr=False)
|
|
66
67
|
except subprocess.CalledProcessError:
|
|
@@ -68,6 +69,10 @@ def _list_remote_names(repo_root: Path | str) -> list[str]:
|
|
|
68
69
|
return [line.strip() for line in raw.splitlines() if line.strip()]
|
|
69
70
|
|
|
70
71
|
|
|
72
|
+
# Back-compat alias for internal callers.
|
|
73
|
+
_list_remote_names = list_remote_names
|
|
74
|
+
|
|
75
|
+
|
|
71
76
|
def resolve_canonical_remote(repo_root: Path | str, configured_remote: str | None) -> str:
|
|
72
77
|
"""Return the name of the remote roar should push tags to.
|
|
73
78
|
|
|
@@ -469,8 +469,18 @@ class RegisterService:
|
|
|
469
469
|
|
|
470
470
|
composite_registered = sum(1 for item in composite_registrations if item.get("registered"))
|
|
471
471
|
composite_failed = sum(1 for item in composite_registrations if not item.get("registered"))
|
|
472
|
-
total_artifacts_registered = batch_result.artifacts_registered + composite_registered
|
|
473
472
|
total_artifacts_failed = batch_result.artifacts_failed + composite_failed
|
|
473
|
+
# Report DISTINCT artifacts, matching `register --dry-run`'s
|
|
474
|
+
# len(lineage.artifacts). The coordinator's running tally double-counts
|
|
475
|
+
# (artifacts are tallied in both the staging and the link phase, and the
|
|
476
|
+
# server's success count is per content-hash) — when everything
|
|
477
|
+
# registered, the distinct figure is simply the lineage's artifact count.
|
|
478
|
+
# The success gate below keys off *_failed, not this display number, so
|
|
479
|
+
# this is safe. On partial failure, fall back to the coordinator's tally.
|
|
480
|
+
if total_artifacts_failed == 0:
|
|
481
|
+
total_artifacts_registered = len(lineage.artifacts)
|
|
482
|
+
else:
|
|
483
|
+
total_artifacts_registered = batch_result.artifacts_registered + composite_registered
|
|
474
484
|
|
|
475
485
|
success = (
|
|
476
486
|
batch_result.jobs_failed == 0 and total_artifacts_failed == 0 and not finalize_failed
|
|
@@ -33,6 +33,7 @@ from ...core.interfaces.logger import ILogger
|
|
|
33
33
|
from ..git import build_roar_git_tag_name, create_roar_git_tag
|
|
34
34
|
from .git_remote import (
|
|
35
35
|
GitRemoteError,
|
|
36
|
+
list_remote_names,
|
|
36
37
|
push_roar_tags,
|
|
37
38
|
resolve_canonical_remote,
|
|
38
39
|
warn_if_ssh_passphrase_prompt_likely,
|
|
@@ -145,6 +146,21 @@ def ensure_roar_tags_pushed(
|
|
|
145
146
|
push_skipped_reason="never_config",
|
|
146
147
|
)
|
|
147
148
|
|
|
149
|
+
# No remote at all (and none configured): degrade to a local-only register
|
|
150
|
+
# instead of blocking. The common "does this work" loop shouldn't be gated on
|
|
151
|
+
# having a remote — and the dry-run never blocks, so the real run shouldn't
|
|
152
|
+
# contradict it. Tags exist locally; the reproducibility checklist surfaces
|
|
153
|
+
# that the commit isn't reachable on a remote. (An *invalid* configured
|
|
154
|
+
# remote or ambiguous multi-remote setup still errors below — those mean the
|
|
155
|
+
# user wants a push but roar can't safely pick where.)
|
|
156
|
+
if not configured_remote and not list_remote_names(repo_root):
|
|
157
|
+
logger.debug("No git remote configured — registering local-only (tags not pushed).")
|
|
158
|
+
return RegisterTagSummary(
|
|
159
|
+
session_tag=session_tag_name,
|
|
160
|
+
job_tags=job_tags,
|
|
161
|
+
push_skipped_reason="no_remote",
|
|
162
|
+
)
|
|
163
|
+
|
|
148
164
|
try:
|
|
149
165
|
remote = resolve_canonical_remote(repo_root, configured_remote)
|
|
150
166
|
except GitRemoteError as exc:
|
|
@@ -134,6 +134,9 @@ def build_registration_package(
|
|
|
134
134
|
git_context=git_context,
|
|
135
135
|
cwd=cwd,
|
|
136
136
|
)
|
|
137
|
+
redacted_lineage, redacted_git_context = _drop_local_remotes(
|
|
138
|
+
redacted_lineage, redacted_git_context
|
|
139
|
+
)
|
|
137
140
|
|
|
138
141
|
registration_jobs = order_jobs_for_registration(
|
|
139
142
|
normalize_jobs_for_registration(redacted_lineage.jobs)
|
|
@@ -263,6 +266,27 @@ def _apply_redaction(
|
|
|
263
266
|
)
|
|
264
267
|
|
|
265
268
|
|
|
269
|
+
def _drop_local_remotes(
|
|
270
|
+
lineage: LineageData, git_context: GitContext
|
|
271
|
+
) -> tuple[LineageData, GitContext]:
|
|
272
|
+
"""Don't publish non-shareable (``file://`` / local-path) git repos to GLaaS.
|
|
273
|
+
|
|
274
|
+
A repo with no real remote records its own ``file://`` path as ``git_repo``;
|
|
275
|
+
publishing that leaks the local filesystem path and is useless to anyone else.
|
|
276
|
+
Replace such repos with "" so the GLaaS record honestly shows no remote — the
|
|
277
|
+
reproducibility checklist already flags this as "commit reachable on a remote".
|
|
278
|
+
"""
|
|
279
|
+
from ...utils.git_url import is_shareable_remote
|
|
280
|
+
|
|
281
|
+
if git_context.repo and not is_shareable_remote(git_context.repo):
|
|
282
|
+
git_context = GitContext(repo="", commit=git_context.commit, branch=git_context.branch)
|
|
283
|
+
for job in lineage.jobs:
|
|
284
|
+
repo = job.get("git_repo")
|
|
285
|
+
if isinstance(repo, str) and repo and not is_shareable_remote(repo):
|
|
286
|
+
job["git_repo"] = ""
|
|
287
|
+
return lineage, git_context
|
|
288
|
+
|
|
289
|
+
|
|
266
290
|
def _filter_git_context(
|
|
267
291
|
git_context: GitContext,
|
|
268
292
|
omit_filter: OmitFilter | None,
|
|
@@ -49,6 +49,11 @@ class RegisterLineageResponse:
|
|
|
49
49
|
# the CLI surfaces a notice so the user knows it can't be reproduced from
|
|
50
50
|
# source. Defaults True so existing/normal registrations are unaffected.
|
|
51
51
|
reproducible: bool = True
|
|
52
|
+
# False when the session's steps span more than one git commit (the user
|
|
53
|
+
# committed between runs). Computed from the session's commit span — the
|
|
54
|
+
# SAME source `roar reproduce` uses — so the two checklists never disagree.
|
|
55
|
+
# Defaults True so single-commit/normal registrations are unaffected.
|
|
56
|
+
single_commit: bool = True
|
|
52
57
|
|
|
53
58
|
|
|
54
59
|
@dataclass(frozen=True)
|
|
@@ -94,3 +99,8 @@ class PutResponse:
|
|
|
94
99
|
git_tag: str | None = None
|
|
95
100
|
warnings: list[str] = field(default_factory=list)
|
|
96
101
|
error: str | None = None
|
|
102
|
+
# Reproducibility-checklist inputs, mirroring RegisterLineageResponse so
|
|
103
|
+
# `roar put` can render the same receipt as `roar register`.
|
|
104
|
+
reproducible: bool = True # the published run has a git commit
|
|
105
|
+
single_commit: bool = True # the session's steps share one commit
|
|
106
|
+
commit_on_remote: bool = False # the commit is reachable on a shareable remote
|
|
@@ -370,13 +370,13 @@ def _resolve_register_preview_git_context(*, path: Path, logger: Any) -> Any:
|
|
|
370
370
|
commit = _run_git(repo_root_path, "rev-parse", "HEAD")
|
|
371
371
|
branch = _run_git(repo_root_path, "rev-parse", "--abbrev-ref", "HEAD")
|
|
372
372
|
remote = _run_git(repo_root_path, "remote", "get-url", "origin")
|
|
373
|
-
|
|
373
|
+
# Publish-only preview: never record a local ``file://`` URI here. A repo
|
|
374
|
+
# with no shareable remote publishes as "no remote" (matching the real
|
|
375
|
+
# register path, which drops it in `resolve_roar_git_context`) rather than
|
|
376
|
+
# leaking the local filesystem path to GLaaS.
|
|
377
|
+
repo = remote if remote else None
|
|
374
378
|
if remote is None:
|
|
375
|
-
logger.debug(
|
|
376
|
-
"No git remote configured for %s; using local repository URI %s",
|
|
377
|
-
repo_root_path,
|
|
378
|
-
repo,
|
|
379
|
-
)
|
|
379
|
+
logger.debug("No git remote configured for %s; publishing with no remote", repo_root_path)
|
|
380
380
|
|
|
381
381
|
return GitContext(repo=repo, commit=commit, branch=branch)
|
|
382
382
|
|
|
@@ -436,6 +436,31 @@ def _form_lineage_composites_for_lineage(*, roar_dir: Path, lineage: Any, logger
|
|
|
436
436
|
return form_lineage_composites(db_ctx=form_db, job_ids=job_ids, logger=logger)
|
|
437
437
|
|
|
438
438
|
|
|
439
|
+
def _session_single_commit(*, roar_dir: Path, session_id: Any) -> bool:
|
|
440
|
+
"""True iff the session's steps all ran at one git commit.
|
|
441
|
+
|
|
442
|
+
Computed from the session's commit span (``git_commit_start`` vs
|
|
443
|
+
``git_commit_end``) — the SAME formula ``roar reproduce`` uses (see
|
|
444
|
+
``reproduce/lookup.py``) — so register's receipt and reproduce's preview can
|
|
445
|
+
never disagree on the "single git commit" check. The old proxy (extra job
|
|
446
|
+
tags) read False-positive whenever tagging was skipped (e.g. no remote),
|
|
447
|
+
silently mis-scoring multi-commit lineages as single-commit. Best-effort:
|
|
448
|
+
defaults True (the existing assume-single behavior) on any miss.
|
|
449
|
+
"""
|
|
450
|
+
if session_id is None:
|
|
451
|
+
return True
|
|
452
|
+
try:
|
|
453
|
+
with create_query_database_context(roar_dir) as db_ctx:
|
|
454
|
+
session = db_ctx.sessions.get(session_id)
|
|
455
|
+
except Exception:
|
|
456
|
+
return True
|
|
457
|
+
if not session:
|
|
458
|
+
return True
|
|
459
|
+
start = session.get("git_commit_start")
|
|
460
|
+
end = session.get("git_commit_end")
|
|
461
|
+
return not (start and end and start != end)
|
|
462
|
+
|
|
463
|
+
|
|
439
464
|
def _load_remote_job_uid_mapping(*, roar_dir: Path, session_id: Any) -> dict[str, str]:
|
|
440
465
|
"""Return the ``{local_job_uid: remote_job_uid}`` map registration persisted.
|
|
441
466
|
|
|
@@ -593,6 +618,12 @@ def register_lineage_target(request: RegisterLineageRequest) -> RegisterLineageR
|
|
|
593
618
|
except Exception as exc: # attribution is best-effort
|
|
594
619
|
logger.debug("anchor attribution skipped: %s", exc)
|
|
595
620
|
|
|
621
|
+
# Did the lineage span more than one git commit? Compute it the same way
|
|
622
|
+
# `roar reproduce` does (commit span), so the two checklists agree.
|
|
623
|
+
single_commit = _session_single_commit(
|
|
624
|
+
roar_dir=request.roar_dir, session_id=collected_lineage.session_id
|
|
625
|
+
)
|
|
626
|
+
|
|
596
627
|
# Collapse each job's dataset membership into consumes/produces view edges (a
|
|
597
628
|
# bloom over the touched leaves) and prune the subsumed leaves from the bundle.
|
|
598
629
|
# Pushed after the main registration. Best-effort.
|
|
@@ -637,7 +668,9 @@ def register_lineage_target(request: RegisterLineageRequest) -> RegisterLineageR
|
|
|
637
668
|
)
|
|
638
669
|
|
|
639
670
|
if request.dry_run:
|
|
640
|
-
|
|
671
|
+
from dataclasses import replace
|
|
672
|
+
|
|
673
|
+
preview = preview_register_lineage(
|
|
641
674
|
lineage=collected_lineage.lineage,
|
|
642
675
|
artifact_hash=collected_lineage.artifact_hash,
|
|
643
676
|
prepared=prepared,
|
|
@@ -645,6 +678,7 @@ def register_lineage_target(request: RegisterLineageRequest) -> RegisterLineageR
|
|
|
645
678
|
skip_confirmation=request.skip_confirmation,
|
|
646
679
|
confirm_callback=request.confirm_callback,
|
|
647
680
|
)
|
|
681
|
+
return replace(preview, single_commit=single_commit)
|
|
648
682
|
|
|
649
683
|
# P1-23: push roar tags BEFORE writing the GLaaS record so the
|
|
650
684
|
# record never references a tag that doesn't yet exist on the
|
|
@@ -743,33 +777,27 @@ def register_lineage_target(request: RegisterLineageRequest) -> RegisterLineageR
|
|
|
743
777
|
tag_summary=tag_summary,
|
|
744
778
|
warnings=warnings,
|
|
745
779
|
reproducible=bool(prepared.git_context.commit),
|
|
780
|
+
single_commit=single_commit,
|
|
746
781
|
)
|
|
747
782
|
except PublishAuthError as exc:
|
|
748
783
|
return RegisterLineageResponse(success=False, error=str(exc))
|
|
749
784
|
|
|
750
785
|
|
|
751
786
|
def _format_anonymous_tag_push_warning(tag_push_error: str) -> str:
|
|
752
|
-
"""
|
|
753
|
-
|
|
754
|
-
Anonymous register continues past
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
tag). We deliberately do *not* suggest
|
|
762
|
-
``git.push_tags_on_register=never`` here — that "fix" breaks
|
|
763
|
-
reproducibility for everyone viewing the GLaaS record, not just
|
|
764
|
-
silences a local warning.
|
|
787
|
+
"""One-line tag-push-failure warning for the anonymous register path.
|
|
788
|
+
|
|
789
|
+
Anonymous register continues past a push failure (GLaaS publish succeeds).
|
|
790
|
+
The "why a missing push matters" explanation now lives in the reproducibility
|
|
791
|
+
checklist's ``commit reachable on a remote`` item, so this stays terse: name
|
|
792
|
+
that the failure is git-remote auth (not GLaaS), that the record was still
|
|
793
|
+
registered, the fix, and the verbatim git error. (Deliberately not suggesting
|
|
794
|
+
``git.push_tags_on_register=never`` — that "fix" breaks reproducibility for
|
|
795
|
+
everyone reading the record, it doesn't just silence the warning.)
|
|
765
796
|
"""
|
|
766
797
|
return (
|
|
767
|
-
"roar tag push to git remote failed (git auth, not GLaaS) — "
|
|
768
|
-
"
|
|
769
|
-
"
|
|
770
|
-
"on the remote to reproduce.\n"
|
|
771
|
-
" Fix git remote auth, then push: `git push <remote> <tag>`.\n"
|
|
772
|
-
f" Verbatim git error: {tag_push_error}"
|
|
798
|
+
"roar tag push to the git remote failed (git auth, not GLaaS) — registered "
|
|
799
|
+
"without it; the 'commit reachable on a remote' check flags this. "
|
|
800
|
+
f"Fix git remote auth and re-push (`git push <remote> <tag>`). git: {tag_push_error}"
|
|
773
801
|
)
|
|
774
802
|
|
|
775
803
|
|
|
@@ -787,6 +815,9 @@ def put_artifacts(request: PutRequest) -> PutResponse:
|
|
|
787
815
|
)
|
|
788
816
|
|
|
789
817
|
repo_root = request.repo_root or request.cwd
|
|
818
|
+
# Reproducibility-checklist facts, filled in on the real (non-dry-run) path.
|
|
819
|
+
put_single_commit = True
|
|
820
|
+
put_commit_on_remote = False
|
|
790
821
|
if request.dry_run:
|
|
791
822
|
git_state = None
|
|
792
823
|
git_commit = None
|
|
@@ -842,6 +873,17 @@ def put_artifacts(request: PutRequest) -> PutResponse:
|
|
|
842
873
|
logger=logger,
|
|
843
874
|
)
|
|
844
875
|
|
|
876
|
+
# Reproducibility facts for the receipt: same commit-span source as
|
|
877
|
+
# register/reproduce, and whether the commit is reachable on a real
|
|
878
|
+
# remote (git_context.repo is None here when no shareable remote —
|
|
879
|
+
# resolve_roar_git_context drops local file:// URIs).
|
|
880
|
+
from ...utils.git_url import is_shareable_remote
|
|
881
|
+
|
|
882
|
+
put_single_commit = _session_single_commit(
|
|
883
|
+
roar_dir=request.roar_dir, session_id=prepared.session_id
|
|
884
|
+
)
|
|
885
|
+
put_commit_on_remote = is_shareable_remote(prepared.git_context.repo)
|
|
886
|
+
|
|
845
887
|
result = service.put_prepared(
|
|
846
888
|
prepared=prepared,
|
|
847
889
|
sources=request.sources,
|
|
@@ -886,6 +928,9 @@ def put_artifacts(request: PutRequest) -> PutResponse:
|
|
|
886
928
|
git_tag=created_git_tag,
|
|
887
929
|
warnings=warnings,
|
|
888
930
|
error=result.error,
|
|
931
|
+
reproducible=bool(git_commit),
|
|
932
|
+
single_commit=put_single_commit,
|
|
933
|
+
commit_on_remote=put_commit_on_remote,
|
|
889
934
|
)
|
|
890
935
|
|
|
891
936
|
|
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import json
|
|
6
6
|
import os
|
|
7
|
+
import subprocess
|
|
7
8
|
from pathlib import Path
|
|
8
9
|
from typing import Any
|
|
9
10
|
|
|
@@ -29,16 +30,45 @@ def render_inputs(request: InputsQueryRequest) -> str:
|
|
|
29
30
|
return summary.message
|
|
30
31
|
|
|
31
32
|
lines: list[str] = []
|
|
33
|
+
any_unsourced = any(a.unsourced for a in summary.artifacts)
|
|
34
|
+
tmp_unsourced = sum(
|
|
35
|
+
1 for a in summary.artifacts if a.unsourced and is_ephemeral_tmp_path(a.path)
|
|
36
|
+
)
|
|
32
37
|
for art in summary.artifacts:
|
|
33
38
|
digest = _short_digest(art.hashes)
|
|
34
39
|
path = art.path or "(no path)"
|
|
35
|
-
if
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
marker = "⚠ " if art.unsourced else (" " if any_unsourced else "")
|
|
41
|
+
suffix = f" {digest}" if digest else ""
|
|
42
|
+
lines.append(f"{marker}{path}{suffix}")
|
|
43
|
+
if any_unsourced:
|
|
44
|
+
lines.append("")
|
|
45
|
+
lines.append(
|
|
46
|
+
"⚠ unsourced: nothing tracked produced this file, so it won't exist on another machine."
|
|
47
|
+
)
|
|
48
|
+
lines.append(
|
|
49
|
+
" Make it reproducible — commit code to a git repo, or ingest data with "
|
|
50
|
+
"`roar get <url>` / `roar run wget <url>`."
|
|
51
|
+
)
|
|
52
|
+
if tmp_unsourced:
|
|
53
|
+
lines.append(
|
|
54
|
+
f"⚠ {tmp_unsourced} in /tmp — these definitely won't survive; "
|
|
55
|
+
"move into your project or ingest with `roar get`."
|
|
56
|
+
)
|
|
39
57
|
return "\n".join(lines)
|
|
40
58
|
|
|
41
59
|
|
|
60
|
+
def is_ephemeral_tmp_path(path: str | None) -> bool:
|
|
61
|
+
"""True for an input under an ephemeral tmp dir (Linux /tmp, macOS var/folders).
|
|
62
|
+
|
|
63
|
+
Such a file is guaranteed not to exist when the lineage is reproduced on
|
|
64
|
+
another machine — a sharper, more certain failure than generic
|
|
65
|
+
unsourcedness, so it warrants its own escalated warning.
|
|
66
|
+
"""
|
|
67
|
+
if not path:
|
|
68
|
+
return False
|
|
69
|
+
return path.startswith("/tmp/") or "/private/var/folders/" in path
|
|
70
|
+
|
|
71
|
+
|
|
42
72
|
def _short_digest(hashes: list[ShowHashSummary]) -> str:
|
|
43
73
|
"""Return a short display digest like 'blake3:abcdef01...'."""
|
|
44
74
|
for h in hashes:
|
|
@@ -67,14 +97,20 @@ def build_inputs_summary(request: InputsQueryRequest) -> InputsSummary:
|
|
|
67
97
|
message=f'"{target_label}" is a root artifact (no upstream inputs)',
|
|
68
98
|
)
|
|
69
99
|
|
|
100
|
+
git_tracked = _git_tracked_paths(request.cwd)
|
|
70
101
|
if request.direct:
|
|
71
|
-
artifacts = _get_direct_inputs(db_ctx, target_artifact_ids)
|
|
102
|
+
artifacts = _get_direct_inputs(db_ctx, target_artifact_ids, git_tracked)
|
|
72
103
|
elif request.show_all:
|
|
73
104
|
artifacts = _walk_upstream_all(
|
|
74
|
-
db_ctx, target_artifact_ids, exclude=set(target_artifact_ids)
|
|
105
|
+
db_ctx, target_artifact_ids, git_tracked, exclude=set(target_artifact_ids)
|
|
75
106
|
)
|
|
76
107
|
else:
|
|
77
|
-
artifacts = _walk_upstream_roots(db_ctx, target_artifact_ids)
|
|
108
|
+
artifacts = _walk_upstream_roots(db_ctx, target_artifact_ids, git_tracked)
|
|
109
|
+
|
|
110
|
+
if request.unsourced:
|
|
111
|
+
artifacts = [a for a in artifacts if a.unsourced]
|
|
112
|
+
elif request.sourced:
|
|
113
|
+
artifacts = [a for a in artifacts if not a.unsourced]
|
|
78
114
|
|
|
79
115
|
return InputsSummary(
|
|
80
116
|
target_ref=target_label,
|
|
@@ -201,7 +237,56 @@ def _is_root_artifact(db_ctx, artifact_id: str) -> bool:
|
|
|
201
237
|
return len(inputs) == 0
|
|
202
238
|
|
|
203
239
|
|
|
204
|
-
def
|
|
240
|
+
def _git_tracked_paths(cwd: Path) -> frozenset[str]:
|
|
241
|
+
"""Absolute paths of every file git tracks in ``cwd``'s repo (empty if none).
|
|
242
|
+
|
|
243
|
+
Used to recognise inputs that are *sourced by git*: a producer-less file that
|
|
244
|
+
git tracks is restored by ``roar reproduce`` (it checks out the commit), so
|
|
245
|
+
it is NOT unsourced even though nothing in the lineage produced it.
|
|
246
|
+
"""
|
|
247
|
+
try:
|
|
248
|
+
root = subprocess.run(
|
|
249
|
+
["git", "rev-parse", "--show-toplevel"],
|
|
250
|
+
cwd=str(cwd),
|
|
251
|
+
capture_output=True,
|
|
252
|
+
text=True,
|
|
253
|
+
check=False,
|
|
254
|
+
).stdout.strip()
|
|
255
|
+
if not root:
|
|
256
|
+
return frozenset()
|
|
257
|
+
out = subprocess.run(
|
|
258
|
+
["git", "ls-files", "-z"], cwd=root, capture_output=True, text=True, check=False
|
|
259
|
+
)
|
|
260
|
+
except OSError:
|
|
261
|
+
return frozenset()
|
|
262
|
+
return frozenset(os.path.join(root, p) for p in out.stdout.split("\0") if p)
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def _sourced_by_git(artifact: dict[str, Any] | None, git_tracked: frozenset[str]) -> bool:
|
|
266
|
+
"""True iff a producer-less artifact is still recoverable because git tracks it."""
|
|
267
|
+
path = (artifact or {}).get("first_seen_path") or ""
|
|
268
|
+
return bool(path) and os.path.abspath(path) in git_tracked
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def _is_unsourced(db_ctx, artifact_id: str, git_tracked: frozenset[str]) -> bool:
|
|
272
|
+
"""True iff this artifact won't exist on another machine.
|
|
273
|
+
|
|
274
|
+
Distinct from ``_is_root_artifact``: a producer-with-no-inputs (e.g. a
|
|
275
|
+
``roar get`` source node, a ``roar run wget`` download, or a deterministic
|
|
276
|
+
generator) is a root but IS sourced — it re-runs on reproduce. An artifact
|
|
277
|
+
with no producer is sourced only if git tracks it (``roar reproduce`` checks
|
|
278
|
+
out the commit and restores it); otherwise it's truly unsourced (a
|
|
279
|
+
pre-existing, un-ingested, uncommitted file).
|
|
280
|
+
"""
|
|
281
|
+
produced_by = db_ctx.artifacts.get_jobs(artifact_id).get("produced_by", [])
|
|
282
|
+
if produced_by:
|
|
283
|
+
return False
|
|
284
|
+
return not _sourced_by_git(db_ctx.artifacts.get(artifact_id), git_tracked)
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def _make_artifact_summary(
|
|
288
|
+
artifact: dict[str, Any], *, unsourced: bool = False
|
|
289
|
+
) -> InputArtifactSummary:
|
|
205
290
|
"""Build an InputArtifactSummary from a raw artifact dict."""
|
|
206
291
|
return InputArtifactSummary(
|
|
207
292
|
artifact_id=str(artifact["id"]),
|
|
@@ -214,10 +299,13 @@ def _make_artifact_summary(artifact: dict[str, Any]) -> InputArtifactSummary:
|
|
|
214
299
|
)
|
|
215
300
|
for h in artifact.get("hashes", [])
|
|
216
301
|
],
|
|
302
|
+
unsourced=unsourced,
|
|
217
303
|
)
|
|
218
304
|
|
|
219
305
|
|
|
220
|
-
def _walk_upstream_roots(
|
|
306
|
+
def _walk_upstream_roots(
|
|
307
|
+
db_ctx, start_artifact_ids: list[str], git_tracked: frozenset[str]
|
|
308
|
+
) -> list[InputArtifactSummary]:
|
|
221
309
|
"""Walk the DAG upstream and collect only root artifacts (no producer)."""
|
|
222
310
|
roots: dict[str, InputArtifactSummary] = {}
|
|
223
311
|
visited: set[str] = set()
|
|
@@ -235,18 +323,22 @@ def _walk_upstream_roots(db_ctx, start_artifact_ids: list[str]) -> list[InputArt
|
|
|
235
323
|
produced_by = jobs.get("produced_by", [])
|
|
236
324
|
|
|
237
325
|
if not produced_by:
|
|
238
|
-
# No producer
|
|
326
|
+
# No producer — unsourced unless git tracks it (reproduce restores
|
|
327
|
+
# a committed file from the recorded commit).
|
|
239
328
|
artifact = db_ctx.artifacts.get(artifact_id)
|
|
240
329
|
if artifact:
|
|
241
|
-
roots[artifact_id] = _make_artifact_summary(
|
|
330
|
+
roots[artifact_id] = _make_artifact_summary(
|
|
331
|
+
artifact, unsourced=not _sourced_by_git(artifact, git_tracked)
|
|
332
|
+
)
|
|
242
333
|
else:
|
|
243
334
|
producer = produced_by[0]
|
|
244
335
|
inputs = db_ctx.jobs.get_inputs(producer["id"])
|
|
245
336
|
if not inputs:
|
|
246
|
-
# Producer has no inputs (e.g., roar get
|
|
337
|
+
# Producer has no inputs (e.g., roar get / wget / a generator) —
|
|
338
|
+
# a root, but SOURCED: it re-runs on reproduce.
|
|
247
339
|
artifact = db_ctx.artifacts.get(artifact_id)
|
|
248
340
|
if artifact:
|
|
249
|
-
roots[artifact_id] = _make_artifact_summary(artifact)
|
|
341
|
+
roots[artifact_id] = _make_artifact_summary(artifact, unsourced=False)
|
|
250
342
|
else:
|
|
251
343
|
for inp in inputs:
|
|
252
344
|
_trace(inp["artifact_id"])
|
|
@@ -259,7 +351,9 @@ def _walk_upstream_roots(db_ctx, start_artifact_ids: list[str]) -> list[InputArt
|
|
|
259
351
|
return list(roots.values())
|
|
260
352
|
|
|
261
353
|
|
|
262
|
-
def _get_direct_inputs(
|
|
354
|
+
def _get_direct_inputs(
|
|
355
|
+
db_ctx, start_artifact_ids: list[str], git_tracked: frozenset[str]
|
|
356
|
+
) -> list[InputArtifactSummary]:
|
|
263
357
|
"""Get only the immediate inputs (one level up)."""
|
|
264
358
|
seen: dict[str, InputArtifactSummary] = {}
|
|
265
359
|
|
|
@@ -274,13 +368,19 @@ def _get_direct_inputs(db_ctx, start_artifact_ids: list[str]) -> list[InputArtif
|
|
|
274
368
|
if aid not in seen:
|
|
275
369
|
artifact = db_ctx.artifacts.get(aid)
|
|
276
370
|
if artifact:
|
|
277
|
-
seen[aid] = _make_artifact_summary(
|
|
371
|
+
seen[aid] = _make_artifact_summary(
|
|
372
|
+
artifact, unsourced=_is_unsourced(db_ctx, aid, git_tracked)
|
|
373
|
+
)
|
|
278
374
|
|
|
279
375
|
return list(seen.values())
|
|
280
376
|
|
|
281
377
|
|
|
282
378
|
def _walk_upstream_all(
|
|
283
|
-
db_ctx,
|
|
379
|
+
db_ctx,
|
|
380
|
+
start_artifact_ids: list[str],
|
|
381
|
+
git_tracked: frozenset[str],
|
|
382
|
+
*,
|
|
383
|
+
exclude: set[str] | None = None,
|
|
284
384
|
) -> list[InputArtifactSummary]:
|
|
285
385
|
"""Walk the DAG upstream and collect all artifacts (intermediates + roots)."""
|
|
286
386
|
exclude = exclude or set()
|
|
@@ -296,13 +396,16 @@ def _walk_upstream_all(
|
|
|
296
396
|
visited.add(artifact_id)
|
|
297
397
|
path_stack.add(artifact_id)
|
|
298
398
|
|
|
399
|
+
# Fetch producers once; reuse for both the unsourced flag and traversal.
|
|
400
|
+
jobs = db_ctx.artifacts.get_jobs(artifact_id)
|
|
401
|
+
produced_by = jobs.get("produced_by", [])
|
|
402
|
+
|
|
299
403
|
if artifact_id not in exclude:
|
|
300
404
|
artifact = db_ctx.artifacts.get(artifact_id)
|
|
301
405
|
if artifact:
|
|
302
|
-
|
|
406
|
+
unsourced = not produced_by and not _sourced_by_git(artifact, git_tracked)
|
|
407
|
+
collected[artifact_id] = _make_artifact_summary(artifact, unsourced=unsourced)
|
|
303
408
|
|
|
304
|
-
jobs = db_ctx.artifacts.get_jobs(artifact_id)
|
|
305
|
-
produced_by = jobs.get("produced_by", [])
|
|
306
409
|
if produced_by:
|
|
307
410
|
producer = produced_by[0]
|
|
308
411
|
inputs = db_ctx.jobs.get_inputs(producer["id"])
|
|
@@ -343,6 +343,10 @@ class InputArtifactSummary:
|
|
|
343
343
|
path: str
|
|
344
344
|
size: int
|
|
345
345
|
hashes: list[ShowHashSummary] = field(default_factory=list)
|
|
346
|
+
# True when nothing tracked produced this artifact (no producing job and not
|
|
347
|
+
# ingested via `roar get` / `roar run wget`). Such inputs won't exist on
|
|
348
|
+
# another machine, so the lineage that consumes them isn't reproducible.
|
|
349
|
+
unsourced: bool = False
|
|
346
350
|
|
|
347
351
|
|
|
348
352
|
@dataclass(frozen=True)
|
|
@@ -116,6 +116,59 @@ def render_status(request: StatusQueryRequest) -> str:
|
|
|
116
116
|
return "\n".join(lines)
|
|
117
117
|
|
|
118
118
|
|
|
119
|
+
def session_output_paths(roar_dir) -> list[str]:
|
|
120
|
+
"""Filesystem paths of the active session's distinct output artifacts.
|
|
121
|
+
|
|
122
|
+
A lightweight counterpart to ``build_status_summary``: no publish-auth
|
|
123
|
+
resolution and no canonical dag-hash — just the paths. Callers like the
|
|
124
|
+
artifact-path reproducibility check need only the paths, and must not trigger
|
|
125
|
+
auth side effects (resolving SSH/creator identity would, e.g., inject a
|
|
126
|
+
signed request into an otherwise-anonymous publish).
|
|
127
|
+
"""
|
|
128
|
+
with create_query_database_context(roar_dir) as db_ctx:
|
|
129
|
+
session = db_ctx.sessions.get_active()
|
|
130
|
+
if not session:
|
|
131
|
+
return []
|
|
132
|
+
distinct_outputs = getattr(db_ctx.jobs, "get_distinct_outputs_by_session", None)
|
|
133
|
+
if callable(distinct_outputs):
|
|
134
|
+
outputs = distinct_outputs(session["id"])
|
|
135
|
+
else:
|
|
136
|
+
seen: set[int | str] = set()
|
|
137
|
+
outputs = []
|
|
138
|
+
for job in db_ctx.jobs.get_by_session(session["id"], limit=10000):
|
|
139
|
+
for output in db_ctx.jobs.get_outputs(job["id"]):
|
|
140
|
+
if output["artifact_id"] not in seen:
|
|
141
|
+
seen.add(output["artifact_id"])
|
|
142
|
+
outputs.append(output)
|
|
143
|
+
return [str(output["path"]) for output in outputs if output["path"]]
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def render_untracked_dirs(request: StatusQueryRequest, cwd) -> str:
|
|
147
|
+
"""Focused view: the session's output artifacts whose directory won't exist
|
|
148
|
+
on a clean checkout (untracked in-repo dirs, or paths outside the repo).
|
|
149
|
+
|
|
150
|
+
Backs the `all artifact paths in tracked directories` reproducibility check;
|
|
151
|
+
surfaced as `roar status --untracked-dirs` so the user can see exactly which
|
|
152
|
+
paths the check is flagging."""
|
|
153
|
+
from ..reproducibility.report import untracked_artifact_dirs
|
|
154
|
+
|
|
155
|
+
paths = untracked_artifact_dirs(request.roar_dir, cwd)
|
|
156
|
+
if paths is None:
|
|
157
|
+
return "Not in a git repository — artifact-path tracking doesn't apply."
|
|
158
|
+
if not paths:
|
|
159
|
+
return "All artifact paths are in tracked directories."
|
|
160
|
+
|
|
161
|
+
lines = [f"Artifacts in untracked directories ({len(paths)}):"]
|
|
162
|
+
lines.extend(f" {path}" for path in paths)
|
|
163
|
+
lines.append("")
|
|
164
|
+
lines.append(
|
|
165
|
+
"These directories won't exist on a clean checkout, so reproduction may "
|
|
166
|
+
"fail unless the run recreates them."
|
|
167
|
+
)
|
|
168
|
+
lines.append("Add a .gitkeep (or any tracked file) to each so a fresh checkout includes it.")
|
|
169
|
+
return "\n".join(lines)
|
|
170
|
+
|
|
171
|
+
|
|
119
172
|
def build_status_summary(request: StatusQueryRequest) -> StatusSummary:
|
|
120
173
|
"""Build a typed summary of the active session status."""
|
|
121
174
|
with create_query_database_context(request.roar_dir) as db_ctx:
|