Repository navigation
Auto-revert deletes only final_model and leaves the rejected weights in checkpoint-N (CR-A02-003) #382
Description
Wave 1 · theme D1-3: Revert, approval and GDPR erasure safety · highest severity High · 3 finding(s) · effort small
Summary
A safety or loss gate rejects a model and auto-revert reports 'Reverted artifacts deleted successfully'. A later step that picks up the newest checkpoint-* (for example --resume, or a script loading checkpoint dirs) still serves the rejected weights.
Primary finding
CR-A02-003 — Auto-revert deletes only final_model and leaves the rejected weights in checkpoint-N
severity High · reachability default · intent contract-violation · confidence confirmed · independently confirmed · reproduced end to end
What happens. _revert_model only rmtree's final_path (trainer.py:994-998); the HF Trainer's checkpoint-N directories under output_dir (adapter_model.safetensors, optimizer.pt) are left on disk, also in pipeline stages, contradicting the field description and manual that say the trained artefacts are removed.
Where.
forgelm/trainer.py:995-1001(rmtree at 997)forgelm/cli/_training.py:152(manage_checkpoints action=keep)forgelm/trainer.py:994-1002forgelm/cli/_training.py:152forgelm/trainer.py:994-997forgelm/config.py:1191-1194(auto_revert description: 'the trained artefacts are removed')forgelm/trainer.py:_revert_model (shutil.rmtree(final_path))docs/usermanuals/en/evaluation/auto-revert.md:11,170forgelm/cli/_training.py:152-153site/features.html:229
Evidence.
- x-dpo-revert-0.01 exit 3: final_model gone, out/checkpoint-1 (13 files incl. adapter_model.safetensors) present. In x-dpo-revert-100, checkpoint-1 and final_model adapters share sha256 1d968539...
- L-A1 (reverted): out/checkpoint-1/adapter_model.safetensors present. L-A2: checkpoint-1 adapter sha256 5f84b448e17700172de271cb43af7b94de882e269f3520b639065948c8efcdae equals the final_model adapter. The same holds for S-C2, J-A2 and B-2.
- runE after the gate failure: stage2_dpo contains README.md, audit_log.jsonl, checkpoint-1/ and no final_model (artefact-tree.txt). runG shows the same for stage 1.
Recommended fix. On revert, also remove or quarantine the checkpoint-* directories produced by the run, or document that checkpoints are kept and contain the rejected weights.
Other findings with the same root cause
These close with the same fix; update them in the same pull request.
CR-A04-007 — Rejected model weights survive auto-revert in checkpoint-* directories, contrary to the auto-revert docs
severity High · reachability documented-opt-in · intent contract-violation · confidence confirmed · independently confirmed · reproduced end to end
What happens. _revert_model deletes only the final model directory (trainer.py:996-997). The CLI then always calls manage_checkpoints(output_dir, action='keep') (cli/_training.py:151-152), so every checkpoint-N of the rejected run is kept, including the last one, whose adapter equals the reverted final adapter. The docs say 'after a revert you have no fine-tuned model on disk, only the untouched base model' (docs/usermanuals/en/evaluation/auto-revert.md:11) and 'Expecting a surviving checkpoint after a revert. There is none.' (auto-revert.md:170). The quickstart guide says auto-revert 'deletes the adapter' (docs/guides/quickstart.md:258). When the trigger is the safety or judge gate, a model the gate rejected stays loadable from output_dir/checkpoint-N.
Failure scenario. Tiny SFT run with evaluation.auto_revert true and max_acceptable_loss 0.001 exits 3 and deletes out/final_model, but out/checkpoint-1/adapter_model.safetensors remains. A twin run with auto_revert false shows that checkpoint adapter is tensor-identical (8/8) to final_model. An operator who trusts the docs ('no fine-tuned model on disk') can deploy, or fail to purge, the rejected weights from checkpoint-1.
Where.
forgelm/cli/_training.py:151-152forgelm/trainer.py:960-1003(rmtree at :997)docs/usermanuals/en/evaluation/auto-revert.md:11docs/usermanuals/en/evaluation/auto-revert.md:170docs/guides/quickstart.md:258forgelm/trainer.py:994-997forgelm/trainer.py:1590-1593forgelm/trainer.py:509forgelm/utils.py:82-83forgelm/trainer.py:345,497,509-510 (checkpoints written into output_dir, save_strategy hardcoded)
Evidence.
- rv/sft/run.log: 'Reverted artifacts deleted successfully.' then 'Preserving intermediate checkpoints (action=keep).' EXIT=3; out/ lists checkpoint-1 (adapter_model.safetensors, optimizer.pt, ...). Copy at outputs/a review run/a1-W78/u215_sft_revert_run.log.
Recommended fix. On revert, also remove (or quarantine and record) the run's checkpoint-* directories, or state plainly in auto-revert.md and quickstart.md that intermediate checkpoints survive.
DOC-D3B08-046 — docs/usermanuals/en/evaluation/auto-revert.md: false claim — After a revert you have no fine-tuned model on disk; a revert leaves nothing to fall back to
severity Medium
Where. docs/usermanuals/en/evaluation/auto-revert.md:11,170 · type: false claim
The document says. After a revert you have no fine-tuned model on disk; a revert leaves nothing to fall back to
What the code does. out/checkpoint-N survives the revert and can be byte-identical to the deleted final model
Code references. forgelm/trainer.py:994-1002, forgelm/cli/_training.py:152, forgelm/trainer.py:995-997, forgelm/cli/_training.py:151-152
User impact. Reverted (possibly unsafe) weights remain on disk unnoticed
Turkish mirror. the Turkish page has the same error; fix both in the same PR
Acceptance criteria
- A regression test reproduces the failure scenario and asserts the corrected behaviour.
- Documentation listed above is corrected in English and in its Turkish mirror in the same PR.
- Every finding in this issue is resolved or explicitly closed with a reason.
Found by the October 2026 ForgeLM code and documentation review against commit cab2947. Code links point at that commit; line numbers may have moved since. Finding IDs (CR-…, DOC-…, TECH-…) are stable references for this backlog.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsTodo
Activity