freesolo-flash-dev 1.2.59__tar.gz → 1.2.61__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 (578) hide show
  1. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/CHANGELOG.md +4 -0
  2. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/PKG-INFO +1 -1
  3. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/content/multimodal.py +12 -3
  4. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/core/spec.py +89 -34
  5. freesolo_flash_dev-1.2.61/flash/core/spec_persistence.py +414 -0
  6. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/backend_common.py +1 -0
  7. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/core/child/glue.py +58 -3
  8. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/overrides.py +2 -26
  9. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/child/multiturn.py +26 -7
  10. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/multi_turn.py +83 -12
  11. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/verl_config.py +2 -0
  12. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/verl/capabilities.py +10 -0
  13. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/adapter.py +38 -46
  14. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/__init__.py +11 -2
  15. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/preparation.py +18 -9
  16. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/status.py +11 -3
  17. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/submit.py +40 -18
  18. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/schema/__init__.py +13 -15
  19. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/pyproject.toml +2 -2
  20. freesolo_flash_dev-1.2.61/tests/test_catalog_only_models.py +88 -0
  21. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_charge_pricing.py +18 -0
  22. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cost_hardware.py +0 -50
  23. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_managed_config_fields.py +26 -2
  24. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_opd_train.py +4 -22
  25. freesolo_flash_dev-1.2.61/tests/test_persisted_spec_envelope.py +255 -0
  26. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_rl_train.py +271 -36
  27. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_server_api.py +5 -0
  28. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_server_billing.py +3 -0
  29. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_spec_and_validation.py +0 -11
  30. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_spec_contract_bytes.py +105 -3
  31. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_verifiers.py +304 -1
  32. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_worker_dryrun.py +16 -12
  33. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/uv.lock +1 -1
  34. freesolo_flash_dev-1.2.59/flash/core/spec_persistence.py +0 -123
  35. freesolo_flash_dev-1.2.59/tests/test_catalog_only_models.py +0 -357
  36. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.dockerignore +0 -0
  37. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.env.example +0 -0
  38. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/CODEOWNERS +0 -0
  39. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  40. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  41. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  42. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  43. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/dependabot.yml +0 -0
  44. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/workflows/auto-rebake.yml +0 -0
  45. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/workflows/bake-kernel-cache.yml +0 -0
  46. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/workflows/ci.yml +0 -0
  47. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/workflows/main-source-guard.yml +0 -0
  48. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/workflows/notify-tests-repo.yml +0 -0
  49. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/workflows/publish-dev.yml +0 -0
  50. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/workflows/publish-image.yml +0 -0
  51. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/workflows/publish.yml +0 -0
  52. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/workflows/version-parity.yml +0 -0
  53. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.github/workflows/worker-image.yml +0 -0
  54. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/.gitignore +0 -0
  55. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/CODE_OF_CONDUCT.md +0 -0
  56. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/CONTRIBUTING.md +0 -0
  57. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/Dockerfile +0 -0
  58. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/Dockerfile.worker +0 -0
  59. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/LICENSE +0 -0
  60. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/NOTICE +0 -0
  61. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/README.md +0 -0
  62. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/SECURITY.md +0 -0
  63. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/SELF_HOSTING.md +0 -0
  64. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/build/kernel_cache/.gitignore +0 -0
  65. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/build/kernel_cache/.keep +0 -0
  66. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/deploy/infisical/README.md +0 -0
  67. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/deploy/infisical/entrypoint.sh +0 -0
  68. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/docker/Dockerfile.kernelcache +0 -0
  69. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/docker/Dockerfile.kernelcache.relayer +0 -0
  70. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/docker/bake_kernel_cache.py +0 -0
  71. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/docker/bake_pod_entry.py +0 -0
  72. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/docker/extract_cudart_fix.py +0 -0
  73. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/docker/kernel_fingerprint.py +0 -0
  74. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/docker/make_rp_handler.py +0 -0
  75. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/__init__.py +0 -0
  76. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/_internal/__init__.py +0 -0
  77. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/_internal/channel.py +0 -0
  78. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/_internal/diagnostics.py +0 -0
  79. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/_internal/fileio.py +0 -0
  80. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/_internal/logging.py +0 -0
  81. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/_internal/paths.py +0 -0
  82. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/adapters/__init__.py +0 -0
  83. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/adapters/artifacts.py +0 -0
  84. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/adapters/fused_experts.py +0 -0
  85. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/adapters/lora_rank.py +0 -0
  86. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/__init__.py +0 -0
  87. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/__main__.py +0 -0
  88. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/__init__.py +0 -0
  89. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/deploy.py +0 -0
  90. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/__init__.py +0 -0
  91. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/episode.py +0 -0
  92. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/eval.py +0 -0
  93. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/eval_args.py +0 -0
  94. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/imports.py +0 -0
  95. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/list.py +0 -0
  96. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/push.py +0 -0
  97. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/retained.py +0 -0
  98. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/setup.py +0 -0
  99. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/test.py +0 -0
  100. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/test_evaluations.py +0 -0
  101. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/test_params.py +0 -0
  102. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/env/test_warnings.py +0 -0
  103. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/prompt_budget.py +0 -0
  104. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/traces.py +0 -0
  105. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/commands/train_cost.py +0 -0
  106. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/scaffold/TRAINING.md +0 -0
  107. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/scaffold/__init__.py +0 -0
  108. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/ui/__init__.py +0 -0
  109. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/ui/cost.py +0 -0
  110. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/ui/env_panels.py +0 -0
  111. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/ui/heartbeat.py +0 -0
  112. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/ui/render.py +0 -0
  113. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/ui/tables.py +0 -0
  114. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cli/ui/tty.py +0 -0
  115. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/client/__init__.py +0 -0
  116. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/client/config.py +0 -0
  117. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/client/freesolo_api.py +0 -0
  118. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/client/http.py +0 -0
  119. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/client/runtime_secrets.py +0 -0
  120. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/client/shapes.py +0 -0
  121. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/client/specs.py +0 -0
  122. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/client/streaming.py +0 -0
  123. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/content/__init__.py +0 -0
  124. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/content/structured_outputs.py +0 -0
  125. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/content/thinking.py +0 -0
  126. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/core/__init__.py +0 -0
  127. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/core/catalog.py +0 -0
  128. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cost/__init__.py +0 -0
  129. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cost/analytical.py +0 -0
  130. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cost/facts.py +0 -0
  131. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cost/spec.py +0 -0
  132. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/cost/types.py +0 -0
  133. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/__init__.py +0 -0
  134. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/plan/__init__.py +0 -0
  135. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/plan/kv_sizing.py +0 -0
  136. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/plan/model_config_probe.py +0 -0
  137. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/plan/prompt_budget.py +0 -0
  138. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/plan/recipe.py +0 -0
  139. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/plan/steps.py +0 -0
  140. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/plan/vram.py +0 -0
  141. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/profiling/__init__.py +0 -0
  142. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/profiling/dataset_profile.py +0 -0
  143. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/profiling/reasoning_render.py +0 -0
  144. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/profiling/sft_workload.py +0 -0
  145. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/profiling/tokenizer.py +0 -0
  146. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/profiling/workload_profile.py +0 -0
  147. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/result/__init__.py +0 -0
  148. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/result/accounting.py +0 -0
  149. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/result/rollout_samples.py +0 -0
  150. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/__init__.py +0 -0
  151. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/__main__.py +0 -0
  152. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/entry/__init__.py +0 -0
  153. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/entry/opd.py +0 -0
  154. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/entry/rl.py +0 -0
  155. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/entry/sft.py +0 -0
  156. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/io/__init__.py +0 -0
  157. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/io/heartbeat.py +0 -0
  158. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/io/hf.py +0 -0
  159. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/io/prefetch.py +0 -0
  160. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/io/wandb_log.py +0 -0
  161. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/model/__init__.py +0 -0
  162. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/model/adapter.py +0 -0
  163. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/model/chatml_mask.py +0 -0
  164. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/model/decoding.py +0 -0
  165. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/model/lora.py +0 -0
  166. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/model/packing.py +0 -0
  167. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/opd_train.py +0 -0
  168. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/opd_train_runner.py +0 -0
  169. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/perf/__init__.py +0 -0
  170. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/perf/diagnostics.py +0 -0
  171. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/perf/lifecycle.py +0 -0
  172. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/perf/liger.py +0 -0
  173. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/perf/memory.py +0 -0
  174. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/rl_train.py +0 -0
  175. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/rl_train_runner.py +0 -0
  176. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/runtime/__init__.py +0 -0
  177. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/runtime/kernel_warmup.py +0 -0
  178. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/runtime/pkg_proxy.py +0 -0
  179. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/runtime/rng.py +0 -0
  180. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/score_batcher.py +0 -0
  181. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/sft_train.py +0 -0
  182. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/sft_train_runner.py +0 -0
  183. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/teacher/__init__.py +0 -0
  184. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/teacher/client.py +0 -0
  185. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/teacher/encoding.py +0 -0
  186. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/teacher/tokenizer_align.py +0 -0
  187. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/__init__.py +0 -0
  188. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/core/__init__.py +0 -0
  189. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/core/checkpoint_lifecycle.py +0 -0
  190. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/core/child/__init__.py +0 -0
  191. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/core/child/runtime.py +0 -0
  192. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/core/step_timing.py +0 -0
  193. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/finalize.py +0 -0
  194. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/__init__.py +0 -0
  195. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/batching.py +0 -0
  196. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/bridge.py +0 -0
  197. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/child/__init__.py +0 -0
  198. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/child/bridge.py +0 -0
  199. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/child/entry.py +0 -0
  200. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/child/multiturn.py +0 -0
  201. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/child/plugin.py +0 -0
  202. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/child/replay_guard.py +0 -0
  203. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/child/runtime.py +0 -0
  204. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/child/structured.py +0 -0
  205. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/failures.py +0 -0
  206. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/gkd.py +0 -0
  207. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/multiturn_validation.py +0 -0
  208. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/prompts.py +0 -0
  209. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/reporting.py +0 -0
  210. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/scoring.py +0 -0
  211. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/state.py +0 -0
  212. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/opd/validation.py +0 -0
  213. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/__init__.py +0 -0
  214. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/checkpoints.py +0 -0
  215. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/child/__init__.py +0 -0
  216. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/child/entry.py +0 -0
  217. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/child/patches.py +0 -0
  218. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/child/plugin.py +0 -0
  219. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/config.py +0 -0
  220. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/inputs.py +0 -0
  221. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/reward_module.py +0 -0
  222. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/scoring.py +0 -0
  223. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/rl/single_turn.py +0 -0
  224. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/sft/__init__.py +0 -0
  225. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/sft/checkpoints.py +0 -0
  226. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/sft/child/entry.py +0 -0
  227. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/sft/child/plugin.py +0 -0
  228. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/train/sft/config.py +0 -0
  229. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/verl/__init__.py +0 -0
  230. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/verl/checkpoints.py +0 -0
  231. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/verl/child_io.py +0 -0
  232. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/verl/diagnostics.py +0 -0
  233. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/verl/parallelism.py +0 -0
  234. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker/verl/parent_work.py +0 -0
  235. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/engine/worker_entrypoint.py +0 -0
  236. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/__init__.py +0 -0
  237. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/base.py +0 -0
  238. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/cache_security.py +0 -0
  239. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/dataset_selection.py +0 -0
  240. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/evaluations.py +0 -0
  241. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/identity.py +0 -0
  242. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/loader.py +0 -0
  243. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/namespace_listing.py +0 -0
  244. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/package/__init__.py +0 -0
  245. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/package/limits.py +0 -0
  246. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/package/unpack.py +0 -0
  247. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/envs/pull.py +0 -0
  248. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/__init__.py +0 -0
  249. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/__init__.py +0 -0
  250. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/auth.py +0 -0
  251. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/bootstrap.py +0 -0
  252. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/bootstrap_console.py +0 -0
  253. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/bootstrap_pip.py +0 -0
  254. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/bootstrap_secrets.py +0 -0
  255. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/deadline.py +0 -0
  256. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/host/__init__.py +0 -0
  257. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/host/deadline_sleep.py +0 -0
  258. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/host/failmark.py +0 -0
  259. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/host/hostlog.py +0 -0
  260. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/http.py +0 -0
  261. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/instance.py +0 -0
  262. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/poll.py +0 -0
  263. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/poll_instance.py +0 -0
  264. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/provider.py +0 -0
  265. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/terminal_artifacts.py +0 -0
  266. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/_lifecycle/worker.py +0 -0
  267. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/allocator.py +0 -0
  268. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/artifacts/__init__.py +0 -0
  269. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/artifacts/hf.py +0 -0
  270. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/artifacts/preload_runpod.py +0 -0
  271. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/artifacts/weight_cache.py +0 -0
  272. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/base.py +0 -0
  273. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/fit_errors.py +0 -0
  274. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/lambda_/__init__.py +0 -0
  275. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/lambda_/api.py +0 -0
  276. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/lambda_/auth.py +0 -0
  277. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/lambda_/gpus.py +0 -0
  278. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/lambda_/jobs/__init__.py +0 -0
  279. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/lambda_/jobs/builders.py +0 -0
  280. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/lambda_/jobs/reap.py +0 -0
  281. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/lambda_/preflight.py +0 -0
  282. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/lambda_/pricing.py +0 -0
  283. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/preflight.py +0 -0
  284. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/realized.py +0 -0
  285. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/runpod/__init__.py +0 -0
  286. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/runpod/api.py +0 -0
  287. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/runpod/auth.py +0 -0
  288. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/runpod/cost.py +0 -0
  289. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/runpod/gpus.py +0 -0
  290. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/runpod/job_execution.py +0 -0
  291. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/runpod/jobs.py +0 -0
  292. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/runpod/preflight.py +0 -0
  293. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/runpod/pricing.py +0 -0
  294. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/runpod/resources.py +0 -0
  295. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/runpod/serverless/__init__.py +0 -0
  296. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/runpod/serverless/endpoints.py +0 -0
  297. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/sharding.py +0 -0
  298. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/vast/__init__.py +0 -0
  299. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/vast/api.py +0 -0
  300. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/vast/auth.py +0 -0
  301. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/vast/jobs/__init__.py +0 -0
  302. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/vast/jobs/builders.py +0 -0
  303. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/vast/preflight.py +0 -0
  304. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/providers/vast/pricing.py +0 -0
  305. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/py.typed +0 -0
  306. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/artifacts.py +0 -0
  307. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/attempts.py +0 -0
  308. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/costs.py +0 -0
  309. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/deadlines.py +0 -0
  310. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/reconciliation.py +0 -0
  311. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/results/__init__.py +0 -0
  312. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/results/checkpoints.py +0 -0
  313. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/results/verified_revisions.py +0 -0
  314. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/supervise/__init__.py +0 -0
  315. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/supervise/attach.py +0 -0
  316. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/supervise/deploy.py +0 -0
  317. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/supervise/lifecycle.py +0 -0
  318. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/supervise/recovery.py +0 -0
  319. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/supervise/retry_decision.py +0 -0
  320. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/supervise/seed_submission.py +0 -0
  321. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/supervise/transitions.py +0 -0
  322. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runner/weight_cache.py +0 -0
  323. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runtime_capsule/__init__.py +0 -0
  324. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runtime_capsule/build.py +0 -0
  325. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runtime_capsule/manifest.py +0 -0
  326. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/runtime_capsule/profiles.py +0 -0
  327. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/schema/fields.py +0 -0
  328. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/serve/__init__.py +0 -0
  329. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/serve/adapter_check.py +0 -0
  330. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/serve/deploy.py +0 -0
  331. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/serve/errors.py +0 -0
  332. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/serve/export.py +0 -0
  333. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/serve/preflight.py +0 -0
  334. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/serve/responses.py +0 -0
  335. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/serve/streaming.py +0 -0
  336. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/serve/thinking.py +0 -0
  337. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/serve/urls.py +0 -0
  338. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/__init__.py +0 -0
  339. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/__main__.py +0 -0
  340. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/app.py +0 -0
  341. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/billing/__init__.py +0 -0
  342. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/billing/charges.py +0 -0
  343. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/billing/retry.py +0 -0
  344. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/domain/__init__.py +0 -0
  345. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/domain/checkpoints.py +0 -0
  346. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/domain/environment_registry.py +0 -0
  347. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/domain/envs.py +0 -0
  348. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/domain/projects.py +0 -0
  349. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/domain/reconcile.py +0 -0
  350. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/domain/repo_cleanup.py +0 -0
  351. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/domain/run_registry.py +0 -0
  352. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/domain/teacher_broker.py +0 -0
  353. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/domain/teacher_errors.py +0 -0
  354. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/domain/teacher_requests.py +0 -0
  355. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/platform/__init__.py +0 -0
  356. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/platform/auth.py +0 -0
  357. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/platform/db.py +0 -0
  358. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/platform/deps.py +0 -0
  359. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/platform/internal_client.py +0 -0
  360. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/platform/locks.py +0 -0
  361. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/platform/runtime.py +0 -0
  362. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/routes/__init__.py +0 -0
  363. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/routes/envs.py +0 -0
  364. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/routes/meta.py +0 -0
  365. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/routes/runs.py +0 -0
  366. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/routes/serving.py +0 -0
  367. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/routes/serving_completion.py +0 -0
  368. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/routes/serving_revisions.py +0 -0
  369. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/routes/serving_smoke.py +0 -0
  370. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/server/routes/teacher.py +0 -0
  371. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/teacher/__init__.py +0 -0
  372. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/teacher/limits.py +0 -0
  373. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/flash/teacher/retry_contract.py +0 -0
  374. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/scripts/build_dev_dist.py +0 -0
  375. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/scripts/check_file_size.py +0 -0
  376. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/scripts/check_function_size.py +0 -0
  377. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/scripts/check_verl_pin_exists.py +0 -0
  378. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/scripts/scrub_history.sh +0 -0
  379. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/__init__.py +0 -0
  380. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/_helpers/__init__.py +0 -0
  381. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/_helpers/profile.py +0 -0
  382. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/_helpers/runner.py +0 -0
  383. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/_helpers/specs.py +0 -0
  384. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/_helpers/teacher.py +0 -0
  385. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/_helpers/vast.py +0 -0
  386. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/conftest.py +0 -0
  387. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/fixtures/math_eval.jsonl +0 -0
  388. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/fixtures/math_train.jsonl +0 -0
  389. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/live/__init__.py +0 -0
  390. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/live/conftest.py +0 -0
  391. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/live/test_lambda_live.py +0 -0
  392. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/live/test_runpod_live.py +0 -0
  393. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/live/test_sft_thinking_render_live.py +0 -0
  394. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/live/test_vast_live.py +0 -0
  395. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_accounting_coverage.py +0 -0
  396. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_adapter_shard_completeness.py +0 -0
  397. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_agent_flash_cli_contract.py +0 -0
  398. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_algorithms.py +0 -0
  399. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_allocator.py +0 -0
  400. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_backend_common.py +0 -0
  401. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_backend_jobspec_contract.py +0 -0
  402. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_bake_kernel_cache.py +0 -0
  403. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_base_model_provenance.py +0 -0
  404. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_billing_retry.py +0 -0
  405. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_build_context_contract.py +0 -0
  406. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cancel_remote.py +0 -0
  407. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_catalog_consistency.py +0 -0
  408. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_checkpoint_lifecycle.py +0 -0
  409. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_checkpoints.py +0 -0
  410. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_commands.py +0 -0
  411. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_commands_coverage.py +0 -0
  412. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_credential_shadowing.py +0 -0
  413. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_errors.py +0 -0
  414. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_estimate.py +0 -0
  415. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_gpus_flag.py +0 -0
  416. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_help.py +0 -0
  417. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_main_coverage.py +0 -0
  418. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_managed.py +0 -0
  419. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_render_coverage.py +0 -0
  420. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_render_theme.py +0 -0
  421. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_traces.py +0 -0
  422. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cli_wandb_warning.py +0 -0
  423. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_client.py +0 -0
  424. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_client_import_purity.py +0 -0
  425. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_client_server_integration.py +0 -0
  426. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_client_stream_reads.py +0 -0
  427. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_config_env_vars.py +0 -0
  428. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_config_overrides.py +0 -0
  429. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_console_upload.py +0 -0
  430. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_controlled_experiment_repairs.py +0 -0
  431. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cost_analytical.py +0 -0
  432. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cost_equation.py +0 -0
  433. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cost_estimate.py +0 -0
  434. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_cost_models.py +0 -0
  435. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_dataset_profile.py +0 -0
  436. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_deploy_alias_move_warning.py +0 -0
  437. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_deploy_latency.py +0 -0
  438. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_dev_channel.py +0 -0
  439. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_disk_gb.py +0 -0
  440. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_endpoint_name.py +0 -0
  441. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_cache_evict.py +0 -0
  442. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_delete.py +0 -0
  443. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_download.py +0 -0
  444. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_download_api.py +0 -0
  445. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_evaluations.py +0 -0
  446. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_list_api.py +0 -0
  447. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_list_cli.py +0 -0
  448. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_list_hub.py +0 -0
  449. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_no_install.py +0 -0
  450. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_publish.py +0 -0
  451. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_pull.py +0 -0
  452. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_pull_coverage.py +0 -0
  453. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_pull_loader_coverage.py +0 -0
  454. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_pull_managed_control_plane.py +0 -0
  455. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_push.py +0 -0
  456. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_rate_limit_resolve.py +0 -0
  457. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_ref_pinning.py +0 -0
  458. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_env_test.py +0 -0
  459. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_envs_coverage.py +0 -0
  460. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_export.py +0 -0
  461. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_flash_mvp.py +0 -0
  462. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_flash_worker.py +0 -0
  463. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_flashinfer_cache_dirs.py +0 -0
  464. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_freesolo_api_transport.py +0 -0
  465. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_fused_expert_warmstart.py +0 -0
  466. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_github_urlopen_retry.py +0 -0
  467. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_gpu_type_single_field.py +0 -0
  468. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_gpus.py +0 -0
  469. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_grpo_params.py +0 -0
  470. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_grpo_resident_sizing.py +0 -0
  471. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_grpo_reward_batching.py +0 -0
  472. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_health_liveness.py +0 -0
  473. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_hf_retry.py +0 -0
  474. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_idle_endpoint_reaper.py +0 -0
  475. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_infisical_secrets.py +0 -0
  476. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_instance_bootstrap_coverage.py +0 -0
  477. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_internal_client.py +0 -0
  478. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_jobs.py +0 -0
  479. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_kernel_cache.py +0 -0
  480. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_kernel_fingerprint.py +0 -0
  481. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_kv_util.py +0 -0
  482. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_lambda_api_coverage.py +0 -0
  483. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_lambda_runner.py +0 -0
  484. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_logging.py +0 -0
  485. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_login_perms.py +0 -0
  486. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_lora_rank_coverage.py +0 -0
  487. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_lora_rank_preflight.py +0 -0
  488. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_managed_hf_repo.py +0 -0
  489. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_metrics_schema_agent_contract.py +0 -0
  490. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_mig_guard.py +0 -0
  491. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_multi_gpu_gate.py +0 -0
  492. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_multimodal_training.py +0 -0
  493. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_named_reward_metrics.py +0 -0
  494. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_oom_escalate_gpu.py +0 -0
  495. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_opd.py +0 -0
  496. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_opd_limits.py +0 -0
  497. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_opd_multiturn_eos_boundary.py +0 -0
  498. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_opd_multiturn_failure_exit.py +0 -0
  499. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_opd_replay_guard.py +0 -0
  500. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_opd_resume_safety.py +0 -0
  501. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_orchestrator_flash.py +0 -0
  502. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_packing.py +0 -0
  503. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_packing_coverage.py +0 -0
  504. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_parasail_teacher.py +0 -0
  505. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_poll_helpers.py +0 -0
  506. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_preflight.py +0 -0
  507. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_projects.py +0 -0
  508. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_prompt_budget.py +0 -0
  509. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_provider_preflight_coverage.py +0 -0
  510. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_provider_routing.py +0 -0
  511. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_provider_teardown_robustness.py +0 -0
  512. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_providers_symmetry.py +0 -0
  513. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_realized_cost.py +0 -0
  514. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_repo_cleanup.py +0 -0
  515. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_resolve_params_b.py +0 -0
  516. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_resume_on_retry.py +0 -0
  517. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_rollout_samples.py +0 -0
  518. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_runmgmt.py +0 -0
  519. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_runpod_api_delete.py +0 -0
  520. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_runpod_key_fingerprint.py +0 -0
  521. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_runpod_key_waterfall.py +0 -0
  522. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_runtime_capsule.py +0 -0
  523. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_serve.py +0 -0
  524. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_serve_reasoning_content.py +0 -0
  525. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_server_app_coverage.py +0 -0
  526. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_server_auth_singleflight.py +0 -0
  527. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_server_checkpoints_coverage.py +0 -0
  528. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_server_db.py +0 -0
  529. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_server_envs_coverage.py +0 -0
  530. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_server_locks_coverage.py +0 -0
  531. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_server_standalone.py +0 -0
  532. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_serving_context_preflight.py +0 -0
  533. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_serving_contract.py +0 -0
  534. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_serving_schema_coverage.py +0 -0
  535. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_sft_chunked_nll.py +0 -0
  536. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_sft_example_selection.py +0 -0
  537. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_sft_gc_off.py +0 -0
  538. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_sft_max_context.py +0 -0
  539. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_sft_startup_block.py +0 -0
  540. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_sft_train.py +0 -0
  541. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_sft_workload.py +0 -0
  542. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_step_floor.py +0 -0
  543. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_step_metrics.py +0 -0
  544. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_step_timing.py +0 -0
  545. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_structured_outputs.py +0 -0
  546. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_teacher_broker.py +0 -0
  547. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_teacher_encoding_contract.py +0 -0
  548. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_terminal_artifacts.py +0 -0
  549. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_thinking_config.py +0 -0
  550. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_train_context_preflight.py +0 -0
  551. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_training_controls.py +0 -0
  552. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_type_comment_prose.py +0 -0
  553. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_vast_api.py +0 -0
  554. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_vast_api_coverage.py +0 -0
  555. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_vast_offers.py +0 -0
  556. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_vast_provider_coverage.py +0 -0
  557. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_vast_runner.py +0 -0
  558. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_verified_revisions.py +0 -0
  559. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_verl_checkpoint_export.py +0 -0
  560. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_verl_child_plugins.py +0 -0
  561. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_verl_silence_watchdog.py +0 -0
  562. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_version.py +0 -0
  563. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_vl_warmstart_adapter_keys.py +0 -0
  564. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_vram_architecture.py +0 -0
  565. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_wandb_link.py +0 -0
  566. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_wandb_naming.py +0 -0
  567. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_warmstart_adapter_download.py +0 -0
  568. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_warmstart_cross_repo.py +0 -0
  569. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_warmstart_error_attribution.py +0 -0
  570. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_weight_cache.py +0 -0
  571. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_worker_hardexit.py +0 -0
  572. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_worker_image.py +0 -0
  573. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_worker_init_heartbeat.py +0 -0
  574. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_worker_stack.py +0 -0
  575. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_worker_thinking.py +0 -0
  576. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_workflow_contracts.py +0 -0
  577. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_workload_profile.py +0 -0
  578. {freesolo_flash_dev-1.2.59 → freesolo_flash_dev-1.2.61}/tests/test_zero2_sharding_gate.py +0 -0
@@ -21,6 +21,10 @@ This file starts at 1.1.35. Earlier releases are not reconstructed here; use
21
21
 
22
22
  ### Changed
23
23
 
24
+ - Multi-turn GRPO now clones each sibling rollout from the task state that produced its prepared
25
+ prompt. Environments that record randomized episode choices on the task during `start_episode`
26
+ are stepped and scored against the same episode the model saw, without sharing mutable state
27
+ between sibling rollouts.
24
28
  - A RunPod attempt's stall window is now measured from evidence timestamps rather than from when
25
29
  the control plane happened to look at it. The window was seeded from the moment polling started
26
30
  and was reset again by the first status read, and a heartbeat was credited at the time it was
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: freesolo-flash-dev
3
- Version: 1.2.59
3
+ Version: 1.2.61
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
@@ -250,13 +250,22 @@ def record_has_images(record: dict, messages: list[dict] | None = None) -> bool:
250
250
  return True
251
251
  for message in messages or []:
252
252
  content = message.get("content") if isinstance(message, dict) else None
253
- if isinstance(content, list) and any(
254
- isinstance(block, dict) and block.get("type") in _IMAGE_BLOCK_TYPES for block in content
255
- ):
253
+ if content_has_images(content):
256
254
  return True
257
255
  return False
258
256
 
259
257
 
258
+ def content_has_images(content: object) -> bool:
259
+ """Whether one message's ``content`` carries an image block.
260
+
261
+ The single definition of "this message shows the model an image", so a path that cannot carry
262
+ media (the multi-turn GRPO bridge) recognises exactly what the paths that can do.
263
+ """
264
+ return isinstance(content, list) and any(
265
+ isinstance(block, dict) and block.get("type") in _IMAGE_BLOCK_TYPES for block in content
266
+ )
267
+
268
+
260
269
  def text_only_prompt_messages(messages: list[dict]) -> list[dict]:
261
270
  """Drop image content blocks while preserving the teacher's message order and text."""
262
271
  stripped: list[dict] = []
@@ -28,6 +28,10 @@ from uuid import UUID
28
28
  from flash._internal.diagnostics import SECRET_ENV_KEYS_ENV
29
29
  from flash.core.catalog import DEFAULT_MODEL, normalize_algorithm
30
30
  from flash.core.spec_persistence import (
31
+ DROPPED_TOP_LEVEL_KEYS,
32
+ REMOVED_PERSISTED_TRAIN_KEYS,
33
+ announce_dropped_keys,
34
+ migrated_optimizer_batch,
31
35
  opt_float,
32
36
  opt_int,
33
37
  str_tuple,
@@ -453,6 +457,58 @@ MANAGED_GPU_KEYS = frozenset(
453
457
  {"disk_gb", "network_volume", "network_volume_gb", "max_retries", "max_wall_seconds"}
454
458
  )
455
459
 
460
+ # the other two halves of the same boundary. together with the managed gpu registry they name every field
461
+ # that separates the worker contract from the public one -- which is the whole difference between
462
+ # them, and is why `to_dict` can be a projection of `to_internal_dict` rather than a second
463
+ # serializer. they were bare `data.pop(...)` calls, so the boundary existed only as a sequence of
464
+ # statements: nothing could enumerate it, and a field added to one serializer but not the other was
465
+ # invisible until a submit round trip or a recovery digest failed.
466
+ #
467
+ # order is irrelevant (the payload is canonicalized with sort_keys), but presence is a recovery
468
+ # contract: `_preparation_digest` hashes the public payload, so moving a name in or out of this set
469
+ # invalidates the stored digest of every warm-start and workload-profile run in flight.
470
+ #
471
+ # not reused by `_validate_effective_spec`, which keeps its own near-identical list. the difference
472
+ # is one name -- `model_revision` -- and it is deliberate there: the validator excludes it only
473
+ # conditionally, so a historical authored pin stays structurally compared between the two halves.
474
+ # substituting this set would widen that exclusion to every run and drop a real integrity check.
475
+ MANAGED_TOP_LEVEL_KEYS = frozenset(
476
+ {
477
+ # server-assigned identity -- never authored in a config.
478
+ "run_id",
479
+ # runner-managed, and no longer part of the public config or status spec. internal round
480
+ # trips keep the value and marker through to_internal_dict(). historical public specs that
481
+ # emitted these are replayed only while verifying a stored preparation digest, from the
482
+ # exact persisted bytes.
483
+ "model_revision",
484
+ "model_revision_auto",
485
+ # the provenance marker only. gpu.count=1 stays in the public [gpu] object for digest
486
+ # stability; internal round trips carry the marker verbatim.
487
+ "gpu_count_auto",
488
+ "workload_profile",
489
+ "workload_profile_input_digest",
490
+ "workload_profile_producer_version",
491
+ }
492
+ )
493
+
494
+ # platform-managed [train] fields: the control-plane-assigned artifact repo and the resolve-once
495
+ # revision pin of a warm-start source.
496
+ MANAGED_TRAIN_KEYS = frozenset({"hf_repo", "init_from_adapter_revision"})
497
+
498
+ # platform-managed [environment] field: the env ref is resolved once and pinned by the control plane.
499
+ # `pip` deliberately stays public -- it is the author's own scorer dependencies, which only they can
500
+ # declare.
501
+ MANAGED_ENVIRONMENT_KEYS = frozenset({"resolved_sha"})
502
+
503
+ # every managed section, so the public/worker boundary can be walked rather than restated. the two
504
+ # things not here are the ones that are not removals: `train.lora_rank`/`lora_alpha` are stripped
505
+ # only for a warm start, and `gpu.type_fallbacks` is respelled into `gpu.type` rather than dropped.
506
+ MANAGED_SECTION_KEYS = (
507
+ ("train", MANAGED_TRAIN_KEYS),
508
+ ("gpu", MANAGED_GPU_KEYS),
509
+ ("environment", MANAGED_ENVIRONMENT_KEYS),
510
+ )
511
+
456
512
 
457
513
  @dataclass(frozen=True)
458
514
  class WandbSpec:
@@ -555,52 +611,44 @@ class JobSpec:
555
611
  parser would reject, so the result re-validates through ``flash.schema.spec_from_dict``. Do
556
612
  not hand its output to a worker or provider path -- those need ``to_internal_dict()``.
557
613
 
614
+ Built as a PROJECTION of the worker payload, because that is the actual relationship: the
615
+ public contract is the worker contract minus the platform-managed fields, which
616
+ MANAGED_TOP_LEVEL_KEYS and MANAGED_SECTION_KEYS name. This is still a blacklist -- a newly
617
+ added field is public until something strips it, exactly as before -- but the strips are now
618
+ enumerable rather than a run of statements, so a test can assert the boundary instead of
619
+ trusting that two independent `asdict(self)` bodies were kept in sync by hand. What the
620
+ registries deliberately do NOT cover is the two adjustments below that are not removals.
621
+
558
622
  Its bytes are a recovery contract. ``_preparation_digest`` hashes this output as canonical
559
623
  JSON, so key PRESENCE is load-bearing even though key order is not: adding or dropping one
560
624
  key here invalidates the stored digest of every warm-start and workload-profile run in
561
625
  flight, which fails integrity validation on recovery.
562
626
  """
563
- data = asdict(self)
564
- # server-assigned identity — never authored in a config.
565
- data.pop("run_id", None)
566
- # model_revision is runner-managed and no longer part of the public config or status spec.
567
- # Internal round trips keep the value and marker through to_internal_dict(). Historical public
568
- # specs that emitted this key are replayed only while verifying their stored preparation
569
- # digest, using the exact value from the persisted bytes.
570
- data.pop("model_revision", None)
571
- data.pop("model_revision_auto", None)
572
- # keep gpu.count=1 in the public gpu object for preparation-digest stability. only the
573
- # platform-managed provenance marker is stripped; internal round trips carry it verbatim.
574
- data.pop("gpu_count_auto", None)
575
- data.pop("workload_profile_input_digest", None)
576
- data.pop("workload_profile_producer_version", None)
577
- data.pop("workload_profile", None)
627
+ data = self.to_internal_dict()
628
+ for managed in MANAGED_TOP_LEVEL_KEYS:
629
+ data.pop(managed, None)
630
+ for section, managed_keys in MANAGED_SECTION_KEYS:
631
+ for managed in managed_keys:
632
+ data[section].pop(managed, None)
578
633
  train = data["train"]
579
- train.pop("init_from_adapter_revision", None)
580
- train.pop("hf_repo", None) # control-plane-assigned artifact repo
581
634
  if train.get("init_from_adapter"):
582
635
  # the source adapter's topology is authoritative for a warm start, so the parser rejects
583
636
  # both keys alongside init_from_adapter. the runner writes the inherited rank/alpha onto
584
637
  # the public spec, so they must be stripped here or the submit round trip re-validates
585
- # a combination the parser refuses.
638
+ # a combination the parser refuses. conditional, so it cannot be a registry entry.
586
639
  train.pop("lora_rank", None)
587
640
  train.pop("lora_alpha", None)
588
- # runner-assigned disk sizing, shared weight-cache volume, and retry/wall-clock lifecycle.
641
+ # restore the public list spelling for an ordered pin -- a reshape rather than a removal,
642
+ # which is the other thing no registry can express. the default stands in for the key the
643
+ # worker payload omits when there are no fallbacks: unlike `providers`, this one is read
644
+ # back, so it cannot rely on the omission alone.
589
645
  gpu = data["gpu"]
590
- for managed in MANAGED_GPU_KEYS:
591
- gpu.pop(managed, None)
592
- # restore the public list spelling for an ordered pin.
593
646
  fallbacks = gpu.pop("type_fallbacks", ())
594
647
  if fallbacks:
595
648
  gpu["type"] = [gpu["type"], *fallbacks]
596
- # omit the unset preference so an internal default does not become an authored empty list on
597
- # the public round trip, where an explicit empty list is rejected as a likely configuration bug.
598
- if not gpu.get("providers"):
599
- gpu.pop("providers", None)
600
- data["environment"].pop("resolved_sha", None) # resolve-once env ref pin
601
- # [environment] pip stays in the payload: it is the author's own scorer dependencies, which
602
- # only they can declare. The submit paths append it to worker_pip_for_env, so what travels
603
- # here is the extra requirements, not the worker's own.
649
+ # an empty `providers` needs no strip: the worker payload this projects from already omits
650
+ # it, for the same reason the public contract wants it gone -- an internal default must not
651
+ # read back as an authored empty list, which the parser rejects as a likely config bug.
604
652
  return data
605
653
 
606
654
  def to_internal_dict(self) -> dict[str, Any]:
@@ -642,9 +690,10 @@ class JobSpec:
642
690
  if not isinstance(data, dict):
643
691
  raise TypeError("job spec must be an object")
644
692
  allowed_top_level = {item.name for item in fields(cls)}
645
- unknown_top_level = sorted(set(data) - allowed_top_level)
693
+ unknown_top_level = sorted(set(data) - allowed_top_level - DROPPED_TOP_LEVEL_KEYS)
646
694
  if unknown_top_level:
647
695
  raise ValueError(f"job spec has unknown key(s): {', '.join(unknown_top_level)}")
696
+ announce_dropped_keys(data)
648
697
  env = data.get("environment") or {}
649
698
  # Reject stale payloads carrying a local `path`; worker only runs published env ids.
650
699
  if isinstance(env, dict) and env.get("path"):
@@ -652,7 +701,12 @@ class JobSpec:
652
701
  "local environment paths are no longer supported; the worker only runs "
653
702
  "published Freesolo environment ids"
654
703
  )
655
- train = validated_section(data, "train", {item.name for item in fields(TrainSpec)})
704
+ train = validated_section(
705
+ data,
706
+ "train",
707
+ {item.name for item in fields(TrainSpec)},
708
+ removed=REMOVED_PERSISTED_TRAIN_KEYS,
709
+ )
656
710
  gpu = validated_section(data, "gpu", {item.name for item in fields(GpuSpec)})
657
711
  gpu_type, gpu_type_fallbacks = _parse_persisted_gpu_types(gpu)
658
712
  provider, providers = validated_persisted_providers(gpu, gpu_type, gpu_type_fallbacks)
@@ -661,8 +715,9 @@ class JobSpec:
661
715
  raise TypeError("project must be a string")
662
716
  project = require_project_id(project_raw) if project_raw.strip() else ""
663
717
  algorithm = normalize_algorithm(data.get("algorithm", cls.algorithm))
664
- batch_size = opt_int(train.get("batch_size"))
665
- prompts_per_step = opt_int(train.get("prompts_per_step"))
718
+ # one reading of the optimizer batch for both keys: the rollout spelling changed in 1.1.43
719
+ # and a persisted spec can still carry the old one.
720
+ batch_size, prompts_per_step = migrated_optimizer_batch(train, algorithm)
666
721
  return cls(
667
722
  model=data.get("model", cls.model),
668
723
  model_revision=_model_revision(data.get("model_revision", cls.model_revision)),
@@ -0,0 +1,414 @@
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 is TOLERANT by necessity. the record is
10
+ immutable history: it was written by an older Flash, it is never rewritten, and a run that is
11
+ still training depends on it decoding. rejecting it strands the run.
12
+
13
+ So the coercions here are deliberately looser than anything the authored parser would accept, and
14
+ the migrations exist to keep specific historical spellings readable. Neither belongs on the
15
+ submission path.
16
+
17
+ Serialized-byte warning: `flash/runner/preparation.py::_preparation_digest` sha256-hashes the
18
+ canonical JSON of `to_dict()` and `to_internal_dict()` output. Key ORDER is safe there
19
+ (`sort_keys=True`), but key PRESENCE is not -- adding, dropping, or renaming a key in a decode path
20
+ changes the digest and fails integrity validation for every warm-start and workload-profile run in
21
+ flight. Change decoding here only with the corpus gate green.
22
+
23
+ These functions take plain dicts and return plain dicts and scalars. That is the rule that keeps the
24
+ module importable by `spec.py` rather than the other way round, and it is why `validated_section`
25
+ takes its allowed-key set as an argument instead of reading `fields(TrainSpec)` itself.
26
+
27
+ What is deliberately NOT here: `_coerce_wandb` and `_parse_persisted_gpu_types` are also called only
28
+ from `JobSpec.from_dict`, so they belong to this contract by usage -- but they construct `WandbSpec`
29
+ and reach `_validated_gpu_type`, which `__post_init__` needs too. Moving them would make this module
30
+ import the dataclasses that import it. The boundary is therefore "persisted-record logic that does
31
+ not depend on the spec types themselves"; `VersionedPersistedSpecEnvelope` follows that rule too.
32
+ """
33
+
34
+ from __future__ import annotations
35
+
36
+ import logging
37
+ from collections.abc import Mapping
38
+ from dataclasses import dataclass, field
39
+ from typing import Any, ClassVar
40
+
41
+ from flash.core.catalog import normalize_algorithm, samples_on_policy
42
+
43
+ # removed public top-level fields that a persisted record can still carry. stored run records are
44
+ # never rewritten, and effective_preparation.worker_spec is written with to_internal_dict() (asdict),
45
+ # which emitted every field including the defaulted ones -- so every record written before a field
46
+ # was dropped still names it. this registry also drives historical public-digest replay for
47
+ # model_revision, which remains an internal field. without it a still-running job can lose its
48
+ # recovery, deploy, and serving paths after the upgrade.
49
+ #
50
+ # ignored on read only. most keys here no longer exist as jobspec fields; model_revision remains an
51
+ # internal runner field, but the public schema rejects it and to_dict omits it. keeping it in this set
52
+ # lets digest recovery identify the historical public key without weakening jobspec.from_dict.
53
+ DROPPED_TOP_LEVEL_KEYS = frozenset(
54
+ {"model_policy", "model_revision", "worker_env", "workload_profile_kind"}
55
+ )
56
+
57
+ # tolerating a dropped key keeps a pre-upgrade run's recovery path, but the values behind it stop
58
+ # being applied -- so a run that authored them now trains on managed defaults instead of what was
59
+ # submitted. that is announced rather than silent. only user-authorable keys qualify: model_policy
60
+ # was platform-managed (to_dict popped it), so its loss cannot change what a submitted config asked
61
+ # for. the values are deliberately not forwarded -- doing so would reinstate the override table this
62
+ # removal exists to close, and would deliver it without the validation the deleted parser performed.
63
+ _ANNOUNCED_DROPPED_KEYS = frozenset({"worker_env"})
64
+
65
+ # removed [train] keys a persisted record can still carry. deliberately narrow: a key is listed only
66
+ # once its behavior is gone, so an unlisted unknown key stays fatal rather than silently ignored.
67
+ REMOVED_PERSISTED_TRAIN_KEYS = frozenset({"advantage_clip"})
68
+
69
+
70
+ def announce_dropped_keys(data: dict[str, Any]) -> None:
71
+ """Log the removed user-authored keys a persisted record still carries and no longer applies.
72
+
73
+ Only announced when the payload names the run. A public spec is ``to_dict()`` output, which pops
74
+ the server-assigned run_id, and the same stored run is read through both shapes -- so warning
75
+ without an id would emit an unactionable "run <unknown>" line and duplicate the identified one
76
+ the worker-spec read already produced. Every provisioned run records an internal worker spec
77
+ (asdict, run_id included), and that is the read this fires on.
78
+ """
79
+ run_id = str(data.get("run_id") or "").strip()
80
+ if not run_id:
81
+ return
82
+ for key in sorted(_ANNOUNCED_DROPPED_KEYS):
83
+ value = data.get(key)
84
+ if not value:
85
+ continue
86
+ names = ", ".join(sorted(str(k) for k in value)) if isinstance(value, dict) else str(value)
87
+ logging.getLogger("flash.spec").warning(
88
+ "run %s was submitted with [%s] (%s); that table was removed and its values are NOT "
89
+ "applied -- this run uses managed defaults instead. resubmit without it if the run "
90
+ "depends on those values.",
91
+ run_id,
92
+ key,
93
+ names,
94
+ )
95
+
96
+
97
+ def validated_section(
98
+ data: dict[str, Any],
99
+ name: str,
100
+ allowed: set[str],
101
+ *,
102
+ removed: frozenset[str] = frozenset(),
103
+ ) -> dict[str, Any]:
104
+ """Read one nested block (``[train]``, ``[gpu]``) of a persisted record, rejecting unknown keys.
105
+
106
+ A missing block and an explicit null are the same state -- both mean "authored nothing" -- so both
107
+ normalize to empty rather than one of them raising. ``removed`` names keys whose behavior is gone:
108
+ they are dropped silently, because the record is immutable history and cannot be rewritten. An
109
+ unlisted unknown key stays fatal, which is what keeps the tolerance narrow instead of turning
110
+ every typo in a stored record into a silent default.
111
+ """
112
+ section = data.get(name)
113
+ if section is None:
114
+ section = {}
115
+ if not isinstance(section, dict):
116
+ raise TypeError(f"{name} must be an object")
117
+ section = {key: value for key, value in section.items() if key not in removed}
118
+ unknown = sorted(set(section) - allowed)
119
+ if unknown:
120
+ raise ValueError(f"{name} has unknown key(s): {', '.join(unknown)}")
121
+ return section
122
+
123
+
124
+ def validated_persisted_providers(
125
+ gpu: dict[str, Any], gpu_type: str, gpu_type_fallbacks: tuple[str, ...]
126
+ ) -> tuple[str, tuple[str, ...]]:
127
+ """``(provider, providers)`` from a persisted ``[gpu]`` block, cross-checked against its classes.
128
+
129
+ ``GpuSpec.__post_init__`` runs the same both-set check but cannot replace this one: ``allow_empty``
130
+ here keys off whether the record CARRIED a ``providers`` key, and that presence is exactly what the
131
+ dataclass has already lost by the time it validates. An explicitly empty preference and an absent
132
+ one are different states in a stored record.
133
+ """
134
+ from flash.providers import PROVIDER_NAMES, validated_provider_preferences
135
+
136
+ provider = gpu.get("provider", "")
137
+ if not isinstance(provider, str):
138
+ raise TypeError("gpu.provider must be a string")
139
+ provider = provider.strip().lower()
140
+ providers = validated_provider_preferences(
141
+ gpu.get("providers", ()), allow_empty="providers" not in gpu
142
+ )
143
+ if provider and providers:
144
+ raise ValueError("gpu.provider and gpu.providers cannot both be set")
145
+ if provider or providers or gpu_type:
146
+ from flash.providers.base import providers_for
147
+
148
+ if provider and provider not in PROVIDER_NAMES:
149
+ raise ValueError(f"unknown gpu.provider {provider!r}")
150
+ # a hard provider pin must carry every acceptable class. provider preferences stay soft: an
151
+ # ineligible named provider contributes no candidate, while eligible named or unnamed
152
+ # configured providers remain available for failover.
153
+ for candidate in (gpu_type, *gpu_type_fallbacks):
154
+ if candidate and provider and provider not in providers_for(candidate):
155
+ raise ValueError(
156
+ f"gpu.provider {provider!r} cannot provision gpu.type {candidate!r}"
157
+ )
158
+ return provider, providers
159
+
160
+
161
+ def str_tuple(value: Any) -> tuple[str, ...]:
162
+ """Normalize a string-or-list knob to a tuple of strings; a bare string is one element, not iterated."""
163
+ if value is None:
164
+ return ()
165
+ if isinstance(value, str):
166
+ return (value,) if value else ()
167
+ return tuple(s for s in (str(x) for x in value) if s)
168
+
169
+
170
+ def volume_gb(value: Any, default: int = 100) -> int:
171
+ """Parse volume size in GB; non-positive / non-numeric / missing values return default."""
172
+ if isinstance(value, bool):
173
+ # bool is an int subclass; reject to avoid int(True)==1 becoming a 1 GB volume.
174
+ return default
175
+ try:
176
+ gb = int(value)
177
+ except (TypeError, ValueError):
178
+ return default
179
+ return gb if gb > 0 else default
180
+
181
+
182
+ def opt_int(value: Any) -> int | None:
183
+ """Parse optional int; rejects bools (bool is int subclass — int(True)==1 is a footgun)."""
184
+ if value is None:
185
+ return None
186
+ if isinstance(value, bool):
187
+ raise TypeError(f"expected a number, got bool {value!r}")
188
+ return int(value)
189
+
190
+
191
+ def opt_float(value: Any) -> float | None:
192
+ """Parse optional float; rejects bools (mirrors ``opt_int``)."""
193
+ if value is None:
194
+ return None
195
+ if isinstance(value, bool):
196
+ raise TypeError(f"expected a number, got bool {value!r}")
197
+ return float(value)
198
+
199
+
200
+ def migrated_optimizer_batch(train: dict, algorithm: str) -> tuple[int | None, int | None]:
201
+ """``(batch_size, prompts_per_step)`` with the pre-1.1.43 rollout spelling migrated.
202
+
203
+ grpo/opd authored the optimizer batch as ``batch_size`` until it was split into
204
+ ``prompts_per_step``. The schema rejects the old name on SUBMISSION, but `from_dict` also
205
+ reparses PERSISTED specs, and the deployed release (1.1.40) has no ``prompts_per_step`` at all
206
+ -- so every rollout run in flight across this upgrade carries only the old key. The workers read
207
+ ``prompts_per_step`` alone, so without this a recovered run silently resumes on the recipe
208
+ default: 64 instead of an authored 32 on grpo, which OOMs a card rented for 32, and 8 on opd.
209
+
210
+ The old key is MOVED, not copied, and is dropped whenever the new one is present. Leaving it
211
+ populated would re-emit both names from ``to_dict()``, and a spec carrying both is rejected by
212
+ the schema -- breaking the resubmit that recovery and ``flash runs get`` perform, and leaving
213
+ `vram.py::_optimizer_batch_value` (which takes the larger of the two) free to size a card off
214
+ the stale value that ranking ignores. That applies to a payload written mid-upgrade carrying
215
+ BOTH spellings too: ``prompts_per_step`` wins, so the superseded key has to go with it.
216
+
217
+ A non-positive legacy value is discarded rather than migrated: ``minimum=1`` would have
218
+ rejected it at submission, and carrying it forward only fails later on a rented GPU. It is
219
+ discarded from BOTH names for the same round-trip reason -- retaining it under the old one
220
+ would re-emit a key the schema rejects for this algorithm.
221
+ """
222
+ batch_size = opt_int(train.get("batch_size"))
223
+ prompts_per_step = opt_int(train.get("prompts_per_step"))
224
+ if not samples_on_policy(algorithm):
225
+ return batch_size, prompts_per_step
226
+ if prompts_per_step is not None:
227
+ return None, prompts_per_step
228
+ return None, batch_size if batch_size is not None and batch_size >= 1 else None
229
+
230
+
231
+ _PREPARATION_ENVELOPE_VERSION = 1
232
+
233
+
234
+ def _prepared_before_public_alpha(raw_public: object) -> bool:
235
+ """True when this run's PERSISTED public spec predates ``lora_alpha`` becoming authorable.
236
+
237
+ The discriminator is the stored bytes, not this build's serialization: a snapshot prepared
238
+ before the change hashed a public spec with no alpha key, and its digest can only be reproduced
239
+ the same way. status.spec is never rewritten, so this answer is stable for the run's life.
240
+
241
+ A warm-start spec is excluded even though it also omits alpha -- to_dict() strips rank and alpha
242
+ for those in every version, so absence there says nothing about when the run was prepared, and
243
+ treating it as legacy would drop a binding that costs nothing to keep.
244
+ """
245
+ if not isinstance(raw_public, dict):
246
+ return False
247
+ train = raw_public.get("train")
248
+ if not isinstance(train, dict) or "lora_alpha" in train:
249
+ return False
250
+ return not train.get("init_from_adapter")
251
+
252
+
253
+ _ROLLOUT_BATCH_KEYS = ("batch_size", "prompts_per_step")
254
+
255
+
256
+ def _stored_rollout_batch_spelling(raw_spec: object) -> dict[str, Any] | None:
257
+ """How a PERSISTED rollout spec spelled its optimizer batch, or None if it is not one.
258
+
259
+ Same discriminator style as ``_prepared_before_public_alpha``: the answer comes from the stored
260
+ bytes, which are never rewritten, so it is stable for the run's life.
261
+
262
+ ``JobSpec.from_dict`` MOVES the pre-1.1.43 ``batch_size`` onto ``prompts_per_step`` when
263
+ reparsing, so rehashing a persisted spec with today's parse can produce different bytes than
264
+ were hashed at persist time -- failing integrity validation for exactly the warm-start grpo/opd
265
+ runs this migration exists to rescue.
266
+
267
+ Both keys are reported, rather than just the value there is to migrate. Reporting only the
268
+ latter conflates snapshots that have nothing to move but still change shape: a mixed-version
269
+ payload storing both names (the migration drops the old one, so the stored ``batch_size`` still
270
+ has to be rehashed), one whose legacy value is non-positive (discarded by the parser), and a
271
+ modern payload (nothing to do). Replaying the stored spelling covers all of them uniformly.
272
+
273
+ A key merely holding null reports None; a key genuinely OMITTED is omitted from the reading too,
274
+ because the two hash differently. Every digest is taken over a serialized ``JobSpec``, which
275
+ emits both names, so a null was really hashed as null -- while 1.1.40 predates
276
+ ``prompts_per_step`` entirely and hashed no such key. Each half's reading therefore carries its
277
+ OWN absence rather than sharing one flag: after a re-persist the worker half is rewritten in the
278
+ modern shape while ``status.spec`` keeps the legacy one, so the halves genuinely disagree about
279
+ which keys exist and a single flag would misdescribe one of them.
280
+
281
+ This is not a way to forge a batch: the replayed values are the STORED ones, and the digest they
282
+ are compared against was computed over the ORIGINAL ones, so any tampering still mismatches.
283
+
284
+ Only a rollout algorithm is eligible: for sft ``batch_size`` is the current, un-migrated name,
285
+ which ``from_dict`` leaves alone.
286
+ """
287
+ if not isinstance(raw_spec, dict):
288
+ return None
289
+ if not samples_on_policy(normalize_algorithm(str(raw_spec.get("algorithm") or ""))):
290
+ return None
291
+ train = raw_spec.get("train")
292
+ if not isinstance(train, dict):
293
+ return None
294
+ stored = {key: train.get(key) for key in _ROLLOUT_BATCH_KEYS}
295
+ # the 1.1.40 shape, read off the bytes themselves: it carried the old name and no new one.
296
+ # a payload omitting both says nothing about when it was written, and the serializer always
297
+ # emits both -- so treating that as absence would drop a key that was hashed.
298
+ if "batch_size" in train and "prompts_per_step" not in train:
299
+ del stored["prompts_per_step"]
300
+ return stored
301
+
302
+
303
+ def _restore_rollout_batch_spelling(payload: dict, stored: dict | None) -> None:
304
+ """Put the optimizer-batch keys back exactly as the stored payload hashed them.
305
+
306
+ A key absent from ``stored`` was absent from the hashed bytes, so it is removed rather than
307
+ written -- that is the 1.1.40 shape, which predates ``prompts_per_step``.
308
+ """
309
+ if stored is None:
310
+ return
311
+ train = payload.get("train")
312
+ if not isinstance(train, dict):
313
+ return
314
+ for key in _ROLLOUT_BATCH_KEYS:
315
+ if key in stored:
316
+ train[key] = stored[key]
317
+ else:
318
+ train.pop(key, None)
319
+
320
+
321
+ @dataclass(frozen=True)
322
+ class VersionedPersistedSpecEnvelope:
323
+ """How a persisted snapshot's bytes were spelled when its digest was taken.
324
+
325
+ Every field here answers one question -- what did the STORED payload look like, not what does
326
+ this build serialize -- and each is read off bytes that are never rewritten, so the answers are
327
+ stable for the run's life. They were previously five keyword arguments threaded through three
328
+ call sites in lockstep; nothing ever passed a meaningful subset, because they are one reading.
329
+
330
+ Empty is the correct default for a snapshot written by this build: there is nothing to rewind,
331
+ so ``rewind()`` is a no-op and the digest is taken over today's serialization directly.
332
+ """
333
+
334
+ CURRENT_VERSION: ClassVar[int] = _PREPARATION_ENVELOPE_VERSION
335
+
336
+ version: int = CURRENT_VERSION
337
+ worker_dropped_keys: Mapping[str, Any] = field(default_factory=dict)
338
+ public_dropped_keys: Mapping[str, Any] = field(default_factory=dict)
339
+ public_omits_lora_alpha: bool = False
340
+ worker_rollout_batch: dict[str, Any] | None = None
341
+ public_rollout_batch: dict[str, Any] | None = None
342
+
343
+ @classmethod
344
+ def read(
345
+ cls,
346
+ snapshot: object,
347
+ raw_public: object,
348
+ *,
349
+ include_worker: bool = True,
350
+ ) -> VersionedPersistedSpecEnvelope:
351
+ """Read one persisted preparation envelope and its public half.
352
+
353
+ Historical snapshots predate the explicit version key and are version 1 by definition. A
354
+ newer version is rejected rather than guessed: the digest cannot reveal which serialization
355
+ produced it, so an older build has no safe replay strategy for bytes it does not understand.
356
+
357
+ The public and worker halves keep independent spelling. After re-persistence the worker half
358
+ is rewritten in the modern shape while ``status.spec`` stays historical; ``include_worker``
359
+ is false on that write path so old worker spelling is not replayed onto newly serialized bytes.
360
+ """
361
+ snapshot = snapshot if isinstance(snapshot, Mapping) else {}
362
+ version = snapshot.get("version", cls.CURRENT_VERSION)
363
+ if isinstance(version, bool) or not isinstance(version, int) or version < 1:
364
+ raise ValueError("persisted preparation envelope version must be a positive integer")
365
+ if version != cls.CURRENT_VERSION:
366
+ raise ValueError(f"unsupported persisted preparation envelope version {version}")
367
+ raw_worker = snapshot.get("worker_spec") if include_worker else None
368
+ return cls(
369
+ version=version,
370
+ worker_dropped_keys=_dropped_key_subset(raw_worker),
371
+ public_dropped_keys=_dropped_key_subset(raw_public),
372
+ public_omits_lora_alpha=_prepared_before_public_alpha(raw_public),
373
+ worker_rollout_batch=_stored_rollout_batch_spelling(raw_worker),
374
+ public_rollout_batch=_stored_rollout_batch_spelling(raw_public),
375
+ )
376
+
377
+ def rewind(self, public_payload: dict, worker_payload: dict) -> None:
378
+ """Rewind today's serialization to the bytes this snapshot actually hashed.
379
+
380
+ None of this can forge a value: every replayed key comes from the STORED payload, and the
381
+ digest it is compared against was computed over the ORIGINAL one, so tampering still
382
+ mismatches. Only keys registered as historical removals are honoured -- filtered HERE and
383
+ not just at ``read()``, because an instance can be built directly -- so a field the
384
+ dataclass still defines always comes from the spec itself.
385
+ """
386
+ # the rollout optimizer batch was renamed `batch_size` -> `prompts_per_step`, and from_dict
387
+ # moves it when reparsing -- so a spec written before or across the rename only reproduces
388
+ # its digest under the spelling it actually stored, including a key it did not have.
389
+ _restore_rollout_batch_spelling(worker_payload, self.worker_rollout_batch)
390
+ _restore_rollout_batch_spelling(public_payload, self.public_rollout_batch)
391
+ # a pre-upgrade snapshot hashed `model_policy` in (to_internal_dict was asdict, so it emitted
392
+ # the defaulted value) and the field no longer exists, so rehashing without it fails a
393
+ # still-valid run's integrity check on recovery.
394
+ worker_payload.update(_dropped_key_subset(self.worker_dropped_keys))
395
+ # a dropped key that was user-authorable was hashed on the public side too. model_policy
396
+ # never was, so the worker half sufficed for it; model_revision and worker_env were.
397
+ public_payload.update(_dropped_key_subset(self.public_dropped_keys))
398
+ # ``lora_alpha`` became user-authorable, so to_dict() now emits it for non-warm-start runs.
399
+ # scoped to legacy snapshots only: a digest created from here on binds the public alpha, and
400
+ # without that binding the two halves can disagree silently -- `_validate_effective_spec`
401
+ # excludes lora_alpha from its structural comparison, leaving the digest as the only cover.
402
+ if self.public_omits_lora_alpha:
403
+ public_payload["train"].pop("lora_alpha", None)
404
+
405
+
406
+ def _dropped_key_subset(raw_spec: object) -> dict[str, Any]:
407
+ """The since-removed top-level keys a mapping carries, and nothing else.
408
+
409
+ Applied on the way in AND on the way out: a key the dataclass still defines must come from the
410
+ spec, never from a replayed reading, so the filter has to sit at the apply site too.
411
+ """
412
+ if not isinstance(raw_spec, Mapping):
413
+ return {}
414
+ return {key: raw_spec[key] for key in DROPPED_TOP_LEVEL_KEYS if key in raw_spec}
@@ -935,6 +935,7 @@ from flash.engine.worker.verl.capabilities import ( # noqa: E402,F401
935
935
  resolve_rollout_enforce_eager,
936
936
  resolve_verl_loggers,
937
937
  resolve_verl_python,
938
+ rollout_mm_processor_cache_overrides,
938
939
  rollout_resident_overrides,
939
940
  rollout_sleep_unsupported,
940
941
  strict_gdn_probe_module,