freesolo-flash-dev 1.2.28__tar.gz → 1.2.36__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 (540) hide show
  1. freesolo_flash_dev-1.2.36/CHANGELOG.md +113 -0
  2. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/PKG-INFO +1 -1
  3. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/__init__.py +2 -2
  4. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/deploy.py +214 -1
  5. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/episode.py +72 -30
  6. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/eval.py +7 -4
  7. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/setup.py +9 -7
  8. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/test.py +26 -20
  9. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/test_evaluations.py +58 -4
  10. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/scaffold/TRAINING.md +7 -2
  11. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/ui/tables.py +3 -1
  12. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/client/http.py +62 -18
  13. freesolo_flash_dev-1.2.36/flash/client/streaming.py +145 -0
  14. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/core/spec.py +106 -11
  15. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/evaluations.py +41 -7
  16. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/allocator.py +92 -58
  17. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/runpod/__init__.py +16 -1
  18. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/preparation.py +11 -0
  19. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/status.py +14 -2
  20. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/submit.py +9 -4
  21. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/supervise/attach.py +2 -5
  22. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/supervise/lifecycle.py +8 -6
  23. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/supervise/seed_submission.py +6 -0
  24. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/supervise/transitions.py +24 -3
  25. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/schema/__init__.py +63 -55
  26. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/serve/deploy.py +17 -9
  27. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/serve/errors.py +16 -0
  28. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/app.py +3 -2
  29. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/billing/charges.py +4 -3
  30. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/domain/run_registry.py +2 -3
  31. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/platform/runtime.py +2 -5
  32. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/routes/serving.py +3 -3
  33. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/routes/serving_completion.py +133 -59
  34. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/routes/serving_revisions.py +38 -7
  35. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/routes/serving_smoke.py +109 -29
  36. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/pyproject.toml +2 -2
  37. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_allocator.py +83 -0
  38. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cancel_remote.py +53 -0
  39. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_commands.py +20 -1
  40. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_render_coverage.py +30 -0
  41. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_client.py +267 -6
  42. freesolo_flash_dev-1.2.36/tests/test_deploy_alias_move_warning.py +554 -0
  43. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_evaluations.py +92 -14
  44. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_publish.py +56 -0
  45. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_test.py +370 -23
  46. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_idle_endpoint_reaper.py +40 -0
  47. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_provider_routing.py +125 -31
  48. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_serve.py +11 -8
  49. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_server_api.py +624 -47
  50. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_server_envs_coverage.py +310 -5
  51. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_spec_and_validation.py +205 -1
  52. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/uv.lock +1 -1
  53. freesolo_flash_dev-1.2.28/CHANGELOG.md +0 -200
  54. freesolo_flash_dev-1.2.28/flash/client/streaming.py +0 -94
  55. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.dockerignore +0 -0
  56. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.env.example +0 -0
  57. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/CODEOWNERS +0 -0
  58. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  59. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  60. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  61. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  62. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/dependabot.yml +0 -0
  63. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/workflows/auto-rebake.yml +0 -0
  64. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/workflows/bake-kernel-cache.yml +0 -0
  65. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/workflows/ci.yml +0 -0
  66. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/workflows/main-source-guard.yml +0 -0
  67. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/workflows/notify-tests-repo.yml +0 -0
  68. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/workflows/publish-dev.yml +0 -0
  69. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/workflows/publish-image.yml +0 -0
  70. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/workflows/publish.yml +0 -0
  71. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/workflows/version-parity.yml +0 -0
  72. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.github/workflows/worker-image.yml +0 -0
  73. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/.gitignore +0 -0
  74. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/CODE_OF_CONDUCT.md +0 -0
  75. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/CONTRIBUTING.md +0 -0
  76. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/Dockerfile +0 -0
  77. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/Dockerfile.worker +0 -0
  78. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/LICENSE +0 -0
  79. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/NOTICE +0 -0
  80. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/README.md +0 -0
  81. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/SECURITY.md +0 -0
  82. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/SELF_HOSTING.md +0 -0
  83. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/build/kernel_cache/.gitignore +0 -0
  84. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/build/kernel_cache/.keep +0 -0
  85. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/deploy/infisical/README.md +0 -0
  86. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/deploy/infisical/entrypoint.sh +0 -0
  87. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/docker/Dockerfile.kernelcache +0 -0
  88. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/docker/Dockerfile.kernelcache.relayer +0 -0
  89. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/docker/bake_kernel_cache.py +0 -0
  90. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/docker/bake_pod_entry.py +0 -0
  91. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/docker/extract_cudart_fix.py +0 -0
  92. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/docker/kernel_fingerprint.py +0 -0
  93. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/docker/make_rp_handler.py +0 -0
  94. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/__init__.py +0 -0
  95. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/_internal/__init__.py +0 -0
  96. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/_internal/channel.py +0 -0
  97. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/_internal/diagnostics.py +0 -0
  98. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/_internal/fileio.py +0 -0
  99. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/_internal/logging.py +0 -0
  100. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/_internal/paths.py +0 -0
  101. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/adapters/__init__.py +0 -0
  102. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/adapters/artifacts.py +0 -0
  103. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/adapters/lora_rank.py +0 -0
  104. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/__main__.py +0 -0
  105. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/__init__.py +0 -0
  106. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/__init__.py +0 -0
  107. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/eval_args.py +0 -0
  108. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/imports.py +0 -0
  109. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/list.py +0 -0
  110. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/push.py +0 -0
  111. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/retained.py +0 -0
  112. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/test_params.py +0 -0
  113. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/env/test_warnings.py +0 -0
  114. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/traces.py +0 -0
  115. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/commands/train_cost.py +0 -0
  116. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/scaffold/__init__.py +0 -0
  117. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/ui/__init__.py +0 -0
  118. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/ui/cost.py +0 -0
  119. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/ui/env_panels.py +0 -0
  120. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/ui/heartbeat.py +0 -0
  121. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/ui/render.py +0 -0
  122. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cli/ui/tty.py +0 -0
  123. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/client/__init__.py +0 -0
  124. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/client/config.py +0 -0
  125. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/client/freesolo_api.py +0 -0
  126. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/client/runtime_secrets.py +0 -0
  127. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/client/shapes.py +0 -0
  128. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/client/specs.py +0 -0
  129. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/content/__init__.py +0 -0
  130. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/content/multimodal.py +0 -0
  131. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/content/structured_outputs.py +0 -0
  132. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/content/thinking.py +0 -0
  133. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/core/__init__.py +0 -0
  134. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/core/catalog.py +0 -0
  135. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cost/__init__.py +0 -0
  136. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cost/analytical.py +0 -0
  137. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cost/facts.py +0 -0
  138. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cost/spec.py +0 -0
  139. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/cost/types.py +0 -0
  140. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/__init__.py +0 -0
  141. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/plan/__init__.py +0 -0
  142. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/plan/kv_sizing.py +0 -0
  143. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/plan/model_config_probe.py +0 -0
  144. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/plan/recipe.py +0 -0
  145. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/plan/steps.py +0 -0
  146. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/plan/vram.py +0 -0
  147. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/profiling/__init__.py +0 -0
  148. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/profiling/dataset_profile.py +0 -0
  149. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/profiling/reasoning_render.py +0 -0
  150. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/profiling/sft_workload.py +0 -0
  151. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/profiling/tokenizer.py +0 -0
  152. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/profiling/workload_profile.py +0 -0
  153. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/result/__init__.py +0 -0
  154. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/result/accounting.py +0 -0
  155. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/result/rollout_samples.py +0 -0
  156. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/__init__.py +0 -0
  157. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/__main__.py +0 -0
  158. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/backend_common.py +0 -0
  159. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/entry/__init__.py +0 -0
  160. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/entry/opd.py +0 -0
  161. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/entry/rl.py +0 -0
  162. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/entry/sft.py +0 -0
  163. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/io/__init__.py +0 -0
  164. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/io/heartbeat.py +0 -0
  165. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/io/hf.py +0 -0
  166. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/io/prefetch.py +0 -0
  167. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/io/wandb_log.py +0 -0
  168. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/model/__init__.py +0 -0
  169. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/model/adapter.py +0 -0
  170. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/model/decoding.py +0 -0
  171. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/model/lora.py +0 -0
  172. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/model/packing.py +0 -0
  173. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/opd_train.py +0 -0
  174. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/opd_train_runner.py +0 -0
  175. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/perf/__init__.py +0 -0
  176. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/perf/diagnostics.py +0 -0
  177. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/perf/lifecycle.py +0 -0
  178. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/perf/liger.py +0 -0
  179. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/perf/memory.py +0 -0
  180. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/rl_train.py +0 -0
  181. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/rl_train_runner.py +0 -0
  182. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/runtime/__init__.py +0 -0
  183. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/runtime/kernel_warmup.py +0 -0
  184. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/runtime/pkg_proxy.py +0 -0
  185. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/runtime/rng.py +0 -0
  186. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/score_batcher.py +0 -0
  187. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/sft_train.py +0 -0
  188. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/sft_train_runner.py +0 -0
  189. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/teacher/__init__.py +0 -0
  190. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/teacher/client.py +0 -0
  191. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/teacher/encoding.py +0 -0
  192. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/teacher/tokenizer_align.py +0 -0
  193. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/__init__.py +0 -0
  194. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/core/__init__.py +0 -0
  195. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/core/child/__init__.py +0 -0
  196. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/core/child/glue.py +0 -0
  197. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/core/step_timing.py +0 -0
  198. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/finalize.py +0 -0
  199. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/__init__.py +0 -0
  200. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/batching.py +0 -0
  201. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/bridge.py +0 -0
  202. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/child/__init__.py +0 -0
  203. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/child/bridge.py +0 -0
  204. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/child/multiturn.py +0 -0
  205. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/child/plugin.py +0 -0
  206. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/child/structured.py +0 -0
  207. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/failures.py +0 -0
  208. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/gkd.py +0 -0
  209. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/multiturn_validation.py +0 -0
  210. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/overrides.py +0 -0
  211. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/prompts.py +0 -0
  212. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/reporting.py +0 -0
  213. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/scoring.py +0 -0
  214. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/state.py +0 -0
  215. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/opd/validation.py +0 -0
  216. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/rl/__init__.py +0 -0
  217. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/rl/checkpoints.py +0 -0
  218. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/rl/child/__init__.py +0 -0
  219. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/rl/child/multiturn.py +0 -0
  220. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/rl/child/plugin.py +0 -0
  221. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/rl/config.py +0 -0
  222. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/rl/inputs.py +0 -0
  223. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/rl/multi_turn.py +0 -0
  224. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/rl/scoring.py +0 -0
  225. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/rl/shims.py +0 -0
  226. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/rl/single_turn.py +0 -0
  227. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/rl/verl_config.py +0 -0
  228. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/sft/__init__.py +0 -0
  229. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/sft/checkpoints.py +0 -0
  230. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/train/sft/config.py +0 -0
  231. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/verl/__init__.py +0 -0
  232. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/verl/capabilities.py +0 -0
  233. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/verl/checkpoints.py +0 -0
  234. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/verl/child_io.py +0 -0
  235. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/verl/diagnostics.py +0 -0
  236. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker/verl/parallelism.py +0 -0
  237. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/engine/worker_entrypoint.py +0 -0
  238. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/__init__.py +0 -0
  239. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/adapter.py +0 -0
  240. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/base.py +0 -0
  241. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/cache_security.py +0 -0
  242. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/dataset_selection.py +0 -0
  243. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/identity.py +0 -0
  244. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/loader.py +0 -0
  245. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/namespace_listing.py +0 -0
  246. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/package/__init__.py +0 -0
  247. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/package/limits.py +0 -0
  248. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/package/unpack.py +0 -0
  249. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/envs/pull.py +0 -0
  250. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/__init__.py +0 -0
  251. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/_lifecycle/__init__.py +0 -0
  252. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/_lifecycle/auth.py +0 -0
  253. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/_lifecycle/bootstrap.py +0 -0
  254. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/_lifecycle/bootstrap_pip.py +0 -0
  255. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/_lifecycle/bootstrap_secrets.py +0 -0
  256. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/_lifecycle/deadline.py +0 -0
  257. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/_lifecycle/http.py +0 -0
  258. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/_lifecycle/instance.py +0 -0
  259. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/_lifecycle/poll.py +0 -0
  260. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/_lifecycle/poll_instance.py +0 -0
  261. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/_lifecycle/provider.py +0 -0
  262. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/_lifecycle/worker.py +0 -0
  263. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/artifacts/__init__.py +0 -0
  264. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/artifacts/hf.py +0 -0
  265. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/artifacts/preload_runpod.py +0 -0
  266. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/artifacts/weight_cache.py +0 -0
  267. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/base.py +0 -0
  268. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/fit_errors.py +0 -0
  269. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/lambda_/__init__.py +0 -0
  270. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/lambda_/api.py +0 -0
  271. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/lambda_/auth.py +0 -0
  272. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/lambda_/gpus.py +0 -0
  273. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/lambda_/jobs/__init__.py +0 -0
  274. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/lambda_/jobs/builders.py +0 -0
  275. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/lambda_/jobs/reap.py +0 -0
  276. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/lambda_/preflight.py +0 -0
  277. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/lambda_/pricing.py +0 -0
  278. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/preflight.py +0 -0
  279. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/realized.py +0 -0
  280. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/runpod/api.py +0 -0
  281. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/runpod/auth.py +0 -0
  282. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/runpod/cost.py +0 -0
  283. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/runpod/gpus.py +0 -0
  284. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/runpod/job_execution.py +0 -0
  285. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/runpod/jobs.py +0 -0
  286. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/runpod/preflight.py +0 -0
  287. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/runpod/pricing.py +0 -0
  288. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/runpod/resources.py +0 -0
  289. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/runpod/serverless/__init__.py +0 -0
  290. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/runpod/serverless/endpoints.py +0 -0
  291. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/sharding.py +0 -0
  292. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/vast/__init__.py +0 -0
  293. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/vast/api.py +0 -0
  294. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/vast/auth.py +0 -0
  295. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/vast/jobs/__init__.py +0 -0
  296. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/vast/jobs/builders.py +0 -0
  297. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/vast/preflight.py +0 -0
  298. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/providers/vast/pricing.py +0 -0
  299. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/py.typed +0 -0
  300. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/__init__.py +0 -0
  301. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/artifacts.py +0 -0
  302. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/attempts.py +0 -0
  303. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/costs.py +0 -0
  304. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/deadlines.py +0 -0
  305. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/reconciliation.py +0 -0
  306. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/results/__init__.py +0 -0
  307. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/results/checkpoints.py +0 -0
  308. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/results/verified_revisions.py +0 -0
  309. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/supervise/__init__.py +0 -0
  310. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/supervise/deploy.py +0 -0
  311. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/supervise/recovery.py +0 -0
  312. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/supervise/retry_decision.py +0 -0
  313. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/runner/weight_cache.py +0 -0
  314. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/schema/fields.py +0 -0
  315. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/serve/__init__.py +0 -0
  316. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/serve/adapter_check.py +0 -0
  317. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/serve/export.py +0 -0
  318. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/serve/preflight.py +0 -0
  319. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/serve/responses.py +0 -0
  320. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/serve/streaming.py +0 -0
  321. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/serve/thinking.py +0 -0
  322. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/serve/urls.py +0 -0
  323. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/__init__.py +0 -0
  324. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/__main__.py +0 -0
  325. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/billing/__init__.py +0 -0
  326. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/billing/retry.py +0 -0
  327. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/domain/__init__.py +0 -0
  328. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/domain/checkpoints.py +0 -0
  329. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/domain/environment_registry.py +0 -0
  330. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/domain/envs.py +0 -0
  331. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/domain/projects.py +0 -0
  332. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/domain/reconcile.py +0 -0
  333. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/domain/repo_cleanup.py +0 -0
  334. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/domain/teacher_broker.py +0 -0
  335. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/domain/teacher_errors.py +0 -0
  336. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/domain/teacher_requests.py +0 -0
  337. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/platform/__init__.py +0 -0
  338. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/platform/auth.py +0 -0
  339. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/platform/db.py +0 -0
  340. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/platform/deps.py +0 -0
  341. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/platform/internal_client.py +0 -0
  342. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/platform/locks.py +0 -0
  343. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/routes/__init__.py +0 -0
  344. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/routes/envs.py +0 -0
  345. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/routes/meta.py +0 -0
  346. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/routes/runs.py +0 -0
  347. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/server/routes/teacher.py +0 -0
  348. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/teacher/__init__.py +0 -0
  349. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/teacher/limits.py +0 -0
  350. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/flash/teacher/retry_contract.py +0 -0
  351. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/scripts/build_dev_dist.py +0 -0
  352. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/scripts/check_file_size.py +0 -0
  353. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/scripts/check_function_size.py +0 -0
  354. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/scripts/check_verl_pin_exists.py +0 -0
  355. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/scripts/scrub_history.sh +0 -0
  356. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/__init__.py +0 -0
  357. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/_helpers/__init__.py +0 -0
  358. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/_helpers/profile.py +0 -0
  359. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/_helpers/runner.py +0 -0
  360. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/_helpers/specs.py +0 -0
  361. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/_helpers/teacher.py +0 -0
  362. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/_helpers/vast.py +0 -0
  363. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/conftest.py +0 -0
  364. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/fixtures/math_eval.jsonl +0 -0
  365. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/fixtures/math_train.jsonl +0 -0
  366. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/live/__init__.py +0 -0
  367. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/live/conftest.py +0 -0
  368. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/live/test_lambda_live.py +0 -0
  369. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/live/test_runpod_live.py +0 -0
  370. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/live/test_sft_thinking_render_live.py +0 -0
  371. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/live/test_vast_live.py +0 -0
  372. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_accounting_coverage.py +0 -0
  373. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_adapter_shard_completeness.py +0 -0
  374. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_agent_flash_cli_contract.py +0 -0
  375. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_algorithms.py +0 -0
  376. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_backend_common.py +0 -0
  377. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_backend_jobspec_contract.py +0 -0
  378. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_bake_kernel_cache.py +0 -0
  379. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_base_model_provenance.py +0 -0
  380. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_billing_retry.py +0 -0
  381. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_build_context_contract.py +0 -0
  382. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_catalog_consistency.py +0 -0
  383. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_catalog_only_models.py +0 -0
  384. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_charge_pricing.py +0 -0
  385. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_checkpoints.py +0 -0
  386. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_commands_coverage.py +0 -0
  387. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_credential_shadowing.py +0 -0
  388. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_errors.py +0 -0
  389. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_estimate.py +0 -0
  390. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_gpus_flag.py +0 -0
  391. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_help.py +0 -0
  392. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_main_coverage.py +0 -0
  393. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_managed.py +0 -0
  394. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_render_theme.py +0 -0
  395. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_traces.py +0 -0
  396. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cli_wandb_warning.py +0 -0
  397. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_client_import_purity.py +0 -0
  398. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_client_server_integration.py +0 -0
  399. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_client_stream_reads.py +0 -0
  400. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_config_env_vars.py +0 -0
  401. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_config_overrides.py +0 -0
  402. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_controlled_experiment_repairs.py +0 -0
  403. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cost_analytical.py +0 -0
  404. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cost_equation.py +0 -0
  405. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cost_estimate.py +0 -0
  406. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cost_hardware.py +0 -0
  407. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_cost_models.py +0 -0
  408. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_dataset_profile.py +0 -0
  409. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_deploy_latency.py +0 -0
  410. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_dev_channel.py +0 -0
  411. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_disk_gb.py +0 -0
  412. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_endpoint_name.py +0 -0
  413. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_cache_evict.py +0 -0
  414. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_delete.py +0 -0
  415. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_download.py +0 -0
  416. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_download_api.py +0 -0
  417. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_list_api.py +0 -0
  418. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_list_cli.py +0 -0
  419. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_list_hub.py +0 -0
  420. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_no_install.py +0 -0
  421. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_pull.py +0 -0
  422. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_pull_coverage.py +0 -0
  423. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_pull_loader_coverage.py +0 -0
  424. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_pull_managed_control_plane.py +0 -0
  425. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_push.py +0 -0
  426. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_rate_limit_resolve.py +0 -0
  427. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_env_ref_pinning.py +0 -0
  428. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_envs_coverage.py +0 -0
  429. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_export.py +0 -0
  430. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_flash_mvp.py +0 -0
  431. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_flash_worker.py +0 -0
  432. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_flashinfer_cache_dirs.py +0 -0
  433. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_freesolo_api_transport.py +0 -0
  434. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_github_urlopen_retry.py +0 -0
  435. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_gpu_type_single_field.py +0 -0
  436. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_gpus.py +0 -0
  437. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_grpo_params.py +0 -0
  438. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_grpo_resident_sizing.py +0 -0
  439. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_grpo_reward_batching.py +0 -0
  440. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_health_liveness.py +0 -0
  441. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_hf_retry.py +0 -0
  442. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_infisical_secrets.py +0 -0
  443. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_instance_bootstrap_coverage.py +0 -0
  444. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_internal_client.py +0 -0
  445. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_jobs.py +0 -0
  446. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_kernel_cache.py +0 -0
  447. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_kernel_fingerprint.py +0 -0
  448. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_kv_util.py +0 -0
  449. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_lambda_api_coverage.py +0 -0
  450. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_lambda_runner.py +0 -0
  451. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_logging.py +0 -0
  452. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_login_perms.py +0 -0
  453. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_lora_rank_coverage.py +0 -0
  454. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_lora_rank_preflight.py +0 -0
  455. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_managed_config_fields.py +0 -0
  456. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_managed_hf_repo.py +0 -0
  457. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_metrics_schema_agent_contract.py +0 -0
  458. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_mig_guard.py +0 -0
  459. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_multi_gpu_gate.py +0 -0
  460. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_multimodal_training.py +0 -0
  461. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_named_reward_metrics.py +0 -0
  462. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_oom_escalate_gpu.py +0 -0
  463. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_opd.py +0 -0
  464. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_opd_limits.py +0 -0
  465. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_opd_multiturn_eos_boundary.py +0 -0
  466. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_opd_resume_safety.py +0 -0
  467. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_opd_train.py +0 -0
  468. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_orchestrator_flash.py +0 -0
  469. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_packing.py +0 -0
  470. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_packing_coverage.py +0 -0
  471. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_parasail_teacher.py +0 -0
  472. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_poll_helpers.py +0 -0
  473. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_preflight.py +0 -0
  474. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_projects.py +0 -0
  475. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_provider_preflight_coverage.py +0 -0
  476. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_provider_teardown_robustness.py +0 -0
  477. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_providers_symmetry.py +0 -0
  478. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_realized_cost.py +0 -0
  479. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_repo_cleanup.py +0 -0
  480. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_resolve_params_b.py +0 -0
  481. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_resume_on_retry.py +0 -0
  482. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_rl_train.py +0 -0
  483. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_rollout_samples.py +0 -0
  484. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_runmgmt.py +0 -0
  485. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_runpod_api_delete.py +0 -0
  486. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_runpod_key_fingerprint.py +0 -0
  487. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_runpod_key_waterfall.py +0 -0
  488. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_serve_reasoning_content.py +0 -0
  489. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_server_app_coverage.py +0 -0
  490. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_server_auth_singleflight.py +0 -0
  491. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_server_billing.py +0 -0
  492. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_server_checkpoints_coverage.py +0 -0
  493. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_server_db.py +0 -0
  494. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_server_locks_coverage.py +0 -0
  495. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_server_standalone.py +0 -0
  496. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_serving_context_preflight.py +0 -0
  497. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_serving_contract.py +0 -0
  498. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_serving_schema_coverage.py +0 -0
  499. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_sft_chunked_nll.py +0 -0
  500. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_sft_example_selection.py +0 -0
  501. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_sft_gc_off.py +0 -0
  502. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_sft_max_context.py +0 -0
  503. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_sft_startup_block.py +0 -0
  504. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_sft_train.py +0 -0
  505. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_sft_workload.py +0 -0
  506. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_step_floor.py +0 -0
  507. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_step_metrics.py +0 -0
  508. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_step_timing.py +0 -0
  509. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_structured_outputs.py +0 -0
  510. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_teacher_broker.py +0 -0
  511. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_teacher_encoding_contract.py +0 -0
  512. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_thinking_config.py +0 -0
  513. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_train_context_preflight.py +0 -0
  514. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_training_controls.py +0 -0
  515. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_type_comment_prose.py +0 -0
  516. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_vast_api.py +0 -0
  517. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_vast_api_coverage.py +0 -0
  518. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_vast_offers.py +0 -0
  519. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_vast_provider_coverage.py +0 -0
  520. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_vast_runner.py +0 -0
  521. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_verified_revisions.py +0 -0
  522. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_verifiers.py +0 -0
  523. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_version.py +0 -0
  524. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_vl_warmstart_adapter_keys.py +0 -0
  525. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_vram_architecture.py +0 -0
  526. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_wandb_link.py +0 -0
  527. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_wandb_naming.py +0 -0
  528. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_warmstart_adapter_download.py +0 -0
  529. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_warmstart_cross_repo.py +0 -0
  530. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_warmstart_error_attribution.py +0 -0
  531. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_weight_cache.py +0 -0
  532. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_worker_dryrun.py +0 -0
  533. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_worker_hardexit.py +0 -0
  534. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_worker_image.py +0 -0
  535. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_worker_init_heartbeat.py +0 -0
  536. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_worker_stack.py +0 -0
  537. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_worker_thinking.py +0 -0
  538. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_workflow_contracts.py +0 -0
  539. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_workload_profile.py +0 -0
  540. {freesolo_flash_dev-1.2.28 → freesolo_flash_dev-1.2.36}/tests/test_zero2_sharding_gate.py +0 -0
@@ -0,0 +1,113 @@
1
+ # Changelog
2
+
3
+ Notable changes to `freesolo-flash`. The dev-channel package `freesolo-flash-dev` ships in
4
+ lockstep at the same version.
5
+
6
+ Releases happen by merging a version bump from `dev` into `main`, which publishes to PyPI
7
+ (`.github/workflows/publish.yml`). Versions are `MAJOR.MINOR.PATCH`.
8
+
9
+ This file starts at 1.1.35. Earlier releases are not reconstructed here; use
10
+ `git log` for anything before that.
11
+
12
+ ## Unreleased
13
+
14
+ ### Added
15
+
16
+ - A `flash-cli` console script, the same entry point as `flash` under a name nothing else
17
+ claims. The `server` and `dev` extras install `runpod-flash`, which declares its own `flash`
18
+ script; whichever distribution is installed last wins, so on a control-plane host
19
+ `pip install 'freesolo-flash[server]'` could leave `flash` running RunPod's CLI, which exits 0
20
+ and does nothing. `flash` is unchanged and remains correct on a base (client-only) install.
21
+
22
+ ### Changed
23
+
24
+ - CI runs the offline test suite on both supported interpreters (3.11 and 3.12) rather than
25
+ 3.11 alone, and sets `HF_HUB_OFFLINE` / `TRANSFORMERS_OFFLINE` so a test that reaches the
26
+ network fails deterministically instead of depending on runner connectivity.
27
+ - Every GitHub Action is pinned to a commit SHA rather than a mutable tag.
28
+ - `mypy` runs in CI as an advisory (non-blocking) job.
29
+
30
+ ### Fixed
31
+
32
+ - `flash models deploy` now warns before it moves the shared `<run-id>` model id onto a
33
+ different checkpoint. Every checkpoint of a run is served under that one id, so deploying
34
+ `<run-id>/step-50` while `step-100` was live silently changed what `<run-id>` served for
35
+ everyone using it — which made "deploy a second checkpoint to compare" a destructive
36
+ operation on the first, and read as a serving regression rather than the deploy that caused
37
+ it. The warning names both checkpoints and points at `flash models chat <run-id>/step-N`,
38
+ which addresses a checkpoint directly and does not depend on where the id points. It is
39
+ advisory: the deploy still proceeds, the pre-deploy read is abandoned outright once it exceeds
40
+ a few seconds so no shape of slow plane can hold a deploy behind it, and a control plane that
41
+ cannot answer (or answers with a checkpoint step this client cannot read) does not fail the
42
+ command. A deployment whose activation outcome was never settled still warns, but without
43
+ naming a checkpoint: that record's step describes the incoming attempt rather than what the id
44
+ currently serves, and the authoritative target is server-side only, so the warning says the
45
+ live checkpoint cannot be determined and points at `flash models deployments`.
46
+
47
+ - A response deadline did not actually bound a response that arrived slowly. The deadline is
48
+ checked between reads, but each read asked for a fixed number of bytes and blocked until all of
49
+ them arrived, so a peer trickling a short body kept one read inside the socket timeout
50
+ indefinitely and the check never ran: a 2s deadline took 12s on a 42-byte body, and 61s when
51
+ the socket timeout was the client default. Reading whatever has already arrived lets the check
52
+ run, which bounds every stall shape. This affected `flash env list`, whose deadline exists to
53
+ stop a slow environment hub hanging the command, as well as the new pre-deploy read.
54
+
55
+ - A response deadline could still be overrun by a read that began near its end. The socket timeout
56
+ is installed once, when the request opens, and time spent connecting and waiting for headers is
57
+ charged to the deadline but not to that timeout, so a peer that delayed its headers and then
58
+ stalled mid-body held the call open past the deadline: 3.5s against a 2s budget. Each read now
59
+ re-caps the socket to the remaining budget, so the two bounds agree instead of stacking. On a
60
+ body still arriving this surfaces as a timeout rather than the "stalled" message; both bound the
61
+ call, and which one wins is a race not worth depending on.
62
+
63
+ - Commands printed for the operator to run (the resume/cancel hand-off after `flash train`,
64
+ usage strings, `next:` hints) now name the executable actually invoked rather than always
65
+ `flash`. On a host where `runpod-flash` owns the `flash` script, the printed
66
+ `flash runs cancel <run-id>` exited 0 without cancelling, leaving a run billing while the
67
+ operator believed they had stopped it. Reached through the `python -m flash.cli` escape hatch,
68
+ the printed command now names the interpreter that is actually running, rather than a bare
69
+ `python` that is absent on a python3-only host and may resolve to a different environment
70
+ inside a virtualenv.
71
+
72
+ - `flash env setup` scaffolded hosted-only environment instructions on every plane. A
73
+ self-hosted plane cannot publish to Freesolo's managed environment hub, so the generated
74
+ configs left `[environment] id` empty (which fails validation) beside a `flash env push`
75
+ command that could not work. Against a self-hosted plane the scaffold now emits the
76
+ `github:owner/repo@ref:path` id form, which such a plane resolves directly. Output against
77
+ the managed plane is unchanged.
78
+
79
+ - `flash-server` reported missing operator configuration as an unhandled ASGI startup
80
+ exception, so the actionable message arrived under ~20 frames of starlette/contextlib. The
81
+ refusing half of the preflight now runs before uvicorn starts, and `flash-server` prints
82
+ `error: ...` and exits 3 (uvicorn's `STARTUP_FAILURE`, which this path already used, so
83
+ supervision keying on it is unaffected). The advisory warnings still come from the lifespan
84
+ alone, so a booted plane logs them once.
85
+ - `flash env test` blamed the reward function for a gold answer that scored zero, when the
86
+ gold completion is equally likely to be at fault: with no `sft_completion` hook the replayed
87
+ answer is the dataset row's raw `output`, so a dataset whose `output` is a bare value fails a
88
+ grader that (correctly) requires a wrapper. The warning now names both candidates and prints
89
+ the exact text it scored, verbatim rather than through the whitespace-collapsing, 200-character
90
+ preview that hid the formatting faults it exists to reveal. The scaffolded `environment.py`
91
+ documents that `output` is also the gold assistant turn SFT trains on, and that per-row scorer
92
+ state belongs in `metadata`.
93
+ - `flash env test` labelled the replayed dataset turns as the text that scored zero, but a
94
+ multi-turn environment whose `step_episode` returns a `final_response_text` has that override
95
+ replace the episode's response before scoring, so the diagnostic named text the grader never
96
+ saw. It now reports what the scorer actually received, captured at the scoring call.
97
+ - An environment that overrode its answer to the empty string had `flash env test` report the
98
+ replayed turns instead: the captured text was tested for truth, so a graded `""` was
99
+ indistinguishable from an episode that never reached the scorer. The override propagates on
100
+ `is not None`, so `""` really is what the grader saw -- and an empty answer explains a zero
101
+ reward on its own, making it the reading a reader most needs named rather than hidden.
102
+ - A crashed scorer went unreported on an `echo` episode -- a row with no gold answer to replay,
103
+ which is also the case that leaves the GRPO gate with nothing to count. `flash env test` could
104
+ exit `overall: PASS` with every reward coming from a scorer that never ran. The scorer's error is
105
+ now surfaced for any policy.
106
+ - A scorer that crashed behind the SDK's guard reached `flash env test` as a bare `0.000000`,
107
+ indistinguishable from a judged-wrong answer, because the adapter kept only
108
+ `RewardResult.score`. The new `FreesoloEnvironment.reward_with_error` returns the reward and the
109
+ discarded error from a single scoring call, so a missing runtime dependency names itself without
110
+ re-scoring the episode -- which would bill a paid judge twice and, for a non-deterministic
111
+ scorer, could report an error that did not produce the printed reward.
112
+ - Two tests resolved Hugging Face model metadata over the network and passed only on a
113
+ connected runner. They now stub the resolver like their siblings already did.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: freesolo-flash-dev
3
- Version: 1.2.28
3
+ Version: 1.2.36
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
@@ -738,11 +738,11 @@ def _add_deployment_commands(models_sub: argparse._SubParsersAction) -> None:
738
738
  "--wait",
739
739
  nargs="?",
740
740
  type=_wait_seconds,
741
- const=1800.0,
741
+ const=2400.0,
742
742
  default=None,
743
743
  metavar="SECONDS",
744
744
  help=(
745
- "block until the requested revision is ready or failed (default timeout 1800s). "
745
+ "block until the requested revision is ready or failed (default timeout 2400s). "
746
746
  "without it, deploy returns while the revision is still queued"
747
747
  ),
748
748
  )
@@ -11,6 +11,7 @@ from __future__ import annotations
11
11
 
12
12
  import json
13
13
  import sys
14
+ import threading
14
15
  import time
15
16
 
16
17
  from flash.cli.ui import render
@@ -41,6 +42,10 @@ _DEPLOYMENT_BUSY_STATES = frozenset({"queued", "smoke_testing", "reconciling"})
41
42
  # plane introduces are both non-busy and non-servable, so `--wait` must fail closed on them
42
43
  # rather than let `deploy --wait && evaluate` proceed against nothing.
43
44
  _DEPLOYMENT_READY_STATES = frozenset({"ready", "deployed"})
45
+ # an undeploy whose backend cleanup failed (flash/runner/supervise/transitions.py). local serving
46
+ # authority is revoked, but the alias may still resolve to the old target -- neither servable nor
47
+ # safely assumed idle.
48
+ _REVOCATION_FAILED_STATE = "revocation_failed"
44
49
  _DEPLOY_POLL_SECONDS = 5.0
45
50
  # `--wait 0` still owes the caller its one read, and a read needs a positive timeout. keep that
46
51
  # bound short enough that "check once, do not block" stays true against a stalled plane: a longer
@@ -57,6 +62,14 @@ _DEPLOY_FINAL_READ_FRACTION = 0.9
57
62
  # an auth or authorization rejection answers the same way every time; polling through it just
58
63
  # spends the whole timeout to arrive at the identical error.
59
64
  _PERMANENT_POLL_STATUSES = frozenset({401, 403})
65
+ # the pre-deploy alias read is advisory, so it must not spend the client's default 60s budget
66
+ # deciding whether to print a warning: a stalled read would delay every real deploy behind a
67
+ # line nobody asked for. short enough to stay unnoticed, long enough for a healthy plane.
68
+ # it is spent three ways, because the client's own bounds are per-phase: as a socket timeout it
69
+ # bounds one socket operation, and as a body deadline it bounds the body but is only consulted
70
+ # once headers are parsed. a peer trickling headers just inside the socket timeout escapes both.
71
+ # `_read_within` bounds the total in wall-clock time, which is the one that actually holds.
72
+ _ALIAS_WARNING_READ_SECONDS = 5.0
60
73
 
61
74
 
62
75
  def _await_deployment(client, run_id: str, deployment: dict, timeout: float) -> dict:
@@ -189,6 +202,196 @@ def _rollback_record(client, run_id: str, timeout: float) -> dict | None:
189
202
  return None
190
203
 
191
204
 
205
+ def _served_step_label(step: int | None) -> str:
206
+ """Name a deployment's checkpoint the way the user addressed it: `step-N`, or `final`."""
207
+ return "final" if step is None else f"step-{step}"
208
+
209
+
210
+ def _read_within(budget: float, read):
211
+ """Run an advisory read, giving up on it entirely once ``budget`` seconds have passed.
212
+
213
+ The client's two bounds are both per-phase, not total: `timeout` restarts on every socket
214
+ operation and the body deadline is only checked once `urlopen` has finished parsing headers.
215
+ A peer that trickles the status line or headers just inside the socket timeout therefore
216
+ stalls for timeout x however many pauses it takes -- 12s against a 2s budget, measured -- and
217
+ the whole point of the bound is that the deploy the user actually asked for is waiting behind
218
+ it. Only wall-clock time outside the call bounds every phase at once.
219
+
220
+ A daemon thread rather than a cancellation: a blocked socket read cannot be interrupted from
221
+ outside, so the read is abandoned rather than stopped. That is sound only because this result
222
+ is discardable -- no warning is the documented outcome for a plane that cannot answer, so an
223
+ overrunning read degrades to silence. Daemon, so a stuck thread cannot keep the interpreter
224
+ alive after the deploy finishes.
225
+ """
226
+ result: list = []
227
+ worker = threading.Thread(
228
+ target=lambda: result.append(_read_or_none(read)),
229
+ daemon=True,
230
+ )
231
+ worker.start()
232
+ worker.join(budget)
233
+ return result[0] if result else None
234
+
235
+
236
+ def _read_or_none(read):
237
+ """The advisory read's failure contract: a plane that cannot answer produces no warning.
238
+
239
+ Deliberately broader than `ApiError`/`ClientError`. The client translates urllib's HTTPError
240
+ and URLError, and documents that anything else propagates -- so a connection reset or a
241
+ truncated body mid-read surfaces as the bare `ConnectionResetError` / `IncompleteRead` that
242
+ urllib raised. Those are exactly the "plane cannot answer" case this exists to absorb, and on
243
+ the worker thread an escaping one reaches the thread hook and prints a traceback across a
244
+ deploy that is otherwise proceeding normally: a warning nobody asked for turning into noise
245
+ on a command that worked.
246
+ """
247
+ try:
248
+ return read()
249
+ except Exception:
250
+ # the deploy itself is the authority on whether it can proceed. failing it here -- or
251
+ # printing a traceback beside it -- would turn a warning nobody asked for into a fault in
252
+ # the command it decorates. BaseException still propagates, so KeyboardInterrupt is
253
+ # unaffected.
254
+ return None
255
+
256
+
257
+ def _alias_move_warning(client, base_run_id: str, requested_step: int | None) -> str | None:
258
+ """Warn when deploying moves the shared `<run_id>` alias off a different checkpoint.
259
+
260
+ `deploy` registers under the bare run id whatever step it is given, so deploying a second
261
+ checkpoint of the same run does not stand up a second endpoint -- it repoints the one alias,
262
+ and everyone chatting bare `<run_id>` silently changes model. That makes "deploy another
263
+ checkpoint to compare" a destructive operation on the first, which reads as a serving fault
264
+ rather than the deploy that caused it.
265
+
266
+ Best-effort by construction: the read is advisory, so a plane that cannot answer must not
267
+ stop the deploy. Returns None when nothing is being displaced -- no deployment, the same
268
+ checkpoint again, or an unreadable current record.
269
+ """
270
+ current = _read_within(
271
+ _ALIAS_WARNING_READ_SECONDS,
272
+ # not `deployment_for`: its step filter hides exactly the record this asks about, a
273
+ # DIFFERENT checkpoint holding the alias.
274
+ lambda: client.deployed_checkpoint(
275
+ base_run_id,
276
+ timeout=_ALIAS_WARNING_READ_SECONDS,
277
+ body_deadline=_ALIAS_WARNING_READ_SECONDS,
278
+ ),
279
+ )
280
+ if current is None:
281
+ return None
282
+ # a `reconciling` record whose activation outcome was never recorded may ALREADY hold the
283
+ # alias. the plane permits replacing exactly that record rather than rejecting it as busy,
284
+ # and resolves the authoritative target through `_activation_predecessor` when it does
285
+ # (flash/server/routes/serving.py). reading it as "not serving" suppressed the warning in
286
+ # the very case the alias is most likely to move out from under someone.
287
+ unknown_activation = current.get("activation_outcome_unknown") is True
288
+ # `revocation_failed` is an undeploy whose BACKEND cleanup failed: local authority is revoked
289
+ # but the alias may still resolve to the old target, and `_validate_deploy_request` rejects
290
+ # only the busy set, so a deploy proceeds from here. reading it as "not serving" suppressed
291
+ # the warning in the case where cleanup already left the alias ambiguous.
292
+ revocation_failed = str(current.get("state") or "") == _REVOCATION_FAILED_STATE
293
+ ambiguous = unknown_activation or revocation_failed
294
+ if str(current.get("state") or "") not in _DEPLOYMENT_READY_STATES and not ambiguous:
295
+ # nothing is being served off the alias yet, so nothing is lost by moving it.
296
+ return None
297
+ cli = _commands().CLI_NAME
298
+ # `step-N` is not universally available: `ApiClient.chat` gates a step target behind
299
+ # `_require_chat_step_selector`, which refuses outright on a plane that does not advertise
300
+ # `chat_step_selector_v1`. the capability cannot be read here without spending a /v1/health on
301
+ # an advisory warning, and `_chat_step_selector_available` starts False, so a negative reading
302
+ # cannot tell "unsupported" from "not checked yet". state the condition instead of asserting
303
+ # the command works, and name the selector that works on every plane.
304
+ tail = (
305
+ f"so every client using bare `{base_run_id}` changes model. address a specific "
306
+ f"checkpoint with `{cli} models chat {base_run_id}/step-N` to compare them, or by "
307
+ "immutable adapter revision if this control plane does not support step selectors."
308
+ )
309
+ if revocation_failed:
310
+ # same reason as the unknown-activation arm: this record's `checkpoint_step` describes the
311
+ # deployment whose revocation failed, and whether the backend still answers on the alias
312
+ # is exactly what could not be determined. hedge rather than name a checkpoint.
313
+ return (
314
+ f"{base_run_id} has a deployment whose revocation did not complete, so whether it "
315
+ f"still serves off that shared model id cannot be determined from here; deploying "
316
+ f"{_served_step_label(requested_step)} may move it, "
317
+ f"{tail} run `{cli} models deployments` to see the current state first."
318
+ )
319
+ if unknown_activation:
320
+ # this record's `checkpoint_step` names the INCOMING attempt, not what the alias holds:
321
+ # the plane resolves the live target from `adapter_alias_target` / `previous_deployment`,
322
+ # and both are server-side (`public_deployment` strips the predecessor). naming a
323
+ # checkpoint here would report the wrong one -- worse than naming none -- so say only what
324
+ # this side can actually stand behind.
325
+ return (
326
+ f"{base_run_id} has a deployment whose activation never settled, so the checkpoint "
327
+ f"it currently serves cannot be determined from here; deploying "
328
+ f"{_served_step_label(requested_step)} may move that shared model id, "
329
+ f"{tail} run `{cli} models deployments` to see the current state first."
330
+ )
331
+ raw_step = current.get("checkpoint_step")
332
+ # `int()` does not just reject what it cannot read -- it silently COERCES. `true` becomes 1,
333
+ # `false` becomes 0, and `1.5` truncates to 1, none of them raising. a step this client cannot
334
+ # read as an exact whole number is an unreadable record, not checkpoint 1: reading it as a
335
+ # number either suppresses the warning (deploying step-1 against a `true`) or names a
336
+ # checkpoint that was never live. bool is checked first because it is a subclass of int.
337
+ if isinstance(raw_step, bool):
338
+ return None
339
+ if isinstance(raw_step, float) and not raw_step.is_integer():
340
+ return None
341
+ try:
342
+ served_step = None if raw_step is None else int(raw_step)
343
+ except (TypeError, ValueError, OverflowError):
344
+ # a proxy or older plane can answer 2xx with a step this client cannot read. that is an
345
+ # unreadable current record like any other, NOT a reason to fail the deploy: leaving the
346
+ # conversion unguarded let an advisory read traceback out of the command it decorates.
347
+ # all three arms are reachable from one JSON body: `json.loads` accepts the non-standard
348
+ # `Infinity`/`NaN` literals, and int() answers those with OverflowError and ValueError
349
+ # respectively -- so catching only the obvious two still crashed the deploy.
350
+ return None
351
+ if served_step == requested_step:
352
+ return None
353
+ reach_displaced = ""
354
+ # the record being displaced carries the one identifier that survives the alias move, so name
355
+ # it whenever it is there. `step-N` is not a substitute: it is rejected outright on a plane
356
+ # without `chat_step_selector_v1`, and after this deploy the listing shows only the NEW record
357
+ # -- `public_deployment` strips `previous_deployment` (flash/serve/urls.py) -- so a revision
358
+ # not printed here is not recoverable from anywhere afterwards.
359
+ revision = str(current.get("adapter_revision") or "").strip()
360
+ if served_step is None:
361
+ # the displaced checkpoint is the FINAL adapter, and `_parse_chat_target` accepts only a
362
+ # bare run id, `RUN/step-N`, or a full immutable revision -- there is no `/final`
363
+ # selector. once the alias moves, `step-N` addresses the incoming checkpoint and the bare
364
+ # id is the thing that just changed, so the generic advice cannot reach the final adapter
365
+ # at all. its immutable revision can, and the record being displaced carries one.
366
+ reach_displaced = (
367
+ f" the displaced final adapter has no `/final` selector; reach it by its immutable "
368
+ f"revision `{revision}`."
369
+ if revision
370
+ # without a revision on the record there is nothing to hand the user, and deferring
371
+ # them to a later command would be worse than saying so: `client.deploy` fires as soon
372
+ # as this prints, and the deployments listing then shows only the NEW record --
373
+ # `public_deployment` strips `previous_deployment` (flash/serve/urls.py), so the
374
+ # displaced revision is not in it. promising a selector that the next command cannot
375
+ # produce is the one outcome worse than admitting there is none.
376
+ else (
377
+ " the displaced final adapter has no `/final` selector and this plane did not "
378
+ "report its immutable revision, so it will not be addressable after this deploy; "
379
+ "undeploy and redeploy it to serve it again."
380
+ )
381
+ )
382
+ elif revision:
383
+ # a numbered checkpoint keeps its `step-N` selector, but only on a plane that advertises
384
+ # `chat_step_selector_v1`; where it does not, the qualified advice above leaves the user
385
+ # holding no identifier at all. this is that identifier, and this is the last moment it
386
+ # can be printed.
387
+ reach_displaced = f" the displaced checkpoint's immutable revision is `{revision}`."
388
+ return (
389
+ f"{base_run_id} currently serves {_served_step_label(served_step)}; deploying "
390
+ f"{_served_step_label(requested_step)} moves that shared model id onto the new "
391
+ f"checkpoint, {tail}{reach_displaced}"
392
+ )
393
+
394
+
192
395
  def _deployment_attempt_failed(requested: dict, final: dict) -> bool:
193
396
  """True when the requested revision is not the one now served.
194
397
 
@@ -229,8 +432,18 @@ def cmd_deploy(args) -> int:
229
432
  file=sys.stderr,
230
433
  )
231
434
  return 1
232
- base_run_id, _step = parsed
435
+ base_run_id, step = parsed
233
436
  client = _commands().client_from_config()
437
+ # before the POST: after it the alias has already moved, and a warning about a checkpoint that
438
+ # is no longer served reads as history rather than a decision the reader still has. a dry run
439
+ # registers nothing, so it displaces nothing and gets no warning.
440
+ if not args.dry_run:
441
+ alias_warning = _alias_move_warning(client, base_run_id, step)
442
+ if alias_warning:
443
+ print(
444
+ render.warn(alias_warning) if render.styled() else f"warning: {alias_warning}",
445
+ file=sys.stderr,
446
+ )
234
447
  dep = client.deploy(args.run_id, dry_run=args.dry_run)
235
448
  wait_seconds = getattr(args, "wait", None)
236
449
  # a dry run creates no deployment to poll for, so --wait has nothing to observe. test against
@@ -13,9 +13,11 @@ from __future__ import annotations
13
13
 
14
14
  import contextlib
15
15
  import inspect
16
+ import sys
16
17
 
17
18
  from flash.cli.commands.env.test_evaluations import _evaluation_example
18
- from flash.envs.evaluations import EvalCase, EvalResult
19
+ from flash.cli.ui import render
20
+ from flash.envs.evaluations import EvalCase, EvalResult, _episode_grading_enabled
19
21
 
20
22
 
21
23
  def _eval_module():
@@ -34,7 +36,7 @@ def _grades_episodes(suite) -> bool:
34
36
  Keying off the environment scored the wrong turn there and turned a well-formed first action
35
37
  into an error, so the suite has to say so itself.
36
38
  """
37
- return bool(getattr(suite, "grades_episodes", False))
39
+ return _episode_grading_enabled(suite)
38
40
 
39
41
 
40
42
  def _drive_episode(client, target: str, environment, case: EvalCase, args) -> dict | str:
@@ -123,7 +125,14 @@ def _effective_turn_cap(environment, state: dict) -> int:
123
125
 
124
126
 
125
127
  def _score_episode_case(
126
- suite, case: EvalCase, case_id: str, state: dict, *, thinking: bool = False
128
+ suite,
129
+ case: EvalCase,
130
+ case_id: str,
131
+ state: dict,
132
+ *,
133
+ scorer,
134
+ state_style: str | None,
135
+ thinking: bool = False,
127
136
  ) -> EvalResult:
128
137
  """Grade a finished episode through the suite's own scorer.
129
138
 
@@ -134,18 +143,19 @@ def _score_episode_case(
134
143
  `reward(completion, example, state)`, which is what reaches the SDK's `score_episodes`.
135
144
 
136
145
  `EvalSuite.score(case, response)` is the published two-argument contract, so state is offered
137
- only to a suite that accepts it, detected by signature rather than by try/except: a TypeError
138
- raised INSIDE a scorer that does accept state would otherwise be silently retried as a
139
- two-argument call and graded on the wrong text.
146
+ only to a suite that accepts it. The caller resolves one scorer and signature style for the
147
+ whole suite rather than retrying on TypeError: an error raised INSIDE a state-aware scorer must
148
+ not be retried as a two-argument call and graded on the wrong text.
140
149
  """
141
150
  response = state.get("response_text")
142
151
  if not isinstance(response, str):
143
152
  turns = state.get("turns") or []
144
153
  response = str(turns[-1]) if turns else ""
145
154
  eval_module = _eval_module()
146
- style = _state_argument(getattr(suite, "score", None))
147
- if style is None:
148
- return eval_module._score_case(suite, case, case_id, response, thinking=thinking)
155
+ if state_style is None:
156
+ return eval_module._score_case(
157
+ suite, case, case_id, response, thinking=thinking, scorer=scorer
158
+ )
149
159
  return eval_module._score_case(
150
160
  suite,
151
161
  case,
@@ -153,7 +163,8 @@ def _score_episode_case(
153
163
  response,
154
164
  thinking=thinking,
155
165
  state=state,
156
- state_keyword=style == "keyword",
166
+ state_keyword=state_style == "keyword",
167
+ scorer=scorer,
157
168
  )
158
169
 
159
170
 
@@ -173,27 +184,45 @@ def _state_argument(score) -> str | None:
173
184
  except (TypeError, ValueError):
174
185
  # builtins and C callables expose no signature; treat them as the published contract.
175
186
  return None
176
- named_state = next((p for p in parameters if p.name == "state"), None)
177
- if named_state is not None and named_state.kind in (
178
- inspect.Parameter.KEYWORD_ONLY,
179
- inspect.Parameter.POSITIONAL_OR_KEYWORD,
180
- ):
181
- # By keyword even where positional would also bind: it cannot land on the wrong parameter.
182
- return "keyword"
183
- # Checked before `*args`, since a scorer with both can take `state=` but one with only
184
- # `*args` cannot.
185
- if any(p.kind is inspect.Parameter.VAR_KEYWORD for p in parameters):
186
- return "keyword"
187
- if any(p.kind is inspect.Parameter.VAR_POSITIONAL for p in parameters):
188
- return "positional"
189
187
  positional = [
190
- p
191
- for p in parameters
192
- if p.kind in (inspect.Parameter.POSITIONAL_ONLY, inspect.Parameter.POSITIONAL_OR_KEYWORD)
188
+ parameter
189
+ for parameter in parameters
190
+ if parameter.kind
191
+ in (inspect.Parameter.POSITIONAL_ONLY, inspect.Parameter.POSITIONAL_OR_KEYWORD)
193
192
  ]
194
- # (case, response) is the published contract; a third positional is the episode state. This
195
- # also catches a positional-only `state`, which the named check above deliberately skips.
196
- return "positional" if len(positional) >= 3 else None
193
+ named_state = next((parameter for parameter in parameters if parameter.name == "state"), None)
194
+ if named_state is not None:
195
+ if named_state.kind is inspect.Parameter.POSITIONAL_ONLY:
196
+ return "positional" if positional.index(named_state) == 2 else None
197
+ if named_state.kind in (
198
+ inspect.Parameter.KEYWORD_ONLY,
199
+ inspect.Parameter.POSITIONAL_OR_KEYWORD,
200
+ ):
201
+ # by keyword even where positional would also bind: it cannot land on the wrong parameter.
202
+ return "keyword"
203
+ # checked before `*args`, since a scorer with both can take `state=` but one with only
204
+ # `*args` cannot.
205
+ if any(parameter.kind is inspect.Parameter.VAR_KEYWORD for parameter in parameters):
206
+ return "keyword"
207
+ if any(parameter.kind is inspect.Parameter.VAR_POSITIONAL for parameter in parameters):
208
+ # scorer(case, response, state) reaches *args when the signature has no fixed third slot.
209
+ # zero, one, or two regular positional parameters can all bind that call.
210
+ return "positional" if len(positional) <= 2 else None
211
+ return None
212
+
213
+
214
+ def _warn_if_episode_state_is_hidden(suite, state_style: str | None) -> None:
215
+ """Warn once when full-episode work feeds a scorer that cannot see the transcript."""
216
+ if state_style is not None:
217
+ return
218
+ message = (
219
+ f"suite {getattr(suite, 'name', 'evaluation')!r} sets grades_episodes = True; "
220
+ "each episode will still be played out with one generation per turn, but the scorer "
221
+ "will receive only the episode's final response text, not the transcript. Add a third "
222
+ "`state` argument to "
223
+ "`score(case, response, state)` to grade the transcript."
224
+ )
225
+ print(render.warn(message) if render.styled() else f"warning: {message}", file=sys.stderr)
197
226
 
198
227
 
199
228
  def _run_episode_cases(
@@ -220,6 +249,9 @@ def _run_episode_cases(
220
249
  )
221
250
  for case_id in case_ids
222
251
  )
252
+ scorer = getattr(suite, "score", None)
253
+ state_style = _state_argument(scorer)
254
+ _warn_if_episode_state_is_hidden(suite, state_style)
223
255
  results = []
224
256
  # The adapter defaults to `thinking = False` (flash/envs/adapter.py), and with it off
225
257
  # `_scored_turn_text` returns the turn unstripped -- so `state["response_text"]` keeps its
@@ -237,7 +269,17 @@ def _run_episode_cases(
237
269
  if isinstance(outcome, str):
238
270
  results.append(eval_module._generation_error(case_id, outcome))
239
271
  continue
240
- results.append(_score_episode_case(suite, case, case_id, outcome, thinking=thinking))
272
+ results.append(
273
+ _score_episode_case(
274
+ suite,
275
+ case,
276
+ case_id,
277
+ outcome,
278
+ scorer=scorer,
279
+ state_style=state_style,
280
+ thinking=thinking,
281
+ )
282
+ )
241
283
  return tuple(results)
242
284
 
243
285
 
@@ -162,6 +162,7 @@ def _score_case(
162
162
  thinking: bool = False,
163
163
  state=None,
164
164
  state_keyword: bool = False,
165
+ scorer=None,
165
166
  ) -> EvalResult:
166
167
  """Grade one response on the caller's thread.
167
168
 
@@ -172,7 +173,8 @@ def _score_case(
172
173
  `episode._score_episode_case`); single-turn scoring keeps the two-argument contract.
173
174
  `state_keyword` says which way that suite's signature can take it -- `**kwargs` and
174
175
  keyword-only scorers reject a third positional, `*args` scorers reject the keyword -- so the
175
- caller decides, having read the signature.
176
+ caller decides, having read the signature. Episode scoring also passes the exact callable it
177
+ inspected, so a descriptor cannot change shape between capability detection and invocation.
176
178
 
177
179
  The scorer grades the stripped answer; the RESULT records the raw generation. Stripping for the
178
180
  scorer must not shorten what is recorded, on the error path least of all -- a failed case is
@@ -182,12 +184,13 @@ def _score_case(
182
184
  try:
183
185
  scored_text = _scored_response(response, thinking=thinking)
184
186
  recorded_response = getattr(scored_text, "raw", response)
187
+ score = suite.score if scorer is None else scorer
185
188
  if state is None:
186
- scored = suite.score(case, scored_text)
189
+ scored = score(case, scored_text)
187
190
  elif state_keyword:
188
- scored = suite.score(case, scored_text, state=state)
191
+ scored = score(case, scored_text, state=state)
189
192
  else:
190
- scored = suite.score(case, scored_text, state)
193
+ scored = score(case, scored_text, state)
191
194
  return normalize_eval_result(case, recorded_response, scored, case_id=case_id)
192
195
  except (Exception, SystemExit) as exc:
193
196
  return EvalResult(
@@ -138,12 +138,14 @@ Given the opening prompt, does the model emit the single integer `step_episode`
138
138
  to advance the game? That is a real held-out check of the action format the episode
139
139
  depends on, and it is the honest scope of a single-shot evaluation.
140
140
 
141
- To grade a finished transcript instead, set `grades_episodes = True` on the suite.
142
- `env eval` then plays each case out against the deployed model -- generating, stepping
143
- the environment, and repeating to `max_episode_turns` -- and scores the resulting
144
- transcript. Such a suite needs cases the environment can actually advance (the cases
145
- below carry no `output`, so `step_episode` has no secret to compare against), and each
146
- case then costs one generation per turn rather than one in total.
141
+ To grade a finished transcript instead, set `grades_episodes = True` on the suite
142
+ and define `score(self, case, response, state)`. `env eval` then plays each case out
143
+ against the deployed model -- generating, stepping the environment, and repeating to
144
+ `max_episode_turns` -- and passes the resulting transcript in `state`; without that
145
+ argument the scorer receives only the episode's final response text. Such a suite
146
+ needs cases the environment can actually advance (the cases below carry no `output`,
147
+ so `step_episode` has no secret to compare against), and each case then costs one
148
+ generation per turn rather than one in total.
147
149
 
148
150
  Do NOT grade these by calling `environment.reward(response, example)`: with no episode
149
151
  state that call scores an empty transcript, so an unrelated answer can score 1.0 and
@@ -289,7 +291,7 @@ class StarterMultiTurnEnv(EnvironmentMultiTurn):
289
291
  # Advance the world after one assistant action. Return done=True to end the
290
292
  # episode, or append an observation message and keep going.
291
293
  # `messages` already ends with this action: messages[-1]["content"] is
292
- # `assistant_response`. If you rebuild state by replaying the transcript, replay
294
+ # `assistant_response`. if you rebuild state by replaying the transcript, replay
293
295
  # `messages[:-1]` and apply `assistant_response` once, or you apply it twice.
294
296
  try:
295
297
  guess = int(assistant_response.strip().split()[0])