freesolo-flash-dev 1.2.49__tar.gz → 1.2.52__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.
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/CHANGELOG.md +10 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/PKG-INFO +1 -1
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/_lifecycle/poll_instance.py +79 -174
- freesolo_flash_dev-1.2.52/flash/providers/_lifecycle/terminal_artifacts.py +261 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/runner/supervise/recovery.py +33 -54
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/pyproject.toml +2 -2
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_runmgmt.py +110 -0
- freesolo_flash_dev-1.2.52/tests/test_terminal_artifacts.py +181 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/uv.lock +1 -1
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/.dockerignore +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/.env.example +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/.github/CODEOWNERS +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/.github/dependabot.yml +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/.github/workflows/auto-rebake.yml +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/.github/workflows/bake-kernel-cache.yml +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/.github/workflows/ci.yml +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/.github/workflows/main-source-guard.yml +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/.github/workflows/notify-tests-repo.yml +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/.github/workflows/publish-dev.yml +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/.github/workflows/publish-image.yml +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/.github/workflows/publish.yml +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/.github/workflows/version-parity.yml +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/.github/workflows/worker-image.yml +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/.gitignore +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/CODE_OF_CONDUCT.md +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/CONTRIBUTING.md +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/Dockerfile +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/Dockerfile.worker +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/LICENSE +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/NOTICE +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/README.md +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/SECURITY.md +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/SELF_HOSTING.md +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/build/kernel_cache/.gitignore +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/build/kernel_cache/.keep +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/deploy/infisical/README.md +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/deploy/infisical/entrypoint.sh +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/docker/Dockerfile.kernelcache +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/docker/Dockerfile.kernelcache.relayer +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/docker/bake_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/docker/bake_pod_entry.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/docker/extract_cudart_fix.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/docker/kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/docker/make_rp_handler.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/_internal/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/_internal/channel.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/_internal/diagnostics.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/_internal/fileio.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/_internal/logging.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/_internal/paths.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/adapters/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/adapters/artifacts.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/adapters/fused_experts.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/adapters/lora_rank.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/__main__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/commands/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/commands/deploy.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/commands/env/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/commands/env/episode.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/commands/env/eval.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/commands/env/eval_args.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/commands/env/imports.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/commands/env/list.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/commands/env/push.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/commands/env/retained.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/commands/env/setup.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/commands/env/test.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/commands/env/test_evaluations.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/commands/env/test_params.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/commands/env/test_warnings.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/commands/prompt_budget.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/commands/traces.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/commands/train_cost.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/scaffold/TRAINING.md +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/scaffold/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/ui/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/ui/cost.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/ui/env_panels.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/ui/heartbeat.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/ui/render.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/ui/tables.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cli/ui/tty.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/client/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/client/config.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/client/freesolo_api.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/client/http.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/client/runtime_secrets.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/client/shapes.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/client/specs.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/client/streaming.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/content/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/content/multimodal.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/content/structured_outputs.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/content/thinking.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/core/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/core/catalog.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/core/spec.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/core/spec_persistence.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cost/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cost/analytical.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cost/facts.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cost/spec.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/cost/types.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/plan/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/plan/kv_sizing.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/plan/model_config_probe.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/plan/prompt_budget.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/plan/recipe.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/plan/steps.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/plan/vram.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/profiling/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/profiling/dataset_profile.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/profiling/reasoning_render.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/profiling/sft_workload.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/profiling/tokenizer.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/profiling/workload_profile.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/result/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/result/accounting.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/result/rollout_samples.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/__main__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/backend_common.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/entry/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/entry/opd.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/entry/rl.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/entry/sft.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/io/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/io/heartbeat.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/io/hf.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/io/prefetch.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/io/wandb_log.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/model/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/model/adapter.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/model/chatml_mask.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/model/decoding.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/model/lora.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/model/packing.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/opd_train.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/opd_train_runner.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/perf/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/perf/diagnostics.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/perf/lifecycle.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/perf/liger.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/perf/memory.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/rl_train.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/rl_train_runner.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/runtime/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/runtime/kernel_warmup.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/runtime/pkg_proxy.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/runtime/rng.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/score_batcher.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/sft_train.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/sft_train_runner.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/teacher/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/teacher/client.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/teacher/encoding.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/teacher/tokenizer_align.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/core/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/core/checkpoint_lifecycle.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/core/child/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/core/child/glue.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/core/child/runtime.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/core/step_timing.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/finalize.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/opd/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/opd/batching.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/opd/bridge.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/opd/child/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/opd/child/bridge.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/opd/child/entry.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/opd/child/multiturn.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/opd/child/plugin.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/opd/child/replay_guard.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/opd/child/runtime.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/opd/child/structured.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/opd/failures.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/opd/gkd.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/opd/multiturn_validation.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/opd/overrides.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/opd/prompts.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/opd/reporting.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/opd/scoring.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/opd/state.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/opd/validation.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/rl/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/rl/checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/rl/child/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/rl/child/entry.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/rl/child/multiturn.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/rl/child/patches.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/rl/child/plugin.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/rl/config.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/rl/inputs.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/rl/multi_turn.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/rl/reward_module.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/rl/scoring.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/rl/single_turn.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/rl/verl_config.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/sft/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/sft/checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/sft/child/entry.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/sft/child/plugin.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/train/sft/config.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/verl/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/verl/capabilities.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/verl/checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/verl/child_io.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/verl/diagnostics.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/verl/parallelism.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker/verl/parent_work.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/engine/worker_entrypoint.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/envs/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/envs/adapter.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/envs/base.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/envs/cache_security.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/envs/dataset_selection.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/envs/evaluations.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/envs/identity.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/envs/loader.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/envs/namespace_listing.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/envs/package/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/envs/package/limits.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/envs/package/unpack.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/envs/pull.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/_lifecycle/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/_lifecycle/auth.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/_lifecycle/bootstrap.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/_lifecycle/bootstrap_console.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/_lifecycle/bootstrap_pip.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/_lifecycle/bootstrap_secrets.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/_lifecycle/deadline.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/_lifecycle/http.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/_lifecycle/instance.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/_lifecycle/poll.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/_lifecycle/provider.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/_lifecycle/worker.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/allocator.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/artifacts/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/artifacts/hf.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/artifacts/preload_runpod.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/artifacts/weight_cache.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/base.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/fit_errors.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/lambda_/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/lambda_/api.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/lambda_/auth.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/lambda_/gpus.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/lambda_/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/lambda_/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/lambda_/jobs/reap.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/lambda_/preflight.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/lambda_/pricing.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/preflight.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/realized.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/runpod/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/runpod/api.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/runpod/auth.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/runpod/cost.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/runpod/gpus.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/runpod/job_execution.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/runpod/jobs.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/runpod/preflight.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/runpod/pricing.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/runpod/resources.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/runpod/serverless/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/runpod/serverless/endpoints.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/sharding.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/vast/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/vast/api.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/vast/auth.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/vast/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/vast/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/vast/preflight.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/vast/pricing.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/py.typed +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/runner/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/runner/artifacts.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/runner/attempts.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/runner/costs.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/runner/deadlines.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/runner/preparation.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/runner/reconciliation.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/runner/results/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/runner/results/checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/runner/results/verified_revisions.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/runner/status.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/runner/submit.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/runner/supervise/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/runner/supervise/attach.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/runner/supervise/deploy.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/runner/supervise/lifecycle.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/runner/supervise/retry_decision.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/runner/supervise/seed_submission.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/runner/supervise/transitions.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/runner/weight_cache.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/schema/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/schema/fields.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/serve/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/serve/adapter_check.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/serve/deploy.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/serve/errors.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/serve/export.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/serve/preflight.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/serve/responses.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/serve/streaming.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/serve/thinking.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/serve/urls.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/__main__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/app.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/billing/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/billing/charges.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/billing/retry.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/domain/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/domain/checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/domain/environment_registry.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/domain/envs.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/domain/projects.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/domain/reconcile.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/domain/repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/domain/run_registry.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/domain/teacher_broker.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/domain/teacher_errors.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/domain/teacher_requests.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/platform/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/platform/auth.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/platform/db.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/platform/deps.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/platform/internal_client.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/platform/locks.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/platform/runtime.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/routes/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/routes/envs.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/routes/meta.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/routes/runs.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/routes/serving.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/routes/serving_completion.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/routes/serving_revisions.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/routes/serving_smoke.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/server/routes/teacher.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/teacher/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/teacher/limits.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/teacher/retry_contract.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/scripts/build_dev_dist.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/scripts/check_file_size.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/scripts/check_function_size.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/scripts/check_verl_pin_exists.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/scripts/scrub_history.sh +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/_helpers/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/_helpers/profile.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/_helpers/runner.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/_helpers/specs.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/_helpers/teacher.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/_helpers/vast.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/conftest.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/fixtures/math_eval.jsonl +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/fixtures/math_train.jsonl +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/live/__init__.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/live/conftest.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/live/test_lambda_live.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/live/test_runpod_live.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/live/test_sft_thinking_render_live.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/live/test_vast_live.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_accounting_coverage.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_adapter_shard_completeness.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_agent_flash_cli_contract.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_algorithms.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_allocator.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_backend_common.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_backend_jobspec_contract.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_bake_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_base_model_provenance.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_billing_retry.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_build_context_contract.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_cancel_remote.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_catalog_consistency.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_catalog_only_models.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_charge_pricing.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_checkpoint_lifecycle.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_cli_commands.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_cli_commands_coverage.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_cli_credential_shadowing.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_cli_errors.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_cli_estimate.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_cli_gpus_flag.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_cli_help.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_cli_main_coverage.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_cli_managed.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_cli_render_coverage.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_cli_render_theme.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_cli_traces.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_cli_wandb_warning.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_client.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_client_import_purity.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_client_server_integration.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_client_stream_reads.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_config_env_vars.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_config_overrides.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_console_upload.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_controlled_experiment_repairs.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_cost_analytical.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_cost_equation.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_cost_estimate.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_cost_hardware.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_cost_models.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_dataset_profile.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_deploy_alias_move_warning.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_deploy_latency.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_dev_channel.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_disk_gb.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_endpoint_name.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_env_cache_evict.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_env_delete.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_env_download.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_env_download_api.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_env_evaluations.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_env_list_api.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_env_list_cli.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_env_list_hub.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_env_no_install.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_env_publish.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_env_pull.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_env_pull_coverage.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_env_pull_loader_coverage.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_env_pull_managed_control_plane.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_env_push.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_env_rate_limit_resolve.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_env_ref_pinning.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_env_test.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_envs_coverage.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_export.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_flash_mvp.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_flash_worker.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_flashinfer_cache_dirs.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_freesolo_api_transport.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_fused_expert_warmstart.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_github_urlopen_retry.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_gpu_type_single_field.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_gpus.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_grpo_params.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_grpo_resident_sizing.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_grpo_reward_batching.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_health_liveness.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_hf_retry.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_idle_endpoint_reaper.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_infisical_secrets.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_instance_bootstrap_coverage.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_internal_client.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_jobs.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_kv_util.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_lambda_api_coverage.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_lambda_runner.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_logging.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_login_perms.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_lora_rank_coverage.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_lora_rank_preflight.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_managed_config_fields.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_managed_hf_repo.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_metrics_schema_agent_contract.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_mig_guard.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_multi_gpu_gate.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_multimodal_training.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_named_reward_metrics.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_oom_escalate_gpu.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_opd.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_opd_limits.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_opd_multiturn_eos_boundary.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_opd_multiturn_failure_exit.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_opd_replay_guard.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_opd_resume_safety.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_opd_train.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_orchestrator_flash.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_packing.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_packing_coverage.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_parasail_teacher.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_poll_helpers.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_preflight.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_projects.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_prompt_budget.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_provider_preflight_coverage.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_provider_routing.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_provider_teardown_robustness.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_providers_symmetry.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_realized_cost.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_resolve_params_b.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_resume_on_retry.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_rl_train.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_rollout_samples.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_runpod_api_delete.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_runpod_key_fingerprint.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_runpod_key_waterfall.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_serve.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_serve_reasoning_content.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_server_api.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_server_app_coverage.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_server_auth_singleflight.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_server_billing.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_server_checkpoints_coverage.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_server_db.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_server_envs_coverage.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_server_locks_coverage.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_server_standalone.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_serving_context_preflight.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_serving_contract.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_serving_schema_coverage.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_sft_chunked_nll.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_sft_example_selection.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_sft_gc_off.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_sft_max_context.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_sft_startup_block.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_sft_train.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_sft_workload.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_spec_and_validation.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_spec_contract_bytes.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_step_floor.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_step_metrics.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_step_timing.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_structured_outputs.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_teacher_broker.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_teacher_encoding_contract.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_thinking_config.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_train_context_preflight.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_training_controls.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_type_comment_prose.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_vast_api.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_vast_api_coverage.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_vast_offers.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_vast_provider_coverage.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_vast_runner.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_verified_revisions.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_verifiers.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_verl_checkpoint_export.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_verl_child_plugins.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_verl_silence_watchdog.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_version.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_vl_warmstart_adapter_keys.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_vram_architecture.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_wandb_link.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_wandb_naming.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_warmstart_adapter_download.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_warmstart_cross_repo.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_warmstart_error_attribution.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_weight_cache.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_worker_dryrun.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_worker_hardexit.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_worker_image.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_worker_init_heartbeat.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_worker_stack.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_worker_thinking.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_workflow_contracts.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_workload_profile.py +0 -0
- {freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/tests/test_zero2_sharding_gate.py +0 -0
|
@@ -21,6 +21,16 @@ This file starts at 1.1.35. Earlier releases are not reconstructed here; use
|
|
|
21
21
|
|
|
22
22
|
### Changed
|
|
23
23
|
|
|
24
|
+
- An attempt's terminal artifacts (its strict marker plus `metrics.json`) are now interpreted by
|
|
25
|
+
one shared protocol instead of being decoded separately by live instance polling and by each
|
|
26
|
+
recovery path. The two decoders disagreed about identical bytes. A marker that could not be tied
|
|
27
|
+
to the attempt was a terminal failure to the live poller but indistinguishable from "no marker
|
|
28
|
+
yet" to recovery, so the same corrupt artifact produced a different story depending on which
|
|
29
|
+
layer happened to observe it; recovery now names it rather than logging silence. Neither path
|
|
30
|
+
ever adopted such a marker as completed work, and neither does now. Recovery also computed a
|
|
31
|
+
fresh observation window for the marker and then another for `metrics.json`, so the real ceiling
|
|
32
|
+
was their sum and moved with however long the first read took; both reads now share one window,
|
|
33
|
+
which makes the bound the cutoff rather than the sum.
|
|
24
34
|
- CI runs the offline test suite on both supported interpreters (3.11 and 3.12) rather than
|
|
25
35
|
3.11 alone, and sets `HF_HUB_OFFLINE` / `TRANSFORMERS_OFFLINE` so a test that reaches the
|
|
26
36
|
network fails deterministically instead of depending on runner connectivity.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: freesolo-flash-dev
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.52
|
|
4
4
|
Summary: Flash — managed LoRA post-training (SFT/GRPO/OPD) for Freesolo environments, driven by the `flash` CLI
|
|
5
5
|
Project-URL: Homepage, https://github.com/freesolo-co/flash
|
|
6
6
|
Project-URL: Repository, https://github.com/freesolo-co/flash
|
{freesolo_flash_dev-1.2.49 → freesolo_flash_dev-1.2.52}/flash/providers/_lifecycle/poll_instance.py
RENAMED
|
@@ -10,7 +10,6 @@ reference ``time`` as a module attribute so provider poll tests patch the shared
|
|
|
10
10
|
from __future__ import annotations
|
|
11
11
|
|
|
12
12
|
import contextlib
|
|
13
|
-
import json
|
|
14
13
|
import math
|
|
15
14
|
import time
|
|
16
15
|
from collections.abc import Callable
|
|
@@ -25,12 +24,19 @@ from flash.providers._lifecycle.poll import (
|
|
|
25
24
|
BOOT_LOG_ABSENT_POLLS,
|
|
26
25
|
FIRST_LIVENESS_OBSERVED_FLOOR_S,
|
|
27
26
|
PollErrorTracker,
|
|
28
|
-
_attempt_int,
|
|
29
27
|
heartbeat_progress_ts,
|
|
30
28
|
is_training_heartbeat,
|
|
31
29
|
make_say,
|
|
32
30
|
surface_heartbeat,
|
|
33
31
|
)
|
|
32
|
+
from flash.providers._lifecycle.terminal_artifacts import (
|
|
33
|
+
INVALID_MARKER_DETAIL,
|
|
34
|
+
AttemptIdentity,
|
|
35
|
+
ProbeBudget,
|
|
36
|
+
TerminalKind,
|
|
37
|
+
read_within,
|
|
38
|
+
resolve_terminal_artifacts,
|
|
39
|
+
)
|
|
34
40
|
from flash.providers.artifacts.hf import worker_flagged_retriable
|
|
35
41
|
from flash.providers.base import PollResult
|
|
36
42
|
|
|
@@ -51,32 +57,13 @@ _TERMINAL_REREAD_RETRIES = 6
|
|
|
51
57
|
_TERMINAL_REREAD_WAIT_S = 5.0
|
|
52
58
|
|
|
53
59
|
|
|
54
|
-
def
|
|
55
|
-
read
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
deadline_at: float | None = None,
|
|
62
|
-
):
|
|
63
|
-
"""Re-read an artifact with every wait capped by the absolute run deadline."""
|
|
64
|
-
value = read()
|
|
65
|
-
while value is None and tries > 0:
|
|
66
|
-
delay = wait_s
|
|
67
|
-
if deadline_at is not None:
|
|
68
|
-
remaining = remaining_seconds(deadline_at)
|
|
69
|
-
if remaining <= 0:
|
|
70
|
-
break
|
|
71
|
-
delay = min(delay, remaining)
|
|
72
|
-
say(message)
|
|
73
|
-
if delay > 0:
|
|
74
|
-
time.sleep(delay)
|
|
75
|
-
if deadline_at is not None and remaining_seconds(deadline_at) <= 0:
|
|
76
|
-
break
|
|
77
|
-
value = read()
|
|
78
|
-
tries -= 1
|
|
79
|
-
return value
|
|
60
|
+
def _reread_budget(cutoff_at: float | None) -> ProbeBudget:
|
|
61
|
+
"""The give-up-path reread window, read from the module constants tests patch."""
|
|
62
|
+
return ProbeBudget(
|
|
63
|
+
tries=_TERMINAL_REREAD_RETRIES,
|
|
64
|
+
wait_s=_TERMINAL_REREAD_WAIT_S,
|
|
65
|
+
cutoff_at=cutoff_at,
|
|
66
|
+
)
|
|
80
67
|
|
|
81
68
|
|
|
82
69
|
@dataclass
|
|
@@ -122,69 +109,6 @@ class InstancePollAdapter:
|
|
|
122
109
|
first_liveness_detail: Callable[[float, float], str] # (elapsed_s, first_liveness_s) -> str
|
|
123
110
|
|
|
124
111
|
|
|
125
|
-
def decode_terminal_marker(
|
|
126
|
-
raw: str,
|
|
127
|
-
*,
|
|
128
|
-
run_id: str,
|
|
129
|
-
attempt: int,
|
|
130
|
-
launch_floor: float,
|
|
131
|
-
deadline_at: float | None = None,
|
|
132
|
-
) -> dict:
|
|
133
|
-
"""Validate one attempt-scoped terminal marker against its durable identity."""
|
|
134
|
-
marker = json.loads(raw)
|
|
135
|
-
if not isinstance(marker, dict) or set(marker) != {
|
|
136
|
-
"attempt",
|
|
137
|
-
"error",
|
|
138
|
-
"ok",
|
|
139
|
-
"retriable",
|
|
140
|
-
"run_id",
|
|
141
|
-
"ts",
|
|
142
|
-
}:
|
|
143
|
-
raise ValueError("invalid terminal marker schema")
|
|
144
|
-
marker_attempt = marker["attempt"]
|
|
145
|
-
ts = marker["ts"]
|
|
146
|
-
error = marker["error"]
|
|
147
|
-
now = time.time()
|
|
148
|
-
if (
|
|
149
|
-
isinstance(launch_floor, bool)
|
|
150
|
-
or not isinstance(launch_floor, (int, float))
|
|
151
|
-
or not math.isfinite(launch_floor)
|
|
152
|
-
or launch_floor <= 0
|
|
153
|
-
or isinstance(now, bool)
|
|
154
|
-
or not isinstance(now, (int, float))
|
|
155
|
-
or not math.isfinite(now)
|
|
156
|
-
or now <= 0
|
|
157
|
-
or _attempt_int(marker_attempt) is None
|
|
158
|
-
or marker_attempt != _attempt_int(attempt)
|
|
159
|
-
or type(marker["run_id"]) is not str
|
|
160
|
-
or marker["run_id"] != run_id
|
|
161
|
-
or type(marker["ok"]) is not bool
|
|
162
|
-
or type(marker["retriable"]) is not bool
|
|
163
|
-
or type(error) is not str
|
|
164
|
-
or len(error) > 4096
|
|
165
|
-
or isinstance(ts, bool)
|
|
166
|
-
or not isinstance(ts, (int, float))
|
|
167
|
-
or not math.isfinite(ts)
|
|
168
|
-
or ts < launch_floor
|
|
169
|
-
or ts > now + 120.0
|
|
170
|
-
or (deadline_at is not None and ts > deadline_at)
|
|
171
|
-
):
|
|
172
|
-
raise ValueError("invalid terminal marker identity")
|
|
173
|
-
return marker
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
def _decode_terminal_marker(
|
|
177
|
-
raw: str,
|
|
178
|
-
adapter: InstancePollAdapter,
|
|
179
|
-
) -> dict:
|
|
180
|
-
return decode_terminal_marker(
|
|
181
|
-
raw,
|
|
182
|
-
run_id=adapter.run_id,
|
|
183
|
-
attempt=adapter.current_attempt,
|
|
184
|
-
launch_floor=adapter.launch_ts,
|
|
185
|
-
)
|
|
186
|
-
|
|
187
|
-
|
|
188
112
|
class _TerminalArtifacts:
|
|
189
113
|
"""Reads HF terminal artifacts (marker, done, metrics) and classifies them into a ``PollResult``.
|
|
190
114
|
|
|
@@ -208,57 +132,6 @@ class _TerminalArtifacts:
|
|
|
208
132
|
**deadline_kwargs(reader, read_deadline_at),
|
|
209
133
|
)
|
|
210
134
|
|
|
211
|
-
def finish_ok(
|
|
212
|
-
self,
|
|
213
|
-
end_ts_hint: float | str | None = None,
|
|
214
|
-
*,
|
|
215
|
-
read_deadline_at: float | None = _UNSET_DEADLINE,
|
|
216
|
-
) -> PollResult:
|
|
217
|
-
if read_deadline_at is _UNSET_DEADLINE:
|
|
218
|
-
read_deadline_at = self._absolute_deadline
|
|
219
|
-
# the strict success marker authorizes completion, but metrics.json visibility can lag it on hf.
|
|
220
|
-
# re-read before falling back to the poll_error retry used for a success without metrics.
|
|
221
|
-
raw = _read_with_retries(
|
|
222
|
-
lambda: self._read_artifact(
|
|
223
|
-
self._adapter.metrics_reader,
|
|
224
|
-
force=True,
|
|
225
|
-
read_deadline_at=read_deadline_at,
|
|
226
|
-
),
|
|
227
|
-
tries=_METRICS_AFTER_SUCCESS_RETRIES,
|
|
228
|
-
wait_s=_METRICS_AFTER_SUCCESS_WAIT_S,
|
|
229
|
-
say=self._say,
|
|
230
|
-
message="DONE seen but metrics.json not visible yet; waiting for HF read-after-write",
|
|
231
|
-
deadline_at=read_deadline_at,
|
|
232
|
-
)
|
|
233
|
-
if raw is None:
|
|
234
|
-
# the strict success marker has authorized completion, so missing metrics after the inline
|
|
235
|
-
# retries is a transient hf read gap, not a worker error. return the infra-retryable
|
|
236
|
-
# poll_error so the run gets its bounded infra budget instead of a hard terminal failure.
|
|
237
|
-
return PollResult(
|
|
238
|
-
False, failure="poll_error", detail="DONE without metrics.json (transient HF read)"
|
|
239
|
-
)
|
|
240
|
-
try:
|
|
241
|
-
metrics = json.loads(raw)
|
|
242
|
-
except ValueError:
|
|
243
|
-
# a present but unparseable metrics.json must not escape as a raw json decode error and
|
|
244
|
-
# bypass the poll result path. treat this marker-authorized success like missing metrics:
|
|
245
|
-
# infra-retryable poll_error, not job_failed.
|
|
246
|
-
return PollResult(
|
|
247
|
-
False,
|
|
248
|
-
failure="poll_error",
|
|
249
|
-
detail="DONE with unparseable metrics.json (transient HF read)",
|
|
250
|
-
)
|
|
251
|
-
# end_ts is the worker completion time: prefer the optional fresh done timestamp supplied by
|
|
252
|
-
# the caller, otherwise use the strict ok marker timestamp. adopt only values in [launch, now].
|
|
253
|
-
end_ts = time.time()
|
|
254
|
-
if end_ts_hint is not None:
|
|
255
|
-
with contextlib.suppress(TypeError, ValueError):
|
|
256
|
-
ts = float(end_ts_hint)
|
|
257
|
-
if self._launch_ts <= ts <= end_ts:
|
|
258
|
-
end_ts = ts
|
|
259
|
-
self._adapter.stamp_cost_and_notes(metrics, end_ts=end_ts, launch_ts=self._launch_ts)
|
|
260
|
-
return PollResult(True, metrics=metrics)
|
|
261
|
-
|
|
262
135
|
def _done_is_fresh(self, content: str) -> bool:
|
|
263
136
|
# done carries only a finite completion timestamp bound to this attempt and deadline.
|
|
264
137
|
try:
|
|
@@ -274,24 +147,27 @@ class _TerminalArtifacts:
|
|
|
274
147
|
and (self._absolute_deadline is None or ts <= self._absolute_deadline)
|
|
275
148
|
)
|
|
276
149
|
|
|
277
|
-
def
|
|
278
|
-
self,
|
|
279
|
-
marker: dict,
|
|
280
|
-
*,
|
|
281
|
-
read_deadline_at: float | None = _UNSET_DEADLINE,
|
|
150
|
+
def _succeed(
|
|
151
|
+
self, marker: dict, metrics: dict, *, read_deadline_at: float | None
|
|
282
152
|
) -> PollResult:
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
153
|
+
"""Stamp a marker-authorized success with the best completion timestamp available.
|
|
154
|
+
|
|
155
|
+
A strict ok marker authorizes completion even if DONE is stale or absent, so DONE only
|
|
156
|
+
refines the wall note. Adopt a timestamp only inside [launch, now].
|
|
157
|
+
"""
|
|
287
158
|
d = self._read_artifact(
|
|
288
159
|
self._adapter.done_reader,
|
|
289
160
|
force=True,
|
|
290
161
|
read_deadline_at=read_deadline_at,
|
|
291
162
|
)
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
163
|
+
hint = d if (d is not None and self._done_is_fresh(d)) else marker["ts"]
|
|
164
|
+
end_ts = time.time()
|
|
165
|
+
with contextlib.suppress(TypeError, ValueError):
|
|
166
|
+
ts = float(hint)
|
|
167
|
+
if self._launch_ts <= ts <= end_ts:
|
|
168
|
+
end_ts = ts
|
|
169
|
+
self._adapter.stamp_cost_and_notes(metrics, end_ts=end_ts, launch_ts=self._launch_ts)
|
|
170
|
+
return PollResult(True, metrics=metrics)
|
|
295
171
|
|
|
296
172
|
def _fail_from_marker(self, marker: dict) -> PollResult:
|
|
297
173
|
# a real worker error fails fast unless flagged retriable in the marker or the worker heartbeat.
|
|
@@ -318,23 +194,56 @@ class _TerminalArtifacts:
|
|
|
318
194
|
# marker-authorized success, but it cannot complete a run by itself.
|
|
319
195
|
if read_deadline_at is _UNSET_DEADLINE:
|
|
320
196
|
read_deadline_at = self._absolute_deadline
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
197
|
+
resolution = resolve_terminal_artifacts(
|
|
198
|
+
AttemptIdentity(
|
|
199
|
+
run_id=self._adapter.run_id,
|
|
200
|
+
attempt=self._adapter.current_attempt,
|
|
201
|
+
launch_floor=self._adapter.launch_ts,
|
|
202
|
+
),
|
|
203
|
+
read_marker=lambda: self._read_artifact(
|
|
204
|
+
self._adapter.marker_reader,
|
|
205
|
+
force=force,
|
|
206
|
+
read_deadline_at=read_deadline_at,
|
|
207
|
+
),
|
|
208
|
+
read_metrics=lambda: self._read_artifact(
|
|
209
|
+
self._adapter.metrics_reader,
|
|
210
|
+
force=True,
|
|
211
|
+
read_deadline_at=read_deadline_at,
|
|
212
|
+
),
|
|
213
|
+
budget=ProbeBudget(
|
|
214
|
+
tries=_METRICS_AFTER_SUCCESS_RETRIES,
|
|
215
|
+
wait_s=_METRICS_AFTER_SUCCESS_WAIT_S,
|
|
216
|
+
cutoff_at=read_deadline_at,
|
|
217
|
+
),
|
|
218
|
+
say=self._say,
|
|
219
|
+
metrics_message=(
|
|
220
|
+
"DONE seen but metrics.json not visible yet; waiting for HF read-after-write"
|
|
221
|
+
),
|
|
325
222
|
)
|
|
326
|
-
if
|
|
223
|
+
if resolution.kind is TerminalKind.ABSENT:
|
|
327
224
|
return None
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
225
|
+
if resolution.kind is TerminalKind.UNVERIFIABLE:
|
|
226
|
+
return PollResult(False, failure="job_failed", detail=INVALID_MARKER_DETAIL)
|
|
227
|
+
if resolution.kind is TerminalKind.SUCCESS:
|
|
228
|
+
return self._succeed(
|
|
229
|
+
resolution.marker,
|
|
230
|
+
resolution.metrics,
|
|
231
|
+
read_deadline_at=read_deadline_at,
|
|
232
|
+
)
|
|
233
|
+
if resolution.kind is TerminalKind.PENDING:
|
|
234
|
+
# the strict success marker has authorized completion, so unreadable metrics are a
|
|
235
|
+
# transient hf read gap, not a worker error. return the infra-retryable poll_error so the
|
|
236
|
+
# run gets its bounded infra budget instead of a hard terminal failure.
|
|
331
237
|
return PollResult(
|
|
332
238
|
False,
|
|
333
|
-
failure="
|
|
334
|
-
detail=
|
|
239
|
+
failure="poll_error",
|
|
240
|
+
detail=(
|
|
241
|
+
"DONE with unparseable metrics.json (transient HF read)"
|
|
242
|
+
if resolution.metrics_unparseable
|
|
243
|
+
else "DONE without metrics.json (transient HF read)"
|
|
244
|
+
),
|
|
335
245
|
)
|
|
336
|
-
|
|
337
|
-
return self._finish_from_ok_marker(marker, read_deadline_at=read_deadline_at)
|
|
246
|
+
marker = resolution.marker
|
|
338
247
|
failure = self._fail_from_marker(marker)
|
|
339
248
|
# the watchdog marker can race a successful final marker or lagging done upload. only the
|
|
340
249
|
# deadline exit defers it; every other failure marker still terminates immediately.
|
|
@@ -358,13 +267,11 @@ class _TerminalArtifacts:
|
|
|
358
267
|
|
|
359
268
|
def reread_before_giving_up(self, message: str) -> PollResult | None:
|
|
360
269
|
"""Bounded terminal reread shared by the dead-host, poll-outage, and stall give-up paths."""
|
|
361
|
-
terminal =
|
|
270
|
+
terminal = read_within(
|
|
362
271
|
self.result,
|
|
363
|
-
|
|
364
|
-
wait_s=_TERMINAL_REREAD_WAIT_S,
|
|
272
|
+
_reread_budget(self._absolute_deadline),
|
|
365
273
|
say=self._say,
|
|
366
274
|
message=message,
|
|
367
|
-
deadline_at=self._absolute_deadline,
|
|
368
275
|
)
|
|
369
276
|
if terminal is not None:
|
|
370
277
|
self.surface_final_heartbeat()
|
|
@@ -376,16 +283,14 @@ class _TerminalArtifacts:
|
|
|
376
283
|
self.deferred_deadline_failure = None
|
|
377
284
|
self.surface_final_heartbeat()
|
|
378
285
|
read_deadline = time.time() + (_TERMINAL_REREAD_RETRIES * _TERMINAL_REREAD_WAIT_S)
|
|
379
|
-
terminal =
|
|
286
|
+
terminal = read_within(
|
|
380
287
|
lambda: self.result(
|
|
381
288
|
read_deadline_at=read_deadline,
|
|
382
289
|
defer_deadline_failure=True,
|
|
383
290
|
),
|
|
384
|
-
|
|
385
|
-
wait_s=_TERMINAL_REREAD_WAIT_S,
|
|
291
|
+
_reread_budget(read_deadline),
|
|
386
292
|
say=self._say,
|
|
387
293
|
message="deadline reached; waiting for HF to expose any terminal DONE/marker before stalled",
|
|
388
|
-
deadline_at=read_deadline,
|
|
389
294
|
)
|
|
390
295
|
if terminal is not None:
|
|
391
296
|
self.surface_final_heartbeat()
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"""one terminal-artifact protocol, shared by live polling and every recovery path.
|
|
2
|
+
|
|
3
|
+
an attempt's terminal evidence (the strict attempt marker plus its metrics.json) used to be decoded
|
|
4
|
+
in two places that disagreed about the same bytes: the live instance poller in ``poll_instance`` and
|
|
5
|
+
the reconstruction helpers in ``flash.runner.supervise.recovery``.
|
|
6
|
+
|
|
7
|
+
two things diverged.
|
|
8
|
+
|
|
9
|
+
* an unverifiable marker. the live poller classified it as a terminal ``job_failed``; recovery caught
|
|
10
|
+
the same ``TypeError``/``ValueError`` and returned ``None``, which its callers read as "no evidence
|
|
11
|
+
yet". neither adopts the corrupt artifact, so this is a classification split rather than a
|
|
12
|
+
correctness hole, but the same bytes still produced two different stories depending on which layer
|
|
13
|
+
happened to observe the attempt.
|
|
14
|
+
* the observation window. the live poller shares one absolute read deadline across its rereads, while
|
|
15
|
+
recovery computed a fresh ~30s window for the marker and then ANOTHER fresh ~30s window for
|
|
16
|
+
metrics. because the second window started only after the first finished, the effective ceiling was
|
|
17
|
+
their SUM, and it drifted with however long the marker read happened to take.
|
|
18
|
+
|
|
19
|
+
this module owns that decode exactly once. it is evidence only: it never mutates run state, never
|
|
20
|
+
performs the exact-remote CAS, and never decides whether a run retries -- the attempt ledger stays
|
|
21
|
+
the sole persisted authority. it answers exactly one question, as a ``TerminalKind``, and callers
|
|
22
|
+
adapt that into their own vocabulary (a ``PollResult`` for the poller, a metrics dict for recovery)
|
|
23
|
+
because finishing a success is provider-specific (cost stamping, done-timestamp refinement) while
|
|
24
|
+
the DECISION is not.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
import json
|
|
30
|
+
import math
|
|
31
|
+
import time
|
|
32
|
+
from collections.abc import Callable
|
|
33
|
+
from dataclasses import dataclass
|
|
34
|
+
from enum import Enum
|
|
35
|
+
from typing import TypeVar
|
|
36
|
+
|
|
37
|
+
from flash.providers._lifecycle.deadline import remaining_seconds
|
|
38
|
+
from flash.providers._lifecycle.poll import _attempt_int
|
|
39
|
+
|
|
40
|
+
T = TypeVar("T")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class TerminalKind(Enum):
|
|
44
|
+
"""What one bounded observation of an attempt's terminal artifacts established.
|
|
45
|
+
|
|
46
|
+
These five are exhaustive and mutually exclusive, so callers dispatch on the kind alone. In
|
|
47
|
+
particular UNVERIFIABLE is its OWN kind rather than a flag on FAILURE: recovery used to fold it
|
|
48
|
+
into "no evidence", and keeping it distinct is what stops that from reappearing.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
# no marker is visible. the attempt may still be running, or hf has not exposed the upload yet.
|
|
52
|
+
ABSENT = "absent"
|
|
53
|
+
# a marker exists but cannot be tied to this attempt, so it cannot be trusted to speak for it.
|
|
54
|
+
# distinct from ABSENT: absence means nothing settled, this means something settled unreadably.
|
|
55
|
+
UNVERIFIABLE = "unverifiable"
|
|
56
|
+
# a strict success marker exists but its metrics are not readable yet. callers must keep
|
|
57
|
+
# observing rather than tearing down: the attempt already finished its paid work.
|
|
58
|
+
PENDING = "pending"
|
|
59
|
+
# a strict success marker plus readable metrics.
|
|
60
|
+
SUCCESS = "success"
|
|
61
|
+
# the attempt is terminally settled and did not succeed.
|
|
62
|
+
FAILURE = "failure"
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@dataclass(frozen=True)
|
|
66
|
+
class TerminalResolution:
|
|
67
|
+
"""One decided observation. ``marker`` is the validated marker when one was decoded."""
|
|
68
|
+
|
|
69
|
+
kind: TerminalKind
|
|
70
|
+
metrics: dict | None = None
|
|
71
|
+
marker: dict | None = None
|
|
72
|
+
# PENDING only, and diagnostic only: metrics were present but unparseable rather than missing.
|
|
73
|
+
# both are the same visibility gap behind an already-authorized completion, so this narrows an
|
|
74
|
+
# operator message and nothing else.
|
|
75
|
+
metrics_unparseable: bool = False
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
ABSENT = TerminalResolution(TerminalKind.ABSENT)
|
|
79
|
+
UNVERIFIABLE = TerminalResolution(TerminalKind.UNVERIFIABLE)
|
|
80
|
+
|
|
81
|
+
INVALID_MARKER_DETAIL = "terminal marker is invalid or unverifiable"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@dataclass(frozen=True)
|
|
85
|
+
class AttemptIdentity:
|
|
86
|
+
"""The durable identity every terminal artifact must match to speak for this attempt."""
|
|
87
|
+
|
|
88
|
+
run_id: str
|
|
89
|
+
attempt: int
|
|
90
|
+
launch_floor: float
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@dataclass(frozen=True)
|
|
94
|
+
class ProbeBudget:
|
|
95
|
+
"""One observation window, computed ONCE and shared by every read inside a resolution.
|
|
96
|
+
|
|
97
|
+
the marker and its metrics are two uploads of the same completion racing the same hf
|
|
98
|
+
read-after-write lag, so they are one budget, not two. ``cutoff_at`` is absolute and is threaded
|
|
99
|
+
through both reads: a marker read that burns most of the window leaves metrics the remainder
|
|
100
|
+
instead of starting a fresh allowance. that makes the ceiling the cutoff rather than the sum of
|
|
101
|
+
however many reads a path happens to make.
|
|
102
|
+
|
|
103
|
+
``tries`` and ``wait_s`` stay per-read because provider tests patch the module constants they
|
|
104
|
+
come from; the shared absolute cutoff is what bounds the total.
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
tries: int
|
|
108
|
+
wait_s: float
|
|
109
|
+
cutoff_at: float | None = None
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def read_within(
|
|
113
|
+
read: Callable[[], T | None],
|
|
114
|
+
budget: ProbeBudget,
|
|
115
|
+
*,
|
|
116
|
+
say: Callable[[str], None] | None = None,
|
|
117
|
+
message: str = "",
|
|
118
|
+
) -> T | None:
|
|
119
|
+
"""Re-read one artifact until it is visible or the SHARED budget is spent.
|
|
120
|
+
|
|
121
|
+
Every wait is clipped to the budget's absolute cutoff, so the window cannot be restarted by a
|
|
122
|
+
later read in the same resolution.
|
|
123
|
+
"""
|
|
124
|
+
value = read()
|
|
125
|
+
tries = budget.tries
|
|
126
|
+
while value is None and tries > 0:
|
|
127
|
+
delay = budget.wait_s
|
|
128
|
+
if budget.cutoff_at is not None:
|
|
129
|
+
remaining = remaining_seconds(budget.cutoff_at)
|
|
130
|
+
if remaining <= 0:
|
|
131
|
+
break
|
|
132
|
+
delay = min(delay, remaining)
|
|
133
|
+
if say is not None and message:
|
|
134
|
+
say(message)
|
|
135
|
+
if delay > 0:
|
|
136
|
+
time.sleep(delay)
|
|
137
|
+
if budget.cutoff_at is not None and remaining_seconds(budget.cutoff_at) <= 0:
|
|
138
|
+
break
|
|
139
|
+
value = read()
|
|
140
|
+
tries -= 1
|
|
141
|
+
return value
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def decode_terminal_marker(
|
|
145
|
+
raw: str,
|
|
146
|
+
*,
|
|
147
|
+
run_id: str,
|
|
148
|
+
attempt: int,
|
|
149
|
+
launch_floor: float,
|
|
150
|
+
deadline_at: float | None = None,
|
|
151
|
+
) -> dict:
|
|
152
|
+
"""Validate one attempt-scoped terminal marker against its durable identity.
|
|
153
|
+
|
|
154
|
+
Fails closed on anything it cannot tie to exactly this attempt: an unknown schema, another run,
|
|
155
|
+
another attempt, a timestamp before the launch this marker claims to end, or one past the bound
|
|
156
|
+
the caller allows. A marker that cannot be verified must never settle an attempt.
|
|
157
|
+
"""
|
|
158
|
+
marker = json.loads(raw)
|
|
159
|
+
if not isinstance(marker, dict) or set(marker) != {
|
|
160
|
+
"attempt",
|
|
161
|
+
"error",
|
|
162
|
+
"ok",
|
|
163
|
+
"retriable",
|
|
164
|
+
"run_id",
|
|
165
|
+
"ts",
|
|
166
|
+
}:
|
|
167
|
+
raise ValueError("invalid terminal marker schema")
|
|
168
|
+
marker_attempt = marker["attempt"]
|
|
169
|
+
ts = marker["ts"]
|
|
170
|
+
error = marker["error"]
|
|
171
|
+
now = time.time()
|
|
172
|
+
if (
|
|
173
|
+
isinstance(launch_floor, bool)
|
|
174
|
+
or not isinstance(launch_floor, (int, float))
|
|
175
|
+
or not math.isfinite(launch_floor)
|
|
176
|
+
or launch_floor <= 0
|
|
177
|
+
or isinstance(now, bool)
|
|
178
|
+
or not isinstance(now, (int, float))
|
|
179
|
+
or not math.isfinite(now)
|
|
180
|
+
or now <= 0
|
|
181
|
+
or _attempt_int(marker_attempt) is None
|
|
182
|
+
or marker_attempt != _attempt_int(attempt)
|
|
183
|
+
or type(marker["run_id"]) is not str
|
|
184
|
+
or marker["run_id"] != run_id
|
|
185
|
+
or type(marker["ok"]) is not bool
|
|
186
|
+
or type(marker["retriable"]) is not bool
|
|
187
|
+
or type(error) is not str
|
|
188
|
+
or len(error) > 4096
|
|
189
|
+
or isinstance(ts, bool)
|
|
190
|
+
or not isinstance(ts, (int, float))
|
|
191
|
+
or not math.isfinite(ts)
|
|
192
|
+
or ts < launch_floor
|
|
193
|
+
or ts > now + 120.0
|
|
194
|
+
or (deadline_at is not None and ts > deadline_at)
|
|
195
|
+
):
|
|
196
|
+
raise ValueError("invalid terminal marker identity")
|
|
197
|
+
return marker
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def _parse_metrics(raw: str | None) -> dict | None:
|
|
201
|
+
if raw is None:
|
|
202
|
+
return None
|
|
203
|
+
try:
|
|
204
|
+
metrics = json.loads(raw)
|
|
205
|
+
except (TypeError, ValueError):
|
|
206
|
+
return None
|
|
207
|
+
return metrics if isinstance(metrics, dict) else None
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def resolve_terminal_artifacts(
|
|
211
|
+
identity: AttemptIdentity,
|
|
212
|
+
*,
|
|
213
|
+
read_marker: Callable[[], str | None],
|
|
214
|
+
read_metrics: Callable[[], str | None],
|
|
215
|
+
budget: ProbeBudget,
|
|
216
|
+
say: Callable[[str], None] | None = None,
|
|
217
|
+
marker_deadline_at: float | None = None,
|
|
218
|
+
marker_wait_message: str | None = None,
|
|
219
|
+
metrics_message: str = "successful marker seen; waiting for metrics.json",
|
|
220
|
+
) -> TerminalResolution:
|
|
221
|
+
"""Decide what an attempt's marker plus metrics establish, under ONE shared budget.
|
|
222
|
+
|
|
223
|
+
The strict marker is the sole terminal authority. A DONE file may later refine a
|
|
224
|
+
marker-authorized success's completion timestamp, but it can never complete an attempt on its
|
|
225
|
+
own, so it is deliberately not consulted here.
|
|
226
|
+
|
|
227
|
+
``marker_wait_message`` both enables and narrates waiting for the marker itself: live polling
|
|
228
|
+
reads it once per iteration (the loop is the retry), while recovery re-reads it inside the shared
|
|
229
|
+
budget. Passing the message is what asks for that wait, so neither can be set without the other.
|
|
230
|
+
"""
|
|
231
|
+
raw = (
|
|
232
|
+
read_marker()
|
|
233
|
+
if marker_wait_message is None
|
|
234
|
+
else read_within(read_marker, budget, say=say, message=marker_wait_message)
|
|
235
|
+
)
|
|
236
|
+
if raw is None:
|
|
237
|
+
return ABSENT
|
|
238
|
+
try:
|
|
239
|
+
marker = decode_terminal_marker(
|
|
240
|
+
raw,
|
|
241
|
+
run_id=identity.run_id,
|
|
242
|
+
attempt=identity.attempt,
|
|
243
|
+
launch_floor=identity.launch_floor,
|
|
244
|
+
deadline_at=marker_deadline_at,
|
|
245
|
+
)
|
|
246
|
+
except (TypeError, ValueError):
|
|
247
|
+
return UNVERIFIABLE
|
|
248
|
+
if not marker["ok"]:
|
|
249
|
+
return TerminalResolution(TerminalKind.FAILURE, marker=marker)
|
|
250
|
+
raw_metrics = read_within(read_metrics, budget, say=say, message=metrics_message)
|
|
251
|
+
metrics = _parse_metrics(raw_metrics)
|
|
252
|
+
if metrics is None:
|
|
253
|
+
# the marker already authorized completion, so unreadable metrics are a visibility gap in the
|
|
254
|
+
# SECOND upload, not a worker error. callers keep observing within the budget instead of
|
|
255
|
+
# tearing down an attempt that already finished its paid work.
|
|
256
|
+
return TerminalResolution(
|
|
257
|
+
TerminalKind.PENDING,
|
|
258
|
+
marker=marker,
|
|
259
|
+
metrics_unparseable=raw_metrics is not None,
|
|
260
|
+
)
|
|
261
|
+
return TerminalResolution(TerminalKind.SUCCESS, metrics=metrics, marker=marker)
|