freesolo-flash-dev 1.2.49__tar.gz → 1.2.52__tar.gz

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