freesolo-flash-dev 1.2.52__tar.gz → 1.2.58__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.52 → freesolo_flash_dev-1.2.58}/CHANGELOG.md +28 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/PKG-INFO +1 -1
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/core/spec.py +4 -23
- freesolo_flash_dev-1.2.58/flash/core/spec_persistence.py +123 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cost/analytical.py +86 -35
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cost/spec.py +5 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cost/types.py +24 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/io/heartbeat.py +41 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/perf/__init__.py +3 -3
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/envs/identity.py +5 -1
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/envs/loader.py +5 -1
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/_lifecycle/bootstrap.py +21 -5
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/_lifecycle/bootstrap_console.py +9 -5
- freesolo_flash_dev-1.2.58/flash/providers/_lifecycle/host/__init__.py +5 -0
- freesolo_flash_dev-1.2.58/flash/providers/_lifecycle/host/deadline_sleep.py +63 -0
- freesolo_flash_dev-1.2.58/flash/providers/_lifecycle/host/failmark.py +89 -0
- freesolo_flash_dev-1.2.58/flash/providers/_lifecycle/host/hostlog.py +60 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/_lifecycle/instance.py +47 -228
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/_lifecycle/worker.py +3 -56
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/artifacts/preload_runpod.py +1 -2
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/artifacts/weight_cache.py +0 -1
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/lambda_/jobs/builders.py +2 -2
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/runpod/job_execution.py +2 -12
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/runpod/jobs.py +2 -39
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/runpod/serverless/__init__.py +0 -3
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/runpod/serverless/endpoints.py +1 -93
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/vast/jobs/builders.py +21 -25
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/runner/__init__.py +2 -13
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/runner/costs.py +2 -44
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/runner/preparation.py +8 -153
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/runner/status.py +4 -35
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/runner/submit.py +1 -19
- freesolo_flash_dev-1.2.58/flash/runtime_capsule/__init__.py +48 -0
- freesolo_flash_dev-1.2.58/flash/runtime_capsule/build.py +231 -0
- freesolo_flash_dev-1.2.58/flash/runtime_capsule/manifest.py +240 -0
- freesolo_flash_dev-1.2.58/flash/runtime_capsule/profiles.py +65 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/schema/__init__.py +2 -6
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/serve/urls.py +1 -2
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/platform/runtime.py +3 -34
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/pyproject.toml +2 -2
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/scripts/check_function_size.py +4 -3
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_cancel_remote.py +3 -59
- freesolo_flash_dev-1.2.58/tests/test_console_upload.py +145 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_cost_estimate.py +6 -2
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_env_rate_limit_resolve.py +26 -6
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_flash_worker.py +129 -28
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_instance_bootstrap_coverage.py +49 -5
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_jobs.py +9 -47
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_kernel_fingerprint.py +36 -23
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_lambda_runner.py +171 -119
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_provider_teardown_robustness.py +1 -1
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_runmgmt.py +0 -66
- freesolo_flash_dev-1.2.58/tests/test_runtime_capsule.py +434 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_server_api.py +1 -7
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_server_envs_coverage.py +0 -1
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_spec_and_validation.py +89 -465
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_spec_contract_bytes.py +0 -64
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_vast_runner.py +128 -29
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_warmstart_cross_repo.py +3 -6
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_weight_cache.py +8 -5
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_worker_image.py +0 -11
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_worker_init_heartbeat.py +219 -17
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_worker_stack.py +28 -40
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/uv.lock +1 -1
- freesolo_flash_dev-1.2.52/flash/core/spec_persistence.py +0 -227
- freesolo_flash_dev-1.2.52/tests/test_console_upload.py +0 -89
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/.dockerignore +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/.env.example +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/.github/CODEOWNERS +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/.github/dependabot.yml +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/.github/workflows/auto-rebake.yml +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/.github/workflows/bake-kernel-cache.yml +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/.github/workflows/ci.yml +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/.github/workflows/main-source-guard.yml +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/.github/workflows/notify-tests-repo.yml +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/.github/workflows/publish-dev.yml +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/.github/workflows/publish-image.yml +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/.github/workflows/publish.yml +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/.github/workflows/version-parity.yml +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/.github/workflows/worker-image.yml +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/.gitignore +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/CODE_OF_CONDUCT.md +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/CONTRIBUTING.md +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/Dockerfile +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/Dockerfile.worker +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/LICENSE +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/NOTICE +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/README.md +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/SECURITY.md +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/SELF_HOSTING.md +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/build/kernel_cache/.gitignore +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/build/kernel_cache/.keep +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/deploy/infisical/README.md +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/deploy/infisical/entrypoint.sh +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/docker/Dockerfile.kernelcache +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/docker/Dockerfile.kernelcache.relayer +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/docker/bake_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/docker/bake_pod_entry.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/docker/extract_cudart_fix.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/docker/kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/docker/make_rp_handler.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/_internal/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/_internal/channel.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/_internal/diagnostics.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/_internal/fileio.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/_internal/logging.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/_internal/paths.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/adapters/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/adapters/artifacts.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/adapters/fused_experts.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/adapters/lora_rank.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/__main__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/commands/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/commands/deploy.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/commands/env/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/commands/env/episode.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/commands/env/eval.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/commands/env/eval_args.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/commands/env/imports.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/commands/env/list.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/commands/env/push.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/commands/env/retained.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/commands/env/setup.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/commands/env/test.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/commands/env/test_evaluations.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/commands/env/test_params.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/commands/env/test_warnings.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/commands/prompt_budget.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/commands/traces.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/commands/train_cost.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/scaffold/TRAINING.md +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/scaffold/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/ui/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/ui/cost.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/ui/env_panels.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/ui/heartbeat.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/ui/render.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/ui/tables.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cli/ui/tty.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/client/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/client/config.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/client/freesolo_api.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/client/http.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/client/runtime_secrets.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/client/shapes.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/client/specs.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/client/streaming.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/content/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/content/multimodal.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/content/structured_outputs.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/content/thinking.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/core/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/core/catalog.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cost/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/cost/facts.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/plan/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/plan/kv_sizing.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/plan/model_config_probe.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/plan/prompt_budget.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/plan/recipe.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/plan/steps.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/plan/vram.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/profiling/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/profiling/dataset_profile.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/profiling/reasoning_render.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/profiling/sft_workload.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/profiling/tokenizer.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/profiling/workload_profile.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/result/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/result/accounting.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/result/rollout_samples.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/__main__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/backend_common.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/entry/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/entry/opd.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/entry/rl.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/entry/sft.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/io/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/io/hf.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/io/prefetch.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/io/wandb_log.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/model/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/model/adapter.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/model/chatml_mask.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/model/decoding.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/model/lora.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/model/packing.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/opd_train.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/opd_train_runner.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/perf/diagnostics.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/perf/lifecycle.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/perf/liger.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/perf/memory.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/rl_train.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/rl_train_runner.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/runtime/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/runtime/kernel_warmup.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/runtime/pkg_proxy.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/runtime/rng.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/score_batcher.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/sft_train.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/sft_train_runner.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/teacher/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/teacher/client.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/teacher/encoding.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/teacher/tokenizer_align.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/core/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/core/checkpoint_lifecycle.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/core/child/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/core/child/glue.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/core/child/runtime.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/core/step_timing.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/finalize.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/opd/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/opd/batching.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/opd/bridge.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/opd/child/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/opd/child/bridge.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/opd/child/entry.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/opd/child/multiturn.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/opd/child/plugin.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/opd/child/replay_guard.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/opd/child/runtime.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/opd/child/structured.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/opd/failures.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/opd/gkd.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/opd/multiturn_validation.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/opd/overrides.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/opd/prompts.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/opd/reporting.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/opd/scoring.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/opd/state.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/opd/validation.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/rl/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/rl/checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/rl/child/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/rl/child/entry.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/rl/child/multiturn.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/rl/child/patches.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/rl/child/plugin.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/rl/config.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/rl/inputs.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/rl/multi_turn.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/rl/reward_module.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/rl/scoring.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/rl/single_turn.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/rl/verl_config.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/sft/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/sft/checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/sft/child/entry.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/sft/child/plugin.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/train/sft/config.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/verl/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/verl/capabilities.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/verl/checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/verl/child_io.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/verl/diagnostics.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/verl/parallelism.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/verl/parent_work.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker_entrypoint.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/envs/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/envs/adapter.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/envs/base.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/envs/cache_security.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/envs/dataset_selection.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/envs/evaluations.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/envs/namespace_listing.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/envs/package/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/envs/package/limits.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/envs/package/unpack.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/envs/pull.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/_lifecycle/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/_lifecycle/auth.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/_lifecycle/bootstrap_pip.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/_lifecycle/bootstrap_secrets.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/_lifecycle/deadline.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/_lifecycle/http.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/_lifecycle/poll.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/_lifecycle/poll_instance.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/_lifecycle/provider.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/_lifecycle/terminal_artifacts.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/allocator.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/artifacts/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/artifacts/hf.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/base.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/fit_errors.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/lambda_/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/lambda_/api.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/lambda_/auth.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/lambda_/gpus.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/lambda_/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/lambda_/jobs/reap.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/lambda_/preflight.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/lambda_/pricing.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/preflight.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/realized.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/runpod/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/runpod/api.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/runpod/auth.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/runpod/cost.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/runpod/gpus.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/runpod/preflight.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/runpod/pricing.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/runpod/resources.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/sharding.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/vast/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/vast/api.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/vast/auth.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/vast/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/vast/preflight.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/vast/pricing.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/py.typed +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/runner/artifacts.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/runner/attempts.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/runner/deadlines.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/runner/reconciliation.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/runner/results/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/runner/results/checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/runner/results/verified_revisions.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/runner/supervise/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/runner/supervise/attach.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/runner/supervise/deploy.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/runner/supervise/lifecycle.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/runner/supervise/recovery.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/runner/supervise/retry_decision.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/runner/supervise/seed_submission.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/runner/supervise/transitions.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/runner/weight_cache.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/schema/fields.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/serve/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/serve/adapter_check.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/serve/deploy.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/serve/errors.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/serve/export.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/serve/preflight.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/serve/responses.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/serve/streaming.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/serve/thinking.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/__main__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/app.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/billing/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/billing/charges.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/billing/retry.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/domain/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/domain/checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/domain/environment_registry.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/domain/envs.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/domain/projects.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/domain/reconcile.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/domain/repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/domain/run_registry.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/domain/teacher_broker.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/domain/teacher_errors.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/domain/teacher_requests.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/platform/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/platform/auth.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/platform/db.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/platform/deps.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/platform/internal_client.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/platform/locks.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/routes/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/routes/envs.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/routes/meta.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/routes/runs.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/routes/serving.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/routes/serving_completion.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/routes/serving_revisions.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/routes/serving_smoke.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/server/routes/teacher.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/teacher/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/teacher/limits.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/teacher/retry_contract.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/scripts/build_dev_dist.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/scripts/check_file_size.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/scripts/check_verl_pin_exists.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/scripts/scrub_history.sh +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/_helpers/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/_helpers/profile.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/_helpers/runner.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/_helpers/specs.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/_helpers/teacher.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/_helpers/vast.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/conftest.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/fixtures/math_eval.jsonl +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/fixtures/math_train.jsonl +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/live/__init__.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/live/conftest.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/live/test_lambda_live.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/live/test_runpod_live.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/live/test_sft_thinking_render_live.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/live/test_vast_live.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_accounting_coverage.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_adapter_shard_completeness.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_agent_flash_cli_contract.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_algorithms.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_allocator.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_backend_common.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_backend_jobspec_contract.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_bake_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_base_model_provenance.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_billing_retry.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_build_context_contract.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_catalog_consistency.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_catalog_only_models.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_charge_pricing.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_checkpoint_lifecycle.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_checkpoints.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_cli_commands.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_cli_commands_coverage.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_cli_credential_shadowing.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_cli_errors.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_cli_estimate.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_cli_gpus_flag.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_cli_help.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_cli_main_coverage.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_cli_managed.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_cli_render_coverage.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_cli_render_theme.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_cli_traces.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_cli_wandb_warning.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_client.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_client_import_purity.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_client_server_integration.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_client_stream_reads.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_config_env_vars.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_config_overrides.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_controlled_experiment_repairs.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_cost_analytical.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_cost_equation.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_cost_hardware.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_cost_models.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_dataset_profile.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_deploy_alias_move_warning.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_deploy_latency.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_dev_channel.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_disk_gb.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_endpoint_name.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_env_cache_evict.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_env_delete.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_env_download.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_env_download_api.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_env_evaluations.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_env_list_api.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_env_list_cli.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_env_list_hub.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_env_no_install.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_env_publish.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_env_pull.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_env_pull_coverage.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_env_pull_loader_coverage.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_env_pull_managed_control_plane.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_env_push.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_env_ref_pinning.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_env_test.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_envs_coverage.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_export.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_flash_mvp.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_flashinfer_cache_dirs.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_freesolo_api_transport.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_fused_expert_warmstart.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_github_urlopen_retry.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_gpu_type_single_field.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_gpus.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_grpo_params.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_grpo_resident_sizing.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_grpo_reward_batching.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_health_liveness.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_hf_retry.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_idle_endpoint_reaper.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_infisical_secrets.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_internal_client.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_kv_util.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_lambda_api_coverage.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_logging.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_login_perms.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_lora_rank_coverage.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_lora_rank_preflight.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_managed_config_fields.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_managed_hf_repo.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_metrics_schema_agent_contract.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_mig_guard.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_multi_gpu_gate.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_multimodal_training.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_named_reward_metrics.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_oom_escalate_gpu.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_opd.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_opd_limits.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_opd_multiturn_eos_boundary.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_opd_multiturn_failure_exit.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_opd_replay_guard.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_opd_resume_safety.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_opd_train.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_orchestrator_flash.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_packing.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_packing_coverage.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_parasail_teacher.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_poll_helpers.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_preflight.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_projects.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_prompt_budget.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_provider_preflight_coverage.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_provider_routing.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_providers_symmetry.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_realized_cost.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_repo_cleanup.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_resolve_params_b.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_resume_on_retry.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_rl_train.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_rollout_samples.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_runpod_api_delete.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_runpod_key_fingerprint.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_runpod_key_waterfall.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_serve.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_serve_reasoning_content.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_server_app_coverage.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_server_auth_singleflight.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_server_billing.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_server_checkpoints_coverage.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_server_db.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_server_locks_coverage.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_server_standalone.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_serving_context_preflight.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_serving_contract.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_serving_schema_coverage.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_sft_chunked_nll.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_sft_example_selection.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_sft_gc_off.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_sft_max_context.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_sft_startup_block.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_sft_train.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_sft_workload.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_step_floor.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_step_metrics.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_step_timing.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_structured_outputs.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_teacher_broker.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_teacher_encoding_contract.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_terminal_artifacts.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_thinking_config.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_train_context_preflight.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_training_controls.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_type_comment_prose.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_vast_api.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_vast_api_coverage.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_vast_offers.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_vast_provider_coverage.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_verified_revisions.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_verifiers.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_verl_checkpoint_export.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_verl_child_plugins.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_verl_silence_watchdog.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_version.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_vl_warmstart_adapter_keys.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_vram_architecture.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_wandb_link.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_wandb_naming.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_warmstart_adapter_download.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_warmstart_error_attribution.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_worker_dryrun.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_worker_hardexit.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_worker_thinking.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_workflow_contracts.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_workload_profile.py +0 -0
- {freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/tests/test_zero2_sharding_gate.py +0 -0
|
@@ -39,6 +39,34 @@ This file starts at 1.1.35. Earlier releases are not reconstructed here; use
|
|
|
39
39
|
|
|
40
40
|
### Fixed
|
|
41
41
|
|
|
42
|
+
- An ordered `[gpu] type` list is now priced over every class it declares acceptable, not just the
|
|
43
|
+
first. Allocation cost-ranks the whole set, so quoting the head alone priced a shape the run may
|
|
44
|
+
never be given — an authored `["B200", "H100"]` quoted roughly 3x the H100 the allocator would
|
|
45
|
+
really rent, and the submit-time affordability check runs on that estimate, so a run the
|
|
46
|
+
organization could afford could be refused before allocation ever got to choose. A single
|
|
47
|
+
authored class is still a hard pin, and a no-fit rejection now names every acceptable class
|
|
48
|
+
rather than whichever happened to be written first.
|
|
49
|
+
|
|
50
|
+
- A provider preference that exhausts every configured provider no longer falls back to quoting
|
|
51
|
+
hardware this plane cannot rent. The final fallback dropped the restriction and ranked the
|
|
52
|
+
registered RunPod pool regardless of credentials, so a vast-only plane could quote a B200: the
|
|
53
|
+
estimate passed affordability and the run was recorded, only for live allocation to fail. The
|
|
54
|
+
quote now raises against the eligible set, which names the real constraint.
|
|
55
|
+
|
|
56
|
+
- A GitHub token that is invalid, expired, or missing a scope now fails during preparation instead
|
|
57
|
+
of after a GPU is rented. Non-rate-limit 401 and 403 responses were left as untyped errors, which
|
|
58
|
+
the submit-time preflight treats as a transient blip worth deferring, so the run proceeded
|
|
59
|
+
through affordability and allocation and hit the same permanent credential error on the worker.
|
|
60
|
+
They are now classified permanent, like 404 and 422. The rate-limit 403 is still transient.
|
|
61
|
+
|
|
62
|
+
- A slow heartbeat upload no longer stalls every other heartbeat behind it. The throttle clock only
|
|
63
|
+
advances once a commit lands, so during a slow HuggingFace commit other callers still saw an
|
|
64
|
+
upload as due and blocked on the upload lock for up to its acquire timeout — 30s, or 120s on a
|
|
65
|
+
critical stage — which stalled the liveness daemon and delayed leaving the wrapped stage by the
|
|
66
|
+
same window. A throttled heartbeat now skips while a commit is in flight, since that commit
|
|
67
|
+
already carries the stage's state. Terminal, error, initial, and forced step commits still queue
|
|
68
|
+
and land: they carry state no later heartbeat would repair.
|
|
69
|
+
|
|
42
70
|
- A GRPO or OPD run whose rollout actor exited hard no longer wedges on a paid GPU until the
|
|
43
71
|
wall-time limit. The actor's `os._exit` bypassed verl's own prompt handler, so the prompt
|
|
44
72
|
stayed `running` forever and verl's unbounded replay poll waited on it at ~0% utilization. The
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: freesolo-flash-dev
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.58
|
|
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
|
|
@@ -27,19 +27,7 @@ from uuid import UUID
|
|
|
27
27
|
|
|
28
28
|
from flash._internal.diagnostics import SECRET_ENV_KEYS_ENV
|
|
29
29
|
from flash.core.catalog import DEFAULT_MODEL, normalize_algorithm
|
|
30
|
-
|
|
31
|
-
# `DROPPED_TOP_LEVEL_KEYS` keeps its historical private alias rather than being renamed at its 5 call
|
|
32
|
-
# sites: `flash.runner` re-exports it as a package attribute and `preparation.py` reads it back through
|
|
33
|
-
# `_runner()`, which is the seam the tests patch. Renaming it is a separate change from moving it, and
|
|
34
|
-
# doing both at once would put a live recovery path's patch points inside a refactor whose whole claim
|
|
35
|
-
# is that nothing behavioral moved.
|
|
36
|
-
from flash.core.spec_persistence import (
|
|
37
|
-
DROPPED_TOP_LEVEL_KEYS as _DROPPED_TOP_LEVEL_KEYS,
|
|
38
|
-
)
|
|
39
30
|
from flash.core.spec_persistence import (
|
|
40
|
-
REMOVED_PERSISTED_TRAIN_KEYS,
|
|
41
|
-
announce_dropped_keys,
|
|
42
|
-
migrated_optimizer_batch,
|
|
43
31
|
opt_float,
|
|
44
32
|
opt_int,
|
|
45
33
|
str_tuple,
|
|
@@ -654,10 +642,9 @@ class JobSpec:
|
|
|
654
642
|
if not isinstance(data, dict):
|
|
655
643
|
raise TypeError("job spec must be an object")
|
|
656
644
|
allowed_top_level = {item.name for item in fields(cls)}
|
|
657
|
-
unknown_top_level = sorted(set(data) - allowed_top_level
|
|
645
|
+
unknown_top_level = sorted(set(data) - allowed_top_level)
|
|
658
646
|
if unknown_top_level:
|
|
659
647
|
raise ValueError(f"job spec has unknown key(s): {', '.join(unknown_top_level)}")
|
|
660
|
-
announce_dropped_keys(data)
|
|
661
648
|
env = data.get("environment") or {}
|
|
662
649
|
# Reject stale payloads carrying a local `path`; worker only runs published env ids.
|
|
663
650
|
if isinstance(env, dict) and env.get("path"):
|
|
@@ -665,12 +652,7 @@ class JobSpec:
|
|
|
665
652
|
"local environment paths are no longer supported; the worker only runs "
|
|
666
653
|
"published Freesolo environment ids"
|
|
667
654
|
)
|
|
668
|
-
train = validated_section(
|
|
669
|
-
data,
|
|
670
|
-
"train",
|
|
671
|
-
{item.name for item in fields(TrainSpec)},
|
|
672
|
-
removed=REMOVED_PERSISTED_TRAIN_KEYS,
|
|
673
|
-
)
|
|
655
|
+
train = validated_section(data, "train", {item.name for item in fields(TrainSpec)})
|
|
674
656
|
gpu = validated_section(data, "gpu", {item.name for item in fields(GpuSpec)})
|
|
675
657
|
gpu_type, gpu_type_fallbacks = _parse_persisted_gpu_types(gpu)
|
|
676
658
|
provider, providers = validated_persisted_providers(gpu, gpu_type, gpu_type_fallbacks)
|
|
@@ -679,9 +661,8 @@ class JobSpec:
|
|
|
679
661
|
raise TypeError("project must be a string")
|
|
680
662
|
project = require_project_id(project_raw) if project_raw.strip() else ""
|
|
681
663
|
algorithm = normalize_algorithm(data.get("algorithm", cls.algorithm))
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
batch_size, prompts_per_step = migrated_optimizer_batch(train, algorithm)
|
|
664
|
+
batch_size = opt_int(train.get("batch_size"))
|
|
665
|
+
prompts_per_step = opt_int(train.get("prompts_per_step"))
|
|
685
666
|
return cls(
|
|
686
667
|
model=data.get("model", cls.model),
|
|
687
668
|
model_revision=_model_revision(data.get("model_revision", cls.model_revision)),
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""Decoding rules for PERSISTED job-spec records, as distinct from authored configuration.
|
|
2
|
+
|
|
3
|
+
`JobSpec` serves four different contracts, and this module owns exactly one of them: reading back
|
|
4
|
+
bytes that were already written to `~/.flash/runs/<run_id>.json`. That is not the same job as
|
|
5
|
+
validating a config a user just wrote, and the two must not be confused:
|
|
6
|
+
|
|
7
|
+
- authored configuration is parsed by `flash.schema.spec_from_dict`, which is STRICT. an unknown key
|
|
8
|
+
is a typo in a file the author can still fix, so it fails loudly.
|
|
9
|
+
- a persisted record is parsed by `JobSpec.from_dict`, which applies the looser scalar coercions
|
|
10
|
+
here. It reads a record this build wrote, in this build's shape; an unknown key is fatal in both.
|
|
11
|
+
|
|
12
|
+
Serialized-byte warning: `flash/runner/preparation.py::_preparation_digest` sha256-hashes the
|
|
13
|
+
canonical JSON of `to_dict()` and `to_internal_dict()` output. Key ORDER is safe there
|
|
14
|
+
(`sort_keys=True`), but key PRESENCE is not -- adding, dropping, or renaming a key in a decode path
|
|
15
|
+
changes the digest and fails integrity validation for a run whose snapshot was already written.
|
|
16
|
+
|
|
17
|
+
These functions take plain dicts and return plain dicts and scalars. That is the rule that keeps the
|
|
18
|
+
module importable by `spec.py` rather than the other way round, and it is why `validated_section`
|
|
19
|
+
takes its allowed-key set as an argument instead of reading `fields(TrainSpec)` itself.
|
|
20
|
+
|
|
21
|
+
What is deliberately NOT here: `_coerce_wandb` and `_parse_persisted_gpu_types` are also called only
|
|
22
|
+
from `JobSpec.from_dict`, so they belong to this contract by usage -- but they construct `WandbSpec`
|
|
23
|
+
and reach `_validated_gpu_type`, which `__post_init__` needs too. Moving them would make this module
|
|
24
|
+
import the dataclasses that import it. The boundary is therefore drawn at "persisted-decoding logic
|
|
25
|
+
that does not depend on the spec types themselves".
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
from typing import Any
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def validated_section(data: dict[str, Any], name: str, allowed: set[str]) -> dict[str, Any]:
|
|
34
|
+
"""Read one nested block (``[train]``, ``[gpu]``) of a persisted record, rejecting unknown keys.
|
|
35
|
+
|
|
36
|
+
A missing block and an explicit null are the same state -- both mean "authored nothing" -- so both
|
|
37
|
+
normalize to empty rather than one of them raising. An unknown key is fatal.
|
|
38
|
+
"""
|
|
39
|
+
section = data.get(name)
|
|
40
|
+
if section is None:
|
|
41
|
+
section = {}
|
|
42
|
+
if not isinstance(section, dict):
|
|
43
|
+
raise TypeError(f"{name} must be an object")
|
|
44
|
+
unknown = sorted(set(section) - allowed)
|
|
45
|
+
if unknown:
|
|
46
|
+
raise ValueError(f"{name} has unknown key(s): {', '.join(unknown)}")
|
|
47
|
+
return section
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def validated_persisted_providers(
|
|
51
|
+
gpu: dict[str, Any], gpu_type: str, gpu_type_fallbacks: tuple[str, ...]
|
|
52
|
+
) -> tuple[str, tuple[str, ...]]:
|
|
53
|
+
"""``(provider, providers)`` from a persisted ``[gpu]`` block, cross-checked against its classes.
|
|
54
|
+
|
|
55
|
+
``GpuSpec.__post_init__`` runs the same both-set check but cannot replace this one: ``allow_empty``
|
|
56
|
+
here keys off whether the record CARRIED a ``providers`` key, and that presence is exactly what the
|
|
57
|
+
dataclass has already lost by the time it validates. An explicitly empty preference and an absent
|
|
58
|
+
one are different states in a stored record.
|
|
59
|
+
"""
|
|
60
|
+
from flash.providers import PROVIDER_NAMES, validated_provider_preferences
|
|
61
|
+
|
|
62
|
+
provider = gpu.get("provider", "")
|
|
63
|
+
if not isinstance(provider, str):
|
|
64
|
+
raise TypeError("gpu.provider must be a string")
|
|
65
|
+
provider = provider.strip().lower()
|
|
66
|
+
providers = validated_provider_preferences(
|
|
67
|
+
gpu.get("providers", ()), allow_empty="providers" not in gpu
|
|
68
|
+
)
|
|
69
|
+
if provider and providers:
|
|
70
|
+
raise ValueError("gpu.provider and gpu.providers cannot both be set")
|
|
71
|
+
if provider or providers or gpu_type:
|
|
72
|
+
from flash.providers.base import providers_for
|
|
73
|
+
|
|
74
|
+
if provider and provider not in PROVIDER_NAMES:
|
|
75
|
+
raise ValueError(f"unknown gpu.provider {provider!r}")
|
|
76
|
+
# a hard provider pin must carry every acceptable class. provider preferences stay soft: an
|
|
77
|
+
# ineligible named provider contributes no candidate, while eligible named or unnamed
|
|
78
|
+
# configured providers remain available for failover.
|
|
79
|
+
for candidate in (gpu_type, *gpu_type_fallbacks):
|
|
80
|
+
if candidate and provider and provider not in providers_for(candidate):
|
|
81
|
+
raise ValueError(
|
|
82
|
+
f"gpu.provider {provider!r} cannot provision gpu.type {candidate!r}"
|
|
83
|
+
)
|
|
84
|
+
return provider, providers
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def str_tuple(value: Any) -> tuple[str, ...]:
|
|
88
|
+
"""Normalize a string-or-list knob to a tuple of strings; a bare string is one element, not iterated."""
|
|
89
|
+
if value is None:
|
|
90
|
+
return ()
|
|
91
|
+
if isinstance(value, str):
|
|
92
|
+
return (value,) if value else ()
|
|
93
|
+
return tuple(s for s in (str(x) for x in value) if s)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def volume_gb(value: Any, default: int = 100) -> int:
|
|
97
|
+
"""Parse volume size in GB; non-positive / non-numeric / missing values return default."""
|
|
98
|
+
if isinstance(value, bool):
|
|
99
|
+
# bool is an int subclass; reject to avoid int(True)==1 becoming a 1 GB volume.
|
|
100
|
+
return default
|
|
101
|
+
try:
|
|
102
|
+
gb = int(value)
|
|
103
|
+
except (TypeError, ValueError):
|
|
104
|
+
return default
|
|
105
|
+
return gb if gb > 0 else default
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def opt_int(value: Any) -> int | None:
|
|
109
|
+
"""Parse optional int; rejects bools (bool is int subclass — int(True)==1 is a footgun)."""
|
|
110
|
+
if value is None:
|
|
111
|
+
return None
|
|
112
|
+
if isinstance(value, bool):
|
|
113
|
+
raise TypeError(f"expected a number, got bool {value!r}")
|
|
114
|
+
return int(value)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def opt_float(value: Any) -> float | None:
|
|
118
|
+
"""Parse optional float; rejects bools (mirrors ``opt_int``)."""
|
|
119
|
+
if value is None:
|
|
120
|
+
return None
|
|
121
|
+
if isinstance(value, bool):
|
|
122
|
+
raise TypeError(f"expected a number, got bool {value!r}")
|
|
123
|
+
return float(value)
|
|
@@ -597,7 +597,15 @@ def _offline_preferred_gpu_shape(config: RunConfig) -> tuple[str, int, int, str,
|
|
|
597
597
|
quote[4] * quote[2] * sharded_step_seconds(config, quote[0], quote[2], quote[3])
|
|
598
598
|
),
|
|
599
599
|
)
|
|
600
|
-
#
|
|
600
|
+
# every eligible provider has now been tried and none has a structural fit. dropping the
|
|
601
|
+
# restriction here to reach the unpinned `provider="auto"` diagnostic would rank the registered
|
|
602
|
+
# runpod pool regardless of credentials, quoting a shape this plane cannot rent -- the same
|
|
603
|
+
# defect the eligibility filter above exists to prevent, reintroduced at the last step. that
|
|
604
|
+
# quote would then pass affordability and only fail once live allocation runs, after the run is
|
|
605
|
+
# recorded. re-raise the eligible set's own failure instead, which names the real constraint.
|
|
606
|
+
if eligible:
|
|
607
|
+
return _offline_gpu_shape(replace(config, provider=eligible[0], providers=()))
|
|
608
|
+
# no provider is registered at all (an empty registry): keep the historical unpinned answer.
|
|
601
609
|
return _offline_gpu_shape(replace(config, providers=()))
|
|
602
610
|
|
|
603
611
|
|
|
@@ -629,11 +637,18 @@ def _offline_gpu_shape(config: RunConfig) -> tuple[str, int, int, str, float]:
|
|
|
629
637
|
providers_for,
|
|
630
638
|
rentable_gpu_counts,
|
|
631
639
|
)
|
|
632
|
-
from flash.providers.fit_errors import vram_fit_error_message, vram_knob_advice
|
|
633
640
|
|
|
634
641
|
provider = config.provider if config.provider != "auto" else "auto"
|
|
635
642
|
if config.gpu_type:
|
|
636
|
-
|
|
643
|
+
# rank every class the author declared acceptable, not just the head. `allocate()` cost-ranks
|
|
644
|
+
# the whole ordered set, so quoting the head alone prices a shape the run may never be given
|
|
645
|
+
# -- an authored ["B200", "H100"] quotes 3x the H100 the allocator would actually rent, and
|
|
646
|
+
# the submit-time affordability precheck refuses an affordable run on that inflated number.
|
|
647
|
+
names = tuple(
|
|
648
|
+
dict.fromkeys(
|
|
649
|
+
canonical_gpu(name) for name in (config.gpu_type, *config.gpu_type_fallbacks)
|
|
650
|
+
)
|
|
651
|
+
)
|
|
637
652
|
elif provider == "auto":
|
|
638
653
|
# `auto` ranks the RunPod pool: it is the default substrate, and the allocator only reaches a
|
|
639
654
|
# lambda-only class after the cheaper runpod classes exhaust, so quoting one here would name
|
|
@@ -700,43 +715,79 @@ def _offline_gpu_shape(config: RunConfig) -> tuple[str, int, int, str, float]:
|
|
|
700
715
|
)
|
|
701
716
|
)
|
|
702
717
|
if not ranked:
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
raise ValueError(
|
|
712
|
-
f"exact GPU {info.name!r} cannot fit this run: it requires at least {need} GB"
|
|
713
|
-
+ (
|
|
714
|
-
remedy
|
|
715
|
-
or _catalog_check_remedy(config, need, names)
|
|
716
|
-
or f". {vram_knob_advice(config.method).capitalize()}."
|
|
717
|
-
)
|
|
718
|
-
)
|
|
719
|
-
raise ValueError(
|
|
720
|
-
vram_fit_error_message(
|
|
721
|
-
config.method,
|
|
722
|
-
need,
|
|
723
|
-
requested_gpu_count=ceiling,
|
|
724
|
-
effective_gpu_count=safe_gpu_count,
|
|
725
|
-
max_gpu_count=auto_cap,
|
|
726
|
-
gpu_names=names,
|
|
727
|
-
providers=None if provider == "auto" else (provider,),
|
|
728
|
-
# same rule the ranking loop rejected shapes with, so the advice cannot name a
|
|
729
|
-
# width the retry will not launch on.
|
|
730
|
-
executed_width=lambda count: executed_gpu_count(config, count),
|
|
731
|
-
# an offline quote does not know the configured fleet, so it cannot claim that
|
|
732
|
-
# dropping a provider pin would make a wider shape purchasable.
|
|
733
|
-
widenable_without_pin=None,
|
|
734
|
-
)
|
|
718
|
+
_raise_no_fitting_shape(
|
|
719
|
+
config,
|
|
720
|
+
need,
|
|
721
|
+
names,
|
|
722
|
+
provider=provider,
|
|
723
|
+
ceiling=ceiling,
|
|
724
|
+
safe_gpu_count=safe_gpu_count,
|
|
725
|
+
auto_cap=auto_cap,
|
|
735
726
|
)
|
|
736
727
|
_cost, count, _combined, _per_card, gpu, hourly = min(ranked)
|
|
737
728
|
return gpu, need, count, provider, hourly
|
|
738
729
|
|
|
739
730
|
|
|
731
|
+
def _raise_no_fitting_shape(
|
|
732
|
+
config: RunConfig,
|
|
733
|
+
need: float,
|
|
734
|
+
names: tuple[str, ...],
|
|
735
|
+
*,
|
|
736
|
+
provider: str,
|
|
737
|
+
ceiling: int | None,
|
|
738
|
+
safe_gpu_count: int,
|
|
739
|
+
auto_cap: int,
|
|
740
|
+
) -> None:
|
|
741
|
+
"""Reject a run no rentable shape fits, naming what the quote was allowed to rank."""
|
|
742
|
+
from flash.providers.base import GPU_INFO, canonical_gpu
|
|
743
|
+
from flash.providers.fit_errors import vram_fit_error_message, vram_knob_advice
|
|
744
|
+
|
|
745
|
+
# a pinned class is blocked by the class itself, so name it -- the pool-wide message would
|
|
746
|
+
# report the widest validated shape, which is not hardware this quote was ever allowed to
|
|
747
|
+
# use. `_wider_shape_remedy` searches only `names`, already narrowed to the pin, so the
|
|
748
|
+
# `--gpus N` clause it appends can never name a shape the pin forbids. an unpinned run
|
|
749
|
+
# falls through to the pool-wide message, which reports the count that would fit.
|
|
750
|
+
remedy = _wider_shape_remedy(config, need, names)
|
|
751
|
+
if config.gpu_type:
|
|
752
|
+
# name every acceptable class, not just the head: with fallbacks authored, reporting the
|
|
753
|
+
# head alone tells the user to fix a class that may not be the one that failed, and
|
|
754
|
+
# hides that the whole declared set was ranked and rejected.
|
|
755
|
+
declared = tuple(
|
|
756
|
+
GPU_INFO[canonical_gpu(name)].name
|
|
757
|
+
for name in (config.gpu_type, *config.gpu_type_fallbacks)
|
|
758
|
+
)
|
|
759
|
+
label = (
|
|
760
|
+
repr(declared[0])
|
|
761
|
+
if len(declared) == 1
|
|
762
|
+
else "none of " + ", ".join(repr(name) for name in declared)
|
|
763
|
+
)
|
|
764
|
+
raise ValueError(
|
|
765
|
+
f"exact GPU {label} cannot fit this run: it requires at least {need} GB"
|
|
766
|
+
+ (
|
|
767
|
+
remedy
|
|
768
|
+
or _catalog_check_remedy(config, need, names)
|
|
769
|
+
or f". {vram_knob_advice(config.method).capitalize()}."
|
|
770
|
+
)
|
|
771
|
+
)
|
|
772
|
+
raise ValueError(
|
|
773
|
+
vram_fit_error_message(
|
|
774
|
+
config.method,
|
|
775
|
+
need,
|
|
776
|
+
requested_gpu_count=ceiling,
|
|
777
|
+
effective_gpu_count=safe_gpu_count,
|
|
778
|
+
max_gpu_count=auto_cap,
|
|
779
|
+
gpu_names=names,
|
|
780
|
+
providers=None if provider == "auto" else (provider,),
|
|
781
|
+
# same rule the ranking loop rejected shapes with, so the advice cannot name a
|
|
782
|
+
# width the retry will not launch on.
|
|
783
|
+
executed_width=lambda count: executed_gpu_count(config, count),
|
|
784
|
+
# an offline quote does not know the configured fleet, so it cannot claim that
|
|
785
|
+
# dropping a provider pin would make a wider shape purchasable.
|
|
786
|
+
widenable_without_pin=None,
|
|
787
|
+
)
|
|
788
|
+
)
|
|
789
|
+
|
|
790
|
+
|
|
740
791
|
def _allocation_quote_shape(config: RunConfig, allocation) -> tuple[str, int, int, str, float]:
|
|
741
792
|
"""The (gpu, need, count, provider, per-card rate) billed against a SELECTED live candidate.
|
|
742
793
|
|
|
@@ -213,6 +213,11 @@ def runconfig_from_spec(spec) -> RunConfig:
|
|
|
213
213
|
# and a caller that predates the preference has no such attribute to offer.
|
|
214
214
|
providers=getattr(g, "providers", ()) or (),
|
|
215
215
|
gpu_type=g.type,
|
|
216
|
+
# the rest of an ordered `[gpu] type` list. allocation cost-ranks every acceptable class, so
|
|
217
|
+
# dropping these here quotes the head alone and the affordability precheck can refuse a run
|
|
218
|
+
# whose cheaper authored fallback it would really have rented. read defensively for the same
|
|
219
|
+
# reason as `providers` above: this is not always a GpuSpec.
|
|
220
|
+
gpu_type_fallbacks=tuple(getattr(g, "type_fallbacks", ()) or ()),
|
|
216
221
|
model_revision=spec.model_revision,
|
|
217
222
|
disk_gb=float(getattr(g, "disk_gb", 0.0) or 0.0),
|
|
218
223
|
# deliberately NOT spec.authored_gpu_count: this asks whether a shape has been RESOLVED
|
|
@@ -61,6 +61,12 @@ class RunConfig:
|
|
|
61
61
|
sft_retained_examples: int | None = None
|
|
62
62
|
# appended for the same positional-constructor reason as sft_retained_examples above.
|
|
63
63
|
providers: tuple[str, ...] = ()
|
|
64
|
+
# the remaining classes an ordered `[gpu] type` list accepts, after gpu_type takes the head.
|
|
65
|
+
# allocation cost-ranks the whole acceptable set, so quoting the head alone prices a shape the
|
|
66
|
+
# run may never be given: an authored ["B200", "H100"] is quoted on B200 while allocate() would
|
|
67
|
+
# rent the cheaper H100, and the affordability precheck runs on that inflated estimate.
|
|
68
|
+
# appended for the same positional-constructor reason as the two fields above.
|
|
69
|
+
gpu_type_fallbacks: tuple[str, ...] = ()
|
|
64
70
|
|
|
65
71
|
def __post_init__(self) -> None:
|
|
66
72
|
object.__setattr__(self, "method", normalize_algorithm(self.method))
|
|
@@ -87,6 +93,24 @@ class RunConfig:
|
|
|
87
93
|
if prov != "auto" and prov not in providers_for(exact):
|
|
88
94
|
raise ValueError(f"provider {prov!r} cannot provision gpu_type {exact!r}")
|
|
89
95
|
object.__setattr__(self, "gpu_type", exact)
|
|
96
|
+
# canonicalized and validated exactly like the head above, so a quote cannot rank a class the
|
|
97
|
+
# spec layer would have rejected. deduped against the head and each other because the
|
|
98
|
+
# ranking loop would otherwise price the same class twice.
|
|
99
|
+
fallbacks: list[str] = []
|
|
100
|
+
for entry in self.gpu_type_fallbacks or ():
|
|
101
|
+
if not isinstance(entry, str):
|
|
102
|
+
raise TypeError("gpu_type_fallbacks entries must be strings")
|
|
103
|
+
name = canonical_gpu(entry)
|
|
104
|
+
info = GPU_INFO.get(name)
|
|
105
|
+
if info is None or not info.validated:
|
|
106
|
+
raise ValueError(
|
|
107
|
+
f"gpu_type_fallbacks entry {name!r} must name an active validated GPU class"
|
|
108
|
+
)
|
|
109
|
+
if name != exact and name not in fallbacks:
|
|
110
|
+
fallbacks.append(name)
|
|
111
|
+
if fallbacks and not exact:
|
|
112
|
+
raise ValueError("gpu_type_fallbacks requires gpu_type")
|
|
113
|
+
object.__setattr__(self, "gpu_type_fallbacks", tuple(fallbacks))
|
|
90
114
|
if not isinstance(self.model_revision, str):
|
|
91
115
|
raise TypeError("model_revision must be a string")
|
|
92
116
|
object.__setattr__(self, "model_revision", self.model_revision.strip())
|
|
@@ -97,6 +97,19 @@ _HB_UPLOAD_LOCK = threading.Lock()
|
|
|
97
97
|
# Terminal/error commits wait longer — no later heartbeat can repair them.
|
|
98
98
|
_HB_UPLOAD_LOCK_TIMEOUT_S = 30.0
|
|
99
99
|
_HB_CRITICAL_UPLOAD_LOCK_TIMEOUT_S = 120.0
|
|
100
|
+
# True while a thread holds _HB_UPLOAD_LOCK and is inside the HF commit. Read under _HB_LOCK.
|
|
101
|
+
#
|
|
102
|
+
# The throttle clock (_HB_LAST_UPLOAD) only advances AFTER a commit lands, so during a slow HF
|
|
103
|
+
# commit every other throttled caller still computes upload_due=True, walks into
|
|
104
|
+
# _HB_UPLOAD_LOCK.acquire() and blocks there for up to the acquire timeout -- 30s, or 120s on a
|
|
105
|
+
# critical stage. That stalls the liveness daemon, and `liveness_heartbeat`'s join delays leaving
|
|
106
|
+
# the wrapped stage by the same window.
|
|
107
|
+
#
|
|
108
|
+
# A marker rather than claiming the clock before the upload: an optimistic claim has to be rolled
|
|
109
|
+
# back when the commit fails, and the rollback has to decide whether a NEWER heartbeat already
|
|
110
|
+
# moved the clock (the reason the old code carried a claim sequence). This says only "a commit is
|
|
111
|
+
# in flight right now", is cleared in a finally, and so cannot strand the throttle on a failure.
|
|
112
|
+
_HB_UPLOAD_IN_FLIGHT = False
|
|
100
113
|
# retain at least one metric row per second across the 900s training heartbeat throttle window.
|
|
101
114
|
GRPO_METRIC_HISTORY_LIMIT = 1024
|
|
102
115
|
|
|
@@ -127,6 +140,12 @@ def _console_heartbeat_snapshot(
|
|
|
127
140
|
return json.dumps(console_payload)
|
|
128
141
|
|
|
129
142
|
|
|
143
|
+
def _set_upload_in_flight(value: bool) -> None:
|
|
144
|
+
"""Mark whether an HF heartbeat commit is running. Call with _HB_LOCK held."""
|
|
145
|
+
global _HB_UPLOAD_IN_FLIGHT
|
|
146
|
+
_HB_UPLOAD_IN_FLIGHT = value
|
|
147
|
+
|
|
148
|
+
|
|
130
149
|
def _heartbeat_upload_due(
|
|
131
150
|
stage: str,
|
|
132
151
|
*,
|
|
@@ -140,6 +159,22 @@ def _heartbeat_upload_due(
|
|
|
140
159
|
"""return eligibility from committed throttle state while _HB_LOCK is held."""
|
|
141
160
|
if initial or _is_critical_stage(stage):
|
|
142
161
|
return True
|
|
162
|
+
# a commit is already in flight and will advance the throttle clock when it lands. an unforced
|
|
163
|
+
# ping would only queue behind it on _HB_UPLOAD_LOCK, publish a snapshot older than the one
|
|
164
|
+
# being written, and block its caller for the acquire timeout -- 30s, or 120s on a critical
|
|
165
|
+
# stage. that is what stalls the liveness daemon, whose `join` then delays leaving the wrapped
|
|
166
|
+
# stage by the same window. skipping loses nothing: the in-flight commit carries this stage.
|
|
167
|
+
#
|
|
168
|
+
# three exemptions, all above or inside this check:
|
|
169
|
+
# - initial and critical stages return True earlier: a terminal or error snapshot has no later
|
|
170
|
+
# heartbeat to repair it, so it must queue and land.
|
|
171
|
+
# - `force` is excluded here because it carries billing state. a forced commit marks a
|
|
172
|
+
# DISTINCT completed step, and a cancel bills the last step a heartbeat recorded, so
|
|
173
|
+
# dropping one to avoid a wait could under-report a step the run really finished.
|
|
174
|
+
# the daemon's own pings are never forced (liveness and keepalive both leave it False), so this
|
|
175
|
+
# exemption does not reopen the stall it fixes.
|
|
176
|
+
if _HB_UPLOAD_IN_FLIGHT and not force:
|
|
177
|
+
return False
|
|
143
178
|
if _w._HB_TERMINAL_ONLY:
|
|
144
179
|
return (
|
|
145
180
|
_w._HB_LAST_UPLOAD == 0.0 or (now - _w._HB_LAST_UPLOAD) >= _HB_TERMINAL_ONLY_INTERVAL_S
|
|
@@ -234,12 +269,18 @@ def heartbeat(
|
|
|
234
269
|
up = f"/tmp/.hb-upload-{os.getpid()}-{threading.get_ident()}.json"
|
|
235
270
|
with open(up, "w") as f:
|
|
236
271
|
f.write(snapshot)
|
|
272
|
+
with _HB_LOCK:
|
|
273
|
+
_set_upload_in_flight(True)
|
|
237
274
|
try:
|
|
238
275
|
if initial:
|
|
239
276
|
committed = _w.hf_upload_file(up, "heartbeat.json", required=True)
|
|
240
277
|
else:
|
|
241
278
|
committed = _w.hf_upload_file(up, "heartbeat.json")
|
|
242
279
|
finally:
|
|
280
|
+
# cleared before the throttle clock is advanced below, and in a finally so a
|
|
281
|
+
# raising upload cannot leave every later heartbeat permanently skipped.
|
|
282
|
+
with _HB_LOCK:
|
|
283
|
+
_set_upload_in_flight(False)
|
|
243
284
|
with contextlib.suppress(OSError):
|
|
244
285
|
os.remove(up)
|
|
245
286
|
if committed is False:
|
{freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/engine/worker/perf/__init__.py
RENAMED
|
@@ -5,7 +5,7 @@ The fla/tilelang/cudart fixup group stays IN THIS MODULE on purpose: tests monke
|
|
|
5
5
|
through the patched module globals. Do NOT move this group into a submodule.
|
|
6
6
|
|
|
7
7
|
NOTE: ``tests/test_worker_stack.py`` reads THIS file as TEXT to assert the fla SHA /
|
|
8
|
-
TILELANG_PIN stay in lockstep with
|
|
8
|
+
TILELANG_PIN stay in lockstep with Dockerfile.worker.
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
11
|
from __future__ import annotations
|
|
@@ -315,7 +315,7 @@ def _ensure_fla_fastpath_on_hopper() -> None:
|
|
|
315
315
|
return False
|
|
316
316
|
return rc == 0
|
|
317
317
|
|
|
318
|
-
# 0.1.12 double-registers the TVM-FFI runtime -> `import tilelang` aborts; keep in lockstep with
|
|
318
|
+
# 0.1.12 double-registers the TVM-FFI runtime -> `import tilelang` aborts; keep in lockstep with Dockerfile.worker.
|
|
319
319
|
TVM_FFI_PIN = "0.1.11"
|
|
320
320
|
TILELANG_PIN = "0.1.11"
|
|
321
321
|
|
|
@@ -334,7 +334,7 @@ def _ensure_fla_fastpath_on_hopper() -> None:
|
|
|
334
334
|
fla_ok = True
|
|
335
335
|
if not (_have("fla") and _have("fla.modules")):
|
|
336
336
|
_remove_fla_from_disk()
|
|
337
|
-
# Pinned commit — keep in lockstep with
|
|
337
|
+
# Pinned commit — keep in lockstep with Dockerfile.worker.
|
|
338
338
|
fla_ok = _pip(
|
|
339
339
|
"--no-deps",
|
|
340
340
|
"git+https://github.com/fla-org/flash-linear-attention.git"
|
|
@@ -46,7 +46,7 @@ class GitHubUnavailableError(GitHubTransientError):
|
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
class GitHubPermanentError(RuntimeError):
|
|
49
|
-
"""GitHub answered, and the answer will not change on a retry:
|
|
49
|
+
"""GitHub answered, and the answer will not change on a retry: 401, 403, 404, or 422.
|
|
50
50
|
|
|
51
51
|
Deliberately NOT a GitHubTransientError. Waiting is the right response to a blip and the wrong
|
|
52
52
|
response to a typo, and the two are indistinguishable once both are a bare RuntimeError -- which
|
|
@@ -57,6 +57,10 @@ class GitHubPermanentError(RuntimeError):
|
|
|
57
57
|
read, rather than leaking its existence with a 403. Both are permanent for this caller: no
|
|
58
58
|
amount of retrying makes an unreadable ref resolvable, and the fix (check the name, or grant the
|
|
59
59
|
token access) is the user's either way. The message carries GitHub's own text so it names which.
|
|
60
|
+
|
|
61
|
+
The credential codes reach here only after the rate-limit shapes (429, and the 403 that says
|
|
62
|
+
rate limit) have been claimed as transient, so a 401 or a surviving 403 is a token this plane
|
|
63
|
+
cannot fix by waiting: invalid, expired, or missing the scope. Same user-side fix as a typo.
|
|
60
64
|
"""
|
|
61
65
|
|
|
62
66
|
|
|
@@ -285,9 +285,13 @@ def _urlopen(
|
|
|
285
285
|
) from exc
|
|
286
286
|
# 404 (no such repo, or one the token cannot read) and 422 (a ref that does not exist,
|
|
287
287
|
# e.g. "No commit found for SHA: main" on a master-default repo) are settled answers.
|
|
288
|
+
# 401 and a non-rate-limit 403 join them: the rate-limit shapes are already claimed
|
|
289
|
+
# above, so what is left is a token this plane cannot fix by waiting -- invalid,
|
|
290
|
+
# expired, or lacking the scope. deferring those rents a GPU to rediscover the same
|
|
291
|
+
# credential error on the worker.
|
|
288
292
|
# Typed so the submit-time pin can fail closed on them while still deferring a blip;
|
|
289
293
|
# every other code keeps the untyped RuntimeError it has always raised.
|
|
290
|
-
if exc.code in (404, 422):
|
|
294
|
+
if exc.code in (401, 403, 404, 422):
|
|
291
295
|
raise GitHubPermanentError(
|
|
292
296
|
f"GitHub environment request failed ({exc.code}): {body[:500]}"
|
|
293
297
|
) from exc
|
{freesolo_flash_dev-1.2.52 → freesolo_flash_dev-1.2.58}/flash/providers/_lifecycle/bootstrap.py
RENAMED
|
@@ -257,15 +257,31 @@ def hf_upload(
|
|
|
257
257
|
return False
|
|
258
258
|
|
|
259
259
|
|
|
260
|
-
def _upload_console_snapshot(
|
|
261
|
-
|
|
262
|
-
|
|
260
|
+
def _upload_console_snapshot(
|
|
261
|
+
payload: dict, console: str, mode: str, extra: str = "", final: bool = False
|
|
262
|
+
) -> bool:
|
|
263
|
+
"""Upload one console snapshot from an isolated process.
|
|
264
|
+
|
|
265
|
+
The periodic snapshot and the terminal one never share a scratch file or a repo destination.
|
|
266
|
+
Reaping the periodic child at teardown is best-effort, so one killed mid-write would otherwise
|
|
267
|
+
truncate the scratch file the terminal snapshot is uploading, or overwrite the terminal artifact
|
|
268
|
+
itself -- losing the failure detail the control plane reads, including the wall-clock-cap marker.
|
|
269
|
+
|
|
270
|
+
The terminal snapshot keeps the canonical ``console_<mode>.txt`` the control plane reads; the
|
|
271
|
+
periodic one takes the attempt-scoped name it reads separately, matching the serverless handler,
|
|
272
|
+
so a retry cannot overwrite the attempt that reproduced the failure. This module can never
|
|
273
|
+
import flash, so the format is spelled out here and pinned against
|
|
274
|
+
``flash.adapters.artifacts.attempt_scoped_artifact_name`` by test rather than by coincidence --
|
|
275
|
+
a name the reader does not expect looks exactly like a worker that uploaded nothing.
|
|
276
|
+
"""
|
|
277
|
+
kind = "" if final else f"_attempt{payload.get('attempt', 0)}"
|
|
278
|
+
tail_path = f"{console}{kind}.tail"
|
|
263
279
|
tail = _read_console_tail(console, 64_000, secrets=_payload_secrets(payload))
|
|
264
280
|
if extra:
|
|
265
281
|
tail += extra
|
|
266
282
|
with open(tail_path, "w", encoding="utf-8", errors="replace") as f:
|
|
267
283
|
f.write(_safe_detail(tail, 64_000, secrets=_payload_secrets(payload)))
|
|
268
|
-
return hf_upload(payload, tail_path, f"console_{mode}.txt")
|
|
284
|
+
return hf_upload(payload, tail_path, f"console_{mode}{kind}.txt")
|
|
269
285
|
|
|
270
286
|
|
|
271
287
|
def _console_upload_loop(
|
|
@@ -453,7 +469,7 @@ def _upload_console_tail_bounded(
|
|
|
453
469
|
context = multiprocessing.get_context("spawn")
|
|
454
470
|
process = context.Process(
|
|
455
471
|
target=_upload_console_snapshot,
|
|
456
|
-
args=(payload, console, mode, extra),
|
|
472
|
+
args=(payload, console, mode, extra, True),
|
|
457
473
|
daemon=True,
|
|
458
474
|
)
|
|
459
475
|
process.start()
|
|
@@ -77,8 +77,13 @@ def _run_console_upload_loop(console: str, interval_s: float, stop_upload, *, up
|
|
|
77
77
|
prevents a flapping run from turning the poll cadence into the commit cadence.
|
|
78
78
|
|
|
79
79
|
Before any heartbeat commits, one additional setup snapshot lands before the fixed 3000-second
|
|
80
|
-
teardown. It does not enter the steady rate: the first committed heartbeat
|
|
81
|
-
the normal interval
|
|
80
|
+
teardown. It does not enter the steady rate: the first committed heartbeat promotes the deadline
|
|
81
|
+
to the normal interval, so a run that commits before 600 seconds never spends that write. the
|
|
82
|
+
promotion is skipped while ``due`` holds, so it only ever moves a deadline that has not arrived.
|
|
83
|
+
A 600-second deadline that already expired with nothing committed still spends its snapshot --
|
|
84
|
+
the startup evidence it exists for -- and a failed upload on that same poll leaves the deadline
|
|
85
|
+
due, so the next poll retries rather than waiting out the hour. Once promoted the deadline is the
|
|
86
|
+
hourly interval, so the guard cannot re-fire early and needs no separate first-commit flag.
|
|
82
87
|
"""
|
|
83
88
|
poll_s = min(_CONSOLE_UPLOAD_POLL_S, interval_s)
|
|
84
89
|
due_s = min(_CONSOLE_UPLOAD_FIRST_SNAPSHOT_S, interval_s)
|
|
@@ -87,14 +92,13 @@ def _run_console_upload_loop(console: str, interval_s: float, stop_upload, *, up
|
|
|
87
92
|
while not stop_upload.wait(poll_s):
|
|
88
93
|
since += poll_s
|
|
89
94
|
cursor, eof, staged, beats = _console_progress(console, max(cursor, 0))
|
|
90
|
-
had_committed = ever
|
|
91
95
|
ever = ever or bool(staged)
|
|
92
|
-
|
|
96
|
+
due = since >= due_s
|
|
97
|
+
if ever and not due:
|
|
93
98
|
due_s = interval_s
|
|
94
99
|
made_progress = staged if ever else beats
|
|
95
100
|
armed = armed or bool(made_progress)
|
|
96
101
|
quiet = 0.0 if made_progress else quiet + 1
|
|
97
|
-
due = since >= due_s
|
|
98
102
|
cap = armed and quiet >= _CONSOLE_UPLOAD_QUIET_POLLS
|
|
99
103
|
wedged = cap and spent < _CONSOLE_UPLOAD_CREDITS and not due
|
|
100
104
|
if eof == sent or not (due or wedged):
|