Repository navigation
retention.enforce (block_on_excess / warn_on_excess) has no runtime reader: the documented trainer pre-flight gate never runs (CR-A01-006) #92
Description
Wave 0 · theme D0-5: Documented controls that are not implemented · highest severity Critical · 10 finding(s) · effort medium
Summary
A regulated CI sets retention.enforce: block_on_excess and reuses a workspace whose audit_log.jsonl is past audit_log_retention_days. Training runs and exits 0, nothing is logged and no exit 3 occurs. The operator believes storage limitation is being enforced.
Primary finding
CR-A01-006 — retention.enforce (block_on_excess / warn_on_excess) has no runtime reader: the documented trainer pre-flight gate never runs
severity High · reachability documented-opt-in · intent contract-violation · confidence confirmed · independently confirmed · reproduced end to end
What happens. RetentionConfig.enforce (forgelm/config.py:1585-1592, docstring 1540-1546) is validated, offered by the wizard's _collect_retention as 'block_on_excess (abort trainer with EXIT_EVAL_FAILURE)' (forgelm/wizard/_collectors.py:863-877) and documented (configuration.md:266) as a trainer pre-flight abort with exit 3. Nothing in forgelm/ reads .enforce: the trainer and CLI train path never call _scan_retention_violations, and the only retention reader, purge --check-policy (forgelm/cli/subcommands/_purge.py:1108-1170), ignores enforce and always exits 0.
Where.
forgelm/config.py:1540-1546forgelm/config.py:1585-1591forgelm/config.py:1559-1567forgelm/wizard/_collectors.py:863-868forgelm/cli/subcommands/_audit.py:56-59(confirmed)forgelm/cli/subcommands/_purge.py:1108-1169docs/reference/configuration.md:266forgelm/config.py:1559-1566forgelm/cli/subcommands/_purge.py:1108-1168config_template.yaml:274
Evidence.
- rg for '.enforce', 'block_on_excess' and 'warn_on_excess' in forgelm/ finds only the schema, the wizard prompt and an _audit.py docstring that cites the 'retention block_on_excess gate'.
config.retentionis read only at _purge.py:1141/1153, and that path always ends in sys.exit(EXIT_SUCCESS). rg -n '\.enforce\b|"retention"|retention_days|staging_ttl' forgelm --glob '*.py'finds no reader outside config/wizard/purge. Repro r15: the output dir holds final_model.staging.fg-old000000000, whose first audit event is 200 days old, andpurge --check-policyreports staging_dir (age 200d, horizon 7d) and compliance_bundle violations.fpy -m forgelm --config r15/cfg.yamlwithretention.enforce: block_on_excessthen exits 0 with success true and writes final_model/. The audit log gets n…rg -n "\.enforce\b|\"enforce\"|'enforce'|retention\." forgelmmatches only config.py and _purge.py horizon reads. The repro config ret/cfg.yaml sets retention.enforce=block_on_excess and ephemeral_artefact_retention_days=1, with out/data_audit_report.json mtime set to 2020.forgelm purge --check-policy --config cfg.yaml --output-dir out --output-format jsonreports count 1 (data_audit_report, age 2465.9d, horizon 1d).fpy -m forgelm --config cfg.yaml(tiny-qwen SFT, 1 step) then ends with…
Recommended fix. Implement the pre-flight check in the training path (reuse _scan_retention_violations; map block_on_excess to EXIT_EVAL_FAILURE and emit an audit event), or remove the promise from the field, the docstring, the wizard and the docs and raise NotImplementedError when a non-default mode is set.
Other findings with the same root cause
These close with the same fix; update them in the same pull request.
-
CR-A02-021 (code, High) — Code does not match docs/design/gdpr_erasure.md: §3.4 site 1: ForgeTrainer.train() runs a retention pre-flight that honours
enforce. L143: 'When set, the trainer's pre-flight gate runs th
severity High · reachabilitydocumented-opt-in· intentcontract-violation· confidence confirmed · independently confirmed
Failure scenario. The document states: §3.4 site 1: ForgeTrainer.train() runs a retention pre-flight that honoursenforce. L143: 'When set, the trainer's pre-flight gate runs the check'. L136-140 define the enforce semantics; L211 reserves exit 3 for block_on_excess; L447 names it 'the CI gate'.. Observed in the code: No retention pre-flight exists in the trainer or anywhere else, andretention.enforceis never read. The design is also internally inconsistent: L139 says block_on_excess raises ConfigError, wh…
Where.forgelm/trainer.py:1571-1580(_run_training_pipeline start; the cited 1569-1660 range is OOM/pipeline helpers, not a retention site),forgelm/config.py:1585-1591,forgelm/cli/subcommands/_purge.py:1108-1168(_run_purge_check_policy, the only consumer of config.retention; always exits 0),forgelm/trainer.py:1661-1700(train(): no retention pre-flight)
Recommended fix. Fix the code (implement the pre-flight) or mark §3.4 site 1 and the enforce semantics as "NOT IMPLEMENTED —enforceis currently inert", and pick one exit behaviour (exit 3) for block_on_excess. -
CR-A10-006 (code, High) — Retention policy is report-only: no code enforces retention.enforce or deletes/prunes artefacts past their horizon, though docs, config and site say it does
severity High · reachabilitydocumented-opt-in· intentcontract-violation· confidence confirmed · independently confirmed · reproduced end to end
Failure scenario. The document states: Retention horizons, including "staging_ttl_days: 7 # final_model.staging.<run_id>/ TTL afterforgelm reject". Observed in the code: Nothing deletes or expires artefacts when a horizon passes. staging_ttl_days and the other horizons are read only byforgelm purge --check-policy, which lists violations and exits 0. No scheduled cleanup exists, and approve/reject never read the TTL.
Where.forgelm/cli/subcommands/_purge.py:1171-1237(_scan_retention_violations, report-only),forgelm/config.py:1526-1592(RetentionConfig; docstring 1540-1546, staging_ttl_days 1559-1566, enforce 1585-1592),forgelm/cli/subcommands/_purge.py:1108-1168(_run_purge_check_policy; exits 0 at 1150 and 1168),forgelm/cli/subcommands/_purge.py:1171-1236(confirmed)
Recommended fix. Add: "# Horizons are reported byforgelm purge --check-policy(read-only); nothing is deleted automatically — remove artefacts withforgelm purge." -
DOC-D1B01-003 (docs, Critical) — docs/reference/configuration.md: false claim — "The
enforceknob switches between log-only, warning, and hard-block modes so a regulated CI gate cannot silently extend the retention horizon". Also…
severity Critical
Where.docs/reference/configuration.md:256-258(Turkish mirror:docs/reference/configuration-tr.md:252-258, :264, :267) · type: false claim
The document says. "Theenforceknob switches between log-only, warning, and hard-block modes so a regulated CI gate cannot silently extend the retention horizon". Also :266block_on_excess"(abort trainer pre-flight withEXIT_EVAL_FAILURE= 3)",log_only"(audit-log only)", and :263 staging_ttl_days "before…
What the code does. Nothing reads retention.enforce at runtime. A grep finds it only in the schema (config.py:1526-1600) and the wizard prompt (wizard/_collectors.py:877). The trainer has no retention pre-flight, writes no audit event and prints no warning. No scheduled cleanup exists. The only consumer of the retention block isforgelm purge --check-policy(_purge.py:1141-1170), a read-only report that always exi…
Code references.forgelm/config.py:1526-1600,forgelm/wizard/_collectors.py:877,forgelm/cli/subcommands/_purge.py:1141-1170,forgelm/cli/subcommands/_purge.py:1171-1226
Proposed correction. Fix the code: implement the trainer pre-flight. Run _scan_retention_violations on training.output_dir; log_only emits an audit event, warn_on_excess prints a structured stderr warning, block_on_excess exits 3. Temporary doc warning: "enforceis currently recorded but not enforced: no mode aborts training, warns or writes an audit event, and noth…
Turkish mirror. the Turkish page has no such statement -
DOC-D2B02-001 (docs, Critical) — docs/design/gdpr_erasure.md: false claim — §3.4 site 1: ForgeTrainer.train() runs a retention pre-flight that honours
enforce. L143: 'When set, the trainer's pre-flight gate runs the check'. L136-1…
severity Critical
Where.docs/design/gdpr_erasure.md:156-158· type: false claim
The document says. §3.4 site 1: ForgeTrainer.train() runs a retention pre-flight that honoursenforce. L143: 'When set, the trainer's pre-flight gate runs the check'. L136-140 define the enforce semantics; L211 reserves exit 3 for block_on_excess; L447 names it 'the CI gate'.
What the code does. No retention pre-flight exists in the trainer or anywhere else, andretention.enforceis never read. The design is also internally inconsistent: L139 says block_on_excess raises ConfigError, while L211 and the config description say exit 3.
Code references.forgelm/trainer.py:1569-1660,forgelm/config.py:1585-1591,forgelm/cli/subcommands/_purge.py:1108-1168
Proposed correction. Fix the code (implement the pre-flight) or mark §3.4 site 1 and the enforce semantics as "NOT IMPLEMENTED —enforceis currently inert", and pick one exit behaviour (exit 3) for block_on_excess. -
DOC-D2B02-002 (docs, Critical) — docs/guides/gdpr_erasure.md: false claim —
enforcecontrols how the trainer pre-flight gate reacts to retention violations (log_only / warn_on_excess / block_on_excess, L81).
severity Critical
Where.docs/guides/gdpr_erasure.md:84(Turkish mirror:docs/guides/gdpr_erasure-tr.md:84) · type: false claim
The document says.enforcecontrols how the trainer pre-flight gate reacts to retention violations (log_only / warn_on_excess / block_on_excess, L81).
What the code does. No trainer pre-flight retention gate exists.retention.enforceis never read anywhere outside the schema. A search for retention across forgelm/ finds only config.py (the field and its description, which itself promises 'block_on_excess aborts the trainer pre-flight with EXIT_EVAL_FAILURE (3)'), the purge --check-policy report (which ignoresenforce), and the wizard prompt. A training run wit…
Code references.forgelm/config.py:1585-1591,forgelm/cli/subcommands/_purge.py:1108-1168,forgelm/trainer.py:1569-1660,forgelm/wizard/_collectors.py:866-868
Proposed correction. Fix the code: implement the documented pre-flight in ForgeTrainer.train(), or removeenforcefrom RetentionConfig. Until then, replace the sentence with: "Note:enforceis currently not acted on by any command. Training does not check retention. Runforgelm purge --check-policyyourself and gate CI on its JSONcount."
Turkish mirror. the Turkish page has the same error; fix both in the same PR -
DOC-BFIELD-003 (docs, High) — forgelm/config.py: false claim —
log_onlyrecords violations in the audit log;warn_on_excessadds a structured warning to stderr;block_on_excessaborts the trainer pre-flight with EXIT_EVAL_F…
severity High
Where.forgelm/config.py:1585-1592(RetentionConfig.enforce, F68) (Turkish mirror:docs/reference/configuration.md:266; config_template.yaml:274; docs/usermanuals/en/reference/configuration.md:297) · type: false claim
The document says.log_onlyrecords violations in the audit log;warn_on_excessadds a structured warning to stderr;block_on_excessaborts the trainer pre-flight with EXIT_EVAL_FAILURE (3)
What the code does. retention.enforce is never read:rg '\.enforce\b' forgelmfinds only config.py and the wizard collector (wizard/_collectors.py:863-877). The trainer has no retention pre-flight; there is no 'retention' match in trainer.py, cli/_training.py or cli/_pipeline.py. The only consumer of the retention block isforgelm purge --check-policy(cli/subcommands/_purge.py:1108-1169). It prints a report, al…
Code references.forgelm/cli/subcommands/_purge.py:1108-1169,forgelm/cli/subcommands/_purge.py:1171-1236,forgelm/wizard/_collectors.py:863-877
Proposed correction. Implement the trainer pre-flight (call _scan_retention_violations against training.output_dir, emit an audit event, warn or exit 3 according to enforce), or rewrite the description and docs to say that retention horizons are report-only throughforgelm purge --check-policyand that enforce is currently ignored. -
DOC-D4B02-004 (docs, High) — config_template.yaml: false claim — enforce: "log_only" # "log_only" | "warn_on_excess" | "block_on_excess" — presented as a working retention enforcement mode
severity High
Where.config_template.yaml:274· type: false claim
The document says. enforce: "log_only" # "log_only" | "warn_on_excess" | "block_on_excess" — presented as a working retention enforcement mode
What the code does. RetentionConfig.enforce is validated but read by no code: rg over forgelm/ finds only the wizard writing it. The trainer has no retention pre-flight, so block_on_excess never aborts and warn_on_excess never warns. The only consumer of the retention block isforgelm purge --check-policy, a read-only report that always exits 0.
Code references.forgelm/config.py:1585-1592,forgelm/cli/subcommands/_purge.py:1125-1172,forgelm/cli/subcommands/_purge.py:1175-1234,forgelm/wizard/_collectors.py:863-877
Proposed correction. Fix the code (implement the retention pre-flight). Temporary doc note: "# NOTE: enforce is currently recorded only — no mode warns or blocks; runforgelm purge --check-policyto list violations." -
DOC-D4B09-012 (docs, High) — site/js/translations.js: false claim — With retention.enforce set, 'ForgeLM auto-deletes artefacts past their horizon'; log_only 'logs violations to audit'; warn_on_excess 'log + stderr warning'; blo…
severity High
Where.site/js/translations.js:1820-1823(wizard.retention.enforce.hint/.log_only/.warn/.block), :1812 · type: false claim
The document says. With retention.enforce set, 'ForgeLM auto-deletes artefacts past their horizon'; log_only 'logs violations to audit'; warn_on_excess 'log + stderr warning'; block_on_excess 'abort trainer (regulated CI)'
What the code does. RetentionConfig.enforce (forgelm/config.py:1585) is declared but nothing reads it: no consumer exists in trainer, cli or compliance, and wizard/_collectors.py only writes it. The horizons are consumed only by 'forgelm purge --check-policy', which prints a report and exits 0 (cli/subcommands/_purge.py:1141-1175). No code deletes artefacts, writes a retention violation to the audit log, or aborts t…
Code references.forgelm/config.py:1526-1593,forgelm/cli/subcommands/_purge.py:1141-1175
Proposed correction. Replace the hint with 'Retention horizons are report-only today: run forgelm purge --check-policy to list artefacts past their horizon. The enforce mode is not yet wired to the trainer; nothing is deleted automatically.' Remove the three mode descriptions, or mark them 'not yet enforced'. -
DOC-D4B02-011 (docs, Medium) — config_template.yaml: misleading — Retention horizons, including "staging_ttl_days: 7 # final_model.staging.<run_id>/ TTL after
forgelm reject"
severity Medium
Where.config_template.yaml:266-273· type: misleading
The document says. Retention horizons, including "staging_ttl_days: 7 # final_model.staging.<run_id>/ TTL afterforgelm reject"
What the code does. Nothing deletes or expires artefacts when a horizon passes. staging_ttl_days and the other horizons are read only byforgelm purge --check-policy, which lists violations and exits 0. No scheduled cleanup exists, and approve/reject never read the TTL.
Code references.forgelm/cli/subcommands/_purge.py:1175-1234,forgelm/config.py:1559-1567
Proposed correction. Add: "# Horizons are reported byforgelm purge --check-policy(read-only); nothing is deleted automatically — remove artefacts withforgelm purge."
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.
- The release note names the contract this fix restores.
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
fix(wizard): do not say log_only has an effect the other retention mo…
fix: rope_scaling on transformers 5, hub telemetry, reserved retentio…
docs: compliance and privacy wording, SBOM and Article 12/14, and the…