Explicit pool claim/reset: one trainer call owns one pool epoch - #5
Merged
Conversation
Contributor
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
⚙️ Control Options:
|
Co-Authored-By: jason.mancuso@modal.com <jvmncs@gmail.com>
After rebasing onto main (which includes #4, composing a multi-version catch-up into a single engine reload), two reconcile tests still asserted the pre-#4 per-version apply accounting: - local_disagg/harness_test.py (added by this PR): a cold latecomer catching up v1..v2 now records a single composed apply [2], not [1, 2]. - standalone_rollouts/provider_test.py (pre-existing; #4 changed the behavior but did not update this cookbook test): same one-apply tail. The served version / run_id invariants are unchanged; only the per-apply accounting moved. No production code change. Co-Authored-By: jason.mancuso@modal.com <jvmncs@gmail.com>
devin-ai-integration
Bot
force-pushed
the
devin/1782792683-pool-claim-reset
branch
from
June 30, 2026 07:03
b5ddb3f to
de61cce
Compare
jvmncs
added a commit
that referenced
this pull request
Jul 4, 2026
* Remove dead and speculative code from the core library - generate_rollout compatibility wrapper and the unreachable per-request version-pinning branch (the live hook contract never supplies rollout_id); the request hook now does only what runs: retry budget + session affinity - test-only helpers: transition_artifact_paths, parse_extra_key_version, validate_policy (redundant with request_context) - register_routes extension point nothing passes - version error helpers inlined into evaluate_version_policy - unused top-level re-export facade in stitch/__init__.py * Remove dangling cookbook artifacts - unreachable per-request version-pin branch in the standalone slime hook (the hook contract never supplies rollout_id; announce_and_wait already gates staleness) + its helper, config knob, and tests - megatron_r3_num_out_tokens.patch: never applied, the fix is baked inline * Dedup the slime/miles twin adapter modules - bulletin_hooks reads generic DELTA_APP_NAME / DELTA_SERVER_CLS_NAME env fallbacks; per-recipe hooks.py become pure re-export shims kept only because configs reference them by dotted string - per-recipe helpers.py shrink to the real per-recipe axes (sidecar module, model-script attr, wake mode) + one-line wrappers; miles-only materialize_node_local_yaml and start_host_mem_monitor move out of the shared trainer_helpers into miles_disagg/helpers - serving wrappers take the shared trainer_repo_* kwarg names; the shared builder computes the cookbook mount dir itself * De-noise prose: drop provenance labels, war stories, and docstring essays Keep the behavioral fact, drop the provenance: external PR/issue labels (slime PR #5, radixark/miles#1261, P0.1), incident anecdotes, milestone roadmap prose (M1/M2/M3), and layout/design essays compressed to what the code needs the reader to know. Pinned SHAs stay; their changelog trailers go. * Trim READMEs and packaging - root README: document all four cookbook recipes; fix the nonexistent slime extra claim - miles_disagg README: compress the fork changelog and bring-up checklist, fold the GLM-4.5-Air section into a variant note, point at the fork for the convert tools, document _spawn_into_deployed - standalone_rollouts README: compress the compatibility spec-dump and the SLIME-harness tail - slime_disagg README: merge the redundant Protocol notes into the run section - pyproject: drop uvicorn from the sglang extra (packaged code never imports it; Modal images install it explicitly)
jvmncs
added a commit
that referenced
this pull request
Jul 20, 2026
* Explicit pool claim/reset: one trainer call owns one pool epoch * Align reconcile tests with #4 composed-reload semantics After rebasing onto main (which includes #4, composing a multi-version catch-up into a single engine reload), two reconcile tests still asserted the pre-#4 per-version apply accounting: - local_disagg/harness_test.py (added by this PR): a cold latecomer catching up v1..v2 now records a single composed apply [2], not [1, 2]. - standalone_rollouts/provider_test.py (pre-existing; #4 changed the behavior but did not update this cookbook test): same one-apply tail. The served version / run_id invariants are unchanged; only the per-apply accounting moved. No production code change.
jvmncs
added a commit
that referenced
this pull request
Jul 20, 2026
* Remove dead and speculative code from the core library - generate_rollout compatibility wrapper and the unreachable per-request version-pinning branch (the live hook contract never supplies rollout_id); the request hook now does only what runs: retry budget + session affinity - test-only helpers: transition_artifact_paths, parse_extra_key_version, validate_policy (redundant with request_context) - register_routes extension point nothing passes - version error helpers inlined into evaluate_version_policy - unused top-level re-export facade in stitch/__init__.py * Remove dangling cookbook artifacts - unreachable per-request version-pin branch in the standalone slime hook (the hook contract never supplies rollout_id; announce_and_wait already gates staleness) + its helper, config knob, and tests - megatron_r3_num_out_tokens.patch: never applied, the fix is baked inline * Dedup the slime/miles twin adapter modules - bulletin_hooks reads generic DELTA_APP_NAME / DELTA_SERVER_CLS_NAME env fallbacks; per-recipe hooks.py become pure re-export shims kept only because configs reference them by dotted string - per-recipe helpers.py shrink to the real per-recipe axes (sidecar module, model-script attr, wake mode) + one-line wrappers; miles-only materialize_node_local_yaml and start_host_mem_monitor move out of the shared trainer_helpers into miles_disagg/helpers - serving wrappers take the shared trainer_repo_* kwarg names; the shared builder computes the cookbook mount dir itself * De-noise prose: drop provenance labels, war stories, and docstring essays Keep the behavioral fact, drop the provenance: external PR/issue labels (slime PR #5, radixark/miles#1261, P0.1), incident anecdotes, milestone roadmap prose (M1/M2/M3), and layout/design essays compressed to what the code needs the reader to know. Pinned SHAs stay; their changelog trailers go. * Trim READMEs and packaging - root README: document all four cookbook recipes; fix the nonexistent slime extra claim - miles_disagg README: compress the fork changelog and bring-up checklist, fold the GLM-4.5-Air section into a variant note, point at the fork for the convert tools, document _spawn_into_deployed - standalone_rollouts README: compress the compatibility spec-dump and the SLIME-harness tail - slime_disagg README: merge the redundant Protocol notes into the run section - pyproject: drop uvicorn from the sglang extra (packaged code never imports it; Modal images install it explicitly)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Makes pool ownership explicit and restart-safe: one trainer launch ↔ one run ↔ one pool epoch. Today the pool's reset-to-base is inferred from a
run_idmismatch on the first publish, and two cookbooks writelatesttwo different ways — so a crash-restart that reused arun_id(derived from a dir basename) could leave the pointer pinned to a dead incarnation's high-water version, and "who owns pool state" was genuinely ambiguous.This PR introduces a single pointer-control vocabulary all writers share, an explicit
claim(write the empty pointer at launch), and a minimal no-Modal harness that pins the invariants down with tests.Shared decision in
protocol.pyOne rule both writer paths go through, so they can't bake in divergent semantics:
Board: guarded writers (
bulletin.py)claimresets every replica to base before any delta. The reconcile path is unchanged — the pool still resets on arun_idswitch viaWeightSyncManager._switch_run(re-materialize base under the commit gate).Consolidation (de-divergence)
advance_latest_decisionnow delegates todecide_pointer_move(only parses the wire identity + shapes the error dict).modal_serve.advance_towrites throughboard.write_latestinstead of a third rawlatestwrite.commit_and_wakepublishes viaboard.advance(monotonic; new-run first publish forks at base) instead of an unconditionalwrite_latest; addsclaim_pool(rank-0 launch hook: claim → commit volume → wake). slime/mileshooks.pyget thinclaim_poolwrappers and theirmodal_trainlaunches call it before the trainer starts publishing._run_idis now required (passed viacustom_config) — the dir-basename fallback (the reuse hazard) is gone. Both disagg trainers already mint a freshuuid4per launch.A restart is now just a new epoch: a fresh
run_idclaims and resets the pool; reusing arun_idraisesPointerRewindinstead of silently serving stale weights.Minimal config:
cookbook/local_disagg/No Modal, no slime/miles, no GPUs — a filesystem board, an in-memory pool (
MemoryEngine+ realWeightSyncManager), and a trainer-as-writer using the sameclaim/advance/reconcile primitives.harness_test.pyasserts the invariants:run_idis rejected as a rewind; a freshrun_idclaims cleanTesting
uv run python -m pytest -q→ 98 passed (was 82; +16 new tests acrossprotocol_test,bulletin_test,frontdoor_test, and the newharness_test). Modal-only cookbook files (modal_train.py, hooks,modal_serve.py)py_compile-check clean. No lint config or CI workflows exist in the repo; pytest is the gate.Link to Devin session: https://modal.devinenterprise.com/sessions/b0d6110c71924c24943bcb5cea1eb5f4
Requested by: @jvmncs