Debug Workflow
Load the Relevant Contracts
Always read Tier 1: ../../knowledge/constraints.md, ../../knowledge/architecture.md, and
../../knowledge/philosophy.md. Then route by symptom:
| Symptom or area |
Also read |
| Wrong gradients, ratio drift, bad output |
../../knowledge/topics/train_inference_consistency.md, ../../knowledge/topics/parity_testing.md |
| Dtype mismatch, overflow, flat loss or KL |
../../knowledge/topics/dtype_precision.md, ../../knowledge/topics/autocast_param_swap.md |
| Missing component, wrong device, lazy load, wrap/OOM |
../../knowledge/topics/component_runtime.md |
| Multi-component rollout or replay |
../../knowledge/topics/structured_trajectory.md |
| Variant, role cadence, optimizer group, Muon, role checkpoint |
../../knowledge/topics/component_variants.md |
| Finite dataset, target encoding, SFT/offline DPO |
../../../guidance/workflow.md, ../../../guidance/datasets.md |
Classify the Execution Path First
Resolve the trainer and its algorithm-specific TrainingArguments; their immutable
ExecutionContract values must be equal.
| Composition |
Expected path |
generation + runtime_reward |
sample() -> feedback/reward -> advantage -> optimize() |
generation + none |
sample() -> optimize(); no training reward/advantage stage |
dataset + none |
Exhaust one official finite DistributedSampler loader through optimize_batch() |
Do not infer execution mode from batch fields. Track optimizer_step independently from
rollout_iteration or data_epoch; a dataset epoch advances only after clean loader exhaustion.
Quick Path
Use when the failure is deterministic and the stack trace identifies one local contract breach.
- Reproduce it with the smallest representative test or config.
- Trace the owning boundary and relevant constraint.
- Add a regression that fails for the same reason.
- Apply the narrow fix and run affected contract tests.
- Run
/ff-review before committing.
If the cause is uncertain, distributed, numerical, or survives one focused attempt, use the full
protocol.
Full Protocol
1. Establish the Failure Boundary
- Read every rank's complete traceback and first causal error.
- Record the resolved trainer, adapter, execution contract, model I/O contract, backend, optimizer
types, finetune type, dtype policy, and checkpoint mode.
- Compare against a working path one variable at a time, including YAML and backend config.
- Identify when failure occurs: preflight, native component load, preprocessing, bundle prepare,
proxy-routed forward, acquisition, optimizer step, save, or resume.
- Check recent changes with a focused file/commit diff; do not assume temporal correlation is cause.
2. Check Ownership Invariants
Dataset acquisition
- Uses PyTorch's official
DistributedSampler, even at one rank, and calls
set_epoch(data_epoch).
- Uses explicit positive
gradient_accumulation_steps; rank-local batch count closes every
accumulation window without an implicit flush.
- Caches prompt/input conditions only. Target, chosen, and rejected media is decoded and encoded on
demand.
- Calls
prepare_condition_state() once per batch. Offline DPO reuses that object, schedule, noise,
and one reference scope across both arms.
- Applies the adapter's complete
offline_training_forward_overrides, not rollout CFG semantics.
Component runtime and loading
- Resolve membership with
has_component, get_component, or _require_component, never
hasattr(adapter, name).
- Keep canonical components, prepared/replacement overrides, declared specs, materialized modules,
optional
None, and pseudo aliases distinct.
materialize_components(None) means already-materialized modules, not all lazy declarations.
- Trace logical names to physical roots through
ModelLoadCoordinator; adapters/trainers must not
reproduce FSDP loading state or broadcast weights directly.
- All target and frozen-but-shardable routes enter one
ModelBundle with one optimizer prepare
root. Adapter forwards after prepare route through RoutedComponentProxy.
- For FSDP OOM, inspect bundle-exposed
_no_split_modules/_repeated_blocks, wrap classes, adapter
memory capabilities, checkpoint replay, unshard stream, and backward prefetch before shrinking
the workload.
Variants, optimizers, and distributed plans
- A temporal reference/EMA/snapshot is not a live component variant.
- Variants are declared before prepare; role parameter and optimizer-group ownership is disjoint and
exhaustive.
- Do not assume one group per role: Muon uses matrices plus an optional AdamW remainder inside one
CompositeOptimizer root.
- Reject ZeRO-3. Reject Muon before model loading when its PyTorch API is absent or the backend is
DeepSpeed/FSDP1. Multi-role DeepSpeed requires ZeRO-1/2. Multi-role FSDP2 requires
use_orig_params=True; after prepare, registry and optimizer references must point to the
DTensor-backed parameters owned by the prepared model root.
- Activation checkpointing has one owner. FSDP2 full policy is normalized to backend ownership;
selective model checkpointing is rejected. Inspect adapter-owned in-forward checkpointing only
when the adapter explicitly opts in.
Checkpoint and exact resume
- Model-only export scope and resumable state scope are different. Resumable multi-role saves include
training-only roles, role counters, optimizer ownership, and variant snapshots.
- Validate variant/runtime metadata before Accelerate mutates prepared state.
- Exact identity covers changed objective, model/backend/optimizer semantics, realized data order,
and replayed evaluation configuration; cadence and resume location remain operational controls.
- Preserve all-rank phase symmetry and atomic publication ordering.
Numerical and reward paths
- Wrap each policy/reference/EMA forward in its own autocast region when weights can change in place.
- Consume trajectories only through adapter bridge methods and authoritative component order.
- A partial cross-rank gather must union the concrete sample class's
reconstruction_required_fields before reconstruction. This is independent of reward
required_fields and collation _shared_fields.
- Pointwise rewards return one finite value per actual input chunk, which may be smaller than
batch_size; groupwise rewards preserve complete unique_id order.
- Per-dataset reward applicability is framework-owned; model NaN/Inf is an error, not a routing
sentinel.
3. Test One Falsifiable Hypothesis
State the proposed cause, the observation that would disprove it, and the smallest experiment that
separates it from alternatives. Add instrumentation when confidence is below 80%. Avoid speculative
fallbacks or several behavioral changes in one experiment.
4. Fix and Verify in Scope
- Write the regression first when practical.
- Fix the authoritative owner rather than patching downstream consumers.
- Verify the narrow unit contract, then affected compositions:
- execution kernel: GRPO, a reward-free generation trainer, and SFT/offline DPO as applicable;
- adapter/trajectory: legacy single-component and structured multimodal paths;
- runtime/loading: the affected classic/modular/pseudo runtime and supported backends;
- variants/optimizer: single-role AdamW plus multi-role/Muon cases when touched;
- checkpoint: model-only round trip and exact-state resume when touched.
- Test at least two adapters only when the changed abstraction is shared across adapters.
5. Capture the Fix
Follow ../../knowledge/topics/fix_patterns.md: record symptom, root cause, fix, lesson, related
constraint, test evidence, and commit. Update Tier 1 only when the fix establishes a durable
cross-module invariant.
Three-Strike Rule
After three failed approaches to the same cause, stop patching, document evidence and rejected
hypotheses, reassess the ownership model, and request review before continuing.
1---2name: ff-debug3description: Debug Flow-Factory crashes, hangs, OOMs, numerical failures, finite-loader errors, component routing, distributed preparation, optimizer roles, and checkpoint/resume mismatches. Use for bug fixing or unexpected training behavior.4---56# Debug Workflow78## Load the Relevant Contracts910Always read Tier 1: `../../knowledge/constraints.md`, `../../knowledge/architecture.md`, and11`../../knowledge/philosophy.md`. Then route by symptom:1213| Symptom or area | Also read |14|---|---|15| Wrong gradients, ratio drift, bad output | `../../knowledge/topics/train_inference_consistency.md`, `../../knowledge/topics/parity_testing.md` |16| Dtype mismatch, overflow, flat loss or KL | `../../knowledge/topics/dtype_precision.md`, `../../knowledge/topics/autocast_param_swap.md` |17| Missing component, wrong device, lazy load, wrap/OOM | `../../knowledge/topics/component_runtime.md` |18| Multi-component rollout or replay | `../../knowledge/topics/structured_trajectory.md` |19| Variant, role cadence, optimizer group, Muon, role checkpoint | `../../knowledge/topics/component_variants.md` |20| Finite dataset, target encoding, SFT/offline DPO | `../../../guidance/workflow.md`, `../../../guidance/datasets.md` |2122## Classify the Execution Path First2324Resolve the trainer and its algorithm-specific `TrainingArguments`; their immutable25`ExecutionContract` values must be equal.2627| Composition | Expected path |28|---|---|29| `generation + runtime_reward` | `sample()` -> feedback/reward -> advantage -> `optimize()` |30| `generation + none` | `sample()` -> `optimize()`; no training reward/advantage stage |31| `dataset + none` | Exhaust one official finite `DistributedSampler` loader through `optimize_batch()` |3233Do not infer execution mode from batch fields. Track `optimizer_step` independently from34`rollout_iteration` or `data_epoch`; a dataset epoch advances only after clean loader exhaustion.3536## Quick Path3738Use when the failure is deterministic and the stack trace identifies one local contract breach.39401. Reproduce it with the smallest representative test or config.412. Trace the owning boundary and relevant constraint.423. Add a regression that fails for the same reason.434. Apply the narrow fix and run affected contract tests.445. Run `/ff-review` before committing.4546If the cause is uncertain, distributed, numerical, or survives one focused attempt, use the full47protocol.4849## Full Protocol5051### 1. Establish the Failure Boundary5253- Read every rank's complete traceback and first causal error.54- Record the resolved trainer, adapter, execution contract, model I/O contract, backend, optimizer55 types, finetune type, dtype policy, and checkpoint mode.56- Compare against a working path one variable at a time, including YAML and backend config.57- Identify when failure occurs: preflight, native component load, preprocessing, bundle prepare,58 proxy-routed forward, acquisition, optimizer step, save, or resume.59- Check recent changes with a focused file/commit diff; do not assume temporal correlation is cause.6061### 2. Check Ownership Invariants6263#### Dataset acquisition6465- Uses PyTorch's official `DistributedSampler`, even at one rank, and calls66 `set_epoch(data_epoch)`.67- Uses explicit positive `gradient_accumulation_steps`; rank-local batch count closes every68 accumulation window without an implicit flush.69- Caches prompt/input conditions only. Target, chosen, and rejected media is decoded and encoded on70 demand.71- Calls `prepare_condition_state()` once per batch. Offline DPO reuses that object, schedule, noise,72 and one reference scope across both arms.73- Applies the adapter's complete `offline_training_forward_overrides`, not rollout CFG semantics.7475#### Component runtime and loading7677- Resolve membership with `has_component`, `get_component`, or `_require_component`, never78 `hasattr(adapter, name)`.79- Keep canonical components, prepared/replacement overrides, declared specs, materialized modules,80 optional `None`, and pseudo aliases distinct.81- `materialize_components(None)` means already-materialized modules, not all lazy declarations.82- Trace logical names to physical roots through `ModelLoadCoordinator`; adapters/trainers must not83 reproduce FSDP loading state or broadcast weights directly.84- All target and frozen-but-shardable routes enter one `ModelBundle` with one optimizer prepare85 root. Adapter forwards after prepare route through `RoutedComponentProxy`.86- For FSDP OOM, inspect bundle-exposed `_no_split_modules`/`_repeated_blocks`, wrap classes, adapter87 memory capabilities, checkpoint replay, unshard stream, and backward prefetch before shrinking88 the workload.8990#### Variants, optimizers, and distributed plans9192- A temporal reference/EMA/snapshot is not a live component variant.93- Variants are declared before prepare; role parameter and optimizer-group ownership is disjoint and94 exhaustive.95- Do not assume one group per role: Muon uses matrices plus an optional AdamW remainder inside one96 `CompositeOptimizer` root.97- Reject ZeRO-3. Reject Muon before model loading when its PyTorch API is absent or the backend is98 DeepSpeed/FSDP1. Multi-role DeepSpeed requires ZeRO-1/2. Multi-role FSDP2 requires99 `use_orig_params=True`; after prepare, registry and optimizer references must point to the100 DTensor-backed parameters owned by the prepared model root.101- Activation checkpointing has one owner. FSDP2 full policy is normalized to backend ownership;102 selective model checkpointing is rejected. Inspect adapter-owned in-forward checkpointing only103 when the adapter explicitly opts in.104105#### Checkpoint and exact resume106107- Model-only export scope and resumable state scope are different. Resumable multi-role saves include108 training-only roles, role counters, optimizer ownership, and variant snapshots.109- Validate variant/runtime metadata before Accelerate mutates prepared state.110- Exact identity covers changed objective, model/backend/optimizer semantics, realized data order,111 and replayed evaluation configuration; cadence and resume location remain operational controls.112- Preserve all-rank phase symmetry and atomic publication ordering.113114#### Numerical and reward paths115116- Wrap each policy/reference/EMA forward in its own autocast region when weights can change in place.117- Consume trajectories only through adapter bridge methods and authoritative component order.118- A partial cross-rank gather must union the concrete sample class's119 `reconstruction_required_fields` before reconstruction. This is independent of reward120 `required_fields` and collation `_shared_fields`.121- Pointwise rewards return one finite value per actual input chunk, which may be smaller than122 `batch_size`; groupwise rewards preserve complete `unique_id` order.123- Per-dataset reward applicability is framework-owned; model NaN/Inf is an error, not a routing124 sentinel.125126### 3. Test One Falsifiable Hypothesis127128State the proposed cause, the observation that would disprove it, and the smallest experiment that129separates it from alternatives. Add instrumentation when confidence is below 80%. Avoid speculative130fallbacks or several behavioral changes in one experiment.131132### 4. Fix and Verify in Scope133134- Write the regression first when practical.135- Fix the authoritative owner rather than patching downstream consumers.136- Verify the narrow unit contract, then affected compositions:137 - execution kernel: GRPO, a reward-free generation trainer, and SFT/offline DPO as applicable;138 - adapter/trajectory: legacy single-component and structured multimodal paths;139 - runtime/loading: the affected classic/modular/pseudo runtime and supported backends;140 - variants/optimizer: single-role AdamW plus multi-role/Muon cases when touched;141 - checkpoint: model-only round trip and exact-state resume when touched.142- Test at least two adapters only when the changed abstraction is shared across adapters.143144### 5. Capture the Fix145146Follow `../../knowledge/topics/fix_patterns.md`: record symptom, root cause, fix, lesson, related147constraint, test evidence, and commit. Update Tier 1 only when the fix establishes a durable148cross-module invariant.149150## Three-Strike Rule151152After three failed approaches to the same cause, stop patching, document evidence and rejected153hypotheses, reassess the ownership model, and request review before continuing.