Repository navigation
[Wave 4] Low/info — Module sweep: Config schema & public library API (part 2/4) #662
Description
Wave 4 · 20 finding(s) in 20 fix package(s). Fix these whenever a pull request touches this module ("clean the module you touch").
Findings
-
CR-A01-095 (code, Low) — Non-finite and out-of-range values for learning_rate, rope_scaling.factor, neftune_noise_alpha, api_delay and benchmark.limit are untested, and the code accepts most of them
severity Low · reachabilitydefault· intentintended-but-harmful· confidence confirmed · independently confirmed · reproduced end to end · already tracked: PARTIALLY-FIXED C31-NUMERIC-CONFIG — docs/roadmap/phase-16-trust-surface-hardening.md:289-292 (S2 done); CHANGELOG.md:9-20
Failure scenario. A generated config withlearning_rate: .inforneftune_noise_alpha: .nanpasses --dry-run and trains a NaN model.api_delay: .infpasses validation and raises OverflowError after the first synthetic API call.benchmark.limit: -1runs an unintended benchmark. All of these arrive silently, with no test that would have forced a decision.
Where.forgelm/config.py:486-491,forgelm/config.py:582-585,forgelm/config.py:663-668,forgelm/config.py:877
Recommended fix. Use allow_inf_nan=False on every float, and add bounds (learning_rate le=1.0, neftune_noise_alpha ge=0, api_delay finite and le=3600, benchmark.limit ge=1, a finite check in_check_factor). Extend NON_FINITE_MATRIX with one row per field, going through_load_config_or_exit, plus a finite control row for each. -
CR-A01-096 (code, Low) — data.shuffle does not do what it documents: the train/validation split is always random and the Trainer shuffles training order anyway
severity Low · reachabilitydefault· intentcontract-violation· confidence likely · independently confirmed · reproduced end to end
Failure scenario. An operator sets shuffle: false to train in curriculum order or to keep a held-out tail as validation, and silently gets neither.
Where.forgelm/config.py:817,forgelm/data.py:549-581,forgelm/data.py:618-631,forgelm/data.py:669-686
Recommended fix. Thread shuffle into train_test_split(shuffle=...) and set train_sampling_strategy='sequential' when shuffle is false, or reword the docs to what the field actually does. -
CR-A01-097 (code, Low) — Risk-tier disagreement warning is deduplicated process-wide: library callers and long-lived processes lose it for every later config, and reversed pairs are merged
severity Low · reachabilitydefault· intentintended-but-harmful· confidence likely · single reviewer · reproduced end to end
Failure scenario. A compliance service validates many customer configs in one process. After the first, no disagreeing config is flagged, and contradictory tiers ship into Annex IV bundles without the documented nudge.
Where.forgelm/config.py:1595-1601,forgelm/config.py:1878-1919
Recommended fix. Dedupe per root config (for example a private flag carried through merge_pipeline_stage_config) instead of per process, and key on the ordered (ra, cm) tuple. -
CR-A01-098 (code, Low) — QLoRA + ZeRO-3 warning keys on the substring 'zero3' in deepspeed_config, not on the configured ZeRO stage
severity Low · reachabilitydocumented-opt-in· intentintended-but-harmful· confidence likely · independently confirmed · reproduced end to end
Failure scenario. An operator with a custom stage-3 JSON and load_in_4bit gets no warning and hits the known incompatibility at runtime.
Where.forgelm/config.py:1945-1955,forgelm/config.py:1945-1954
Recommended fix. For paths, read zero_optimization.stage from the JSON when the file exists; keep the name test for presets. -
CR-A01-099 (code, Low) — evaluation.safety.min_classifier_confidence has no effect under the default generation scoring, with no warning or documentation
severity Low · reachabilitydefault· intentintended-but-harmful· confidence likely · single reviewer · not reproduced (code trace)
Failure scenario. A compliance team raises min_classifier_confidence to 0.95 to route more borderline verdicts to human review. Under the default classifier nothing changes and low_confidence_count reflects only malformed verdicts.
Where.forgelm/config.py:962-967,forgelm/safety/_score_generation.py:171-243,forgelm/safety/_gates.py:349-359,forgelm/safety/_orchestrator.py:251-277
Recommended fix. Document that the field applies only in classification mode, and warn when it is set explicitly while generation mode is in effect. -
CR-A01-100 (code, Low) — load_config parameter is config_path, documented as path
severity Low · reachabilitydefault· intentcontract-violation· confidence likely · independently confirmed · reproduced end to end
Failure scenario. A caller using the documented keyword gets TypeError. Renaming the parameter to match the doc would itself be a signature change to a stable symbol.
Where.docs/reference/library_api_reference.md:46,docs/reference/library_api_reference-tr.md:46,forgelm/config.py:2245,tests/_data/api_signatures_1.2.0.json:143-146
Recommended fix. Correct the doc to config_path. Do not rename the code parameter. -
CR-A01-101 (code, Low) — TrainResult field list omits awaiting_approval, run_id and config_hash
severity Low · reachabilitydefault· intentcontract-violation· confidence likely · independently confirmed · reproduced end to end
Failure scenario. An integrator branching on success and staging_path misreads a human-approval pause. results.py:42 itself says staging_path alone is not a safe discriminator.
Where.docs/reference/library_api_reference.md:56,docs/reference/library_api_reference-tr.md:56,forgelm/results.py:52,forgelm/results.py:51
Recommended fix. Add the three fields to the doc and state that awaiting_approval is the gate-pending discriminator. -
CR-A01-102 (code, Low) — Example 3 note claims training.trainer_type and training.output_dir are required by the schema; both have defaults
severity Low · reachabilitydefault· intentcontract-violation· confidence likely · single reviewer · reproduced end to end
Failure scenario. A reader concludes output_dir must always be given, or is surprised that omitting it silently falls back to the default.
Where.docs/reference/library_api_reference.md:183,docs/reference/library_api_reference-tr.md:183,forgelm/config.py:451-462,forgelm/config.py:461
Recommended fix. Drop the 'required' claim for those two keys. -
CR-A01-103 (code, Low) — Auxiliary-symbol rows are incomplete or loosely worded: setup_authentication, manage_checkpoints, AuditLogger, BenchmarkResult
severity Low · reachabilitydefault· intentcontract-violation· confidence likely · independently confirmed · reproduced (plumbing only)
Failure scenario. A caller expects setup_authentication to raise on a bad token, or calls manage_checkpoints(action='prune') and silently keeps everything.
Where.docs/reference/library_api_reference.md:21,docs/reference/library_api_reference.md:83,docs/reference/library_api_reference.md:114,docs/reference/library_api_reference.md:113
Recommended fix. Document the three real actions and the no-raise behaviour. Add the ConfigError from AuditLogger.init to the table. -
CR-A01-104 (code, Low) — model.max_length is never compared with the model's max_position_embeddings or the rope-scaled limit; out-of-range context trains silently
severity Low · reachabilitydefault· intentintended-but-harmful· confidence confirmed · independently confirmed · reproduced end to end
Failure scenario. An operator sets max_length: 8192 on a base model with a 4096-position RoPE range (or copies the long-context guide's 32768 example) and leaves out rope_scaling. Dry-run, fit-check and training all succeed silently. The model trains on positions it was never trained or scaled for, and the model card and manifest claim an 8192 context. Deploy then emits num_ctx/max_model_len 8192, which vLLM may refuse.
Where.forgelm/config.py:253-258,forgelm/fit_check.py:92-103,forgelm/model.py:463-466,forgelm/trainer.py:672-683
Recommended fix. At config-load or model-load time, read max_position_embeddings (and the rope_parameters/rope_scaling factor when present) and compare with model.max_length. Warn or fail when max_length exceeds the effective limit, and surface the same check as a fit-check note. Add a test using a derived tiny config. -
CR-A01-105 (code, Low) — Empty output paths pass validation and fail only after the expensive work, with the wrong exit class
severity Low · reachabilitydefault· intentintended-but-harmful· confidence likely · independently confirmed · reproduced end to end
Failure scenario. A templated CI config whose output variable resolves to an empty string burns a full merge or a paid teacher call before failing, and reports a training error instead of a config error.
Where.forgelm/config.py:194,forgelm/config.py:1363,forgelm/merging.py:110-112,forgelm/synthetic.py:131-132
Recommended fix. Add min_length=1 to both fields (Field(..., min_length=1)) so the error is caught at config load and by --dry-run with exit 1. -
CR-A01-106 (code, Low) — sanitize_non_finite recursion cap (~1000) is below json's (~10^4): a valid deep data_audit_report.json makes the governance writer fail, truncating the previous data_governance_report.json to 0 bytes
severity Low · reachabilitydefault· intentintended-but-harmful· confidence confirmed · independently confirmed · reproduced end to end · already tracked: PARTIALLY-FIXED TRUST-15 — docs/roadmap/phase-16-trust-surface-hardening.md:9-11,339-343 (S2 done); CHANGELOG.md:91-101
Failure scenario. Anyone able to drop a data_audit_report.json into training.output_dir (or an audit tool emitting deep nesting) makes every subsequent training run destroy the existing Art. 10 governance report: the file is replaced by 0 bytes while the export rollup still lists it.
Where.forgelm/_strict_json.py:53-56,forgelm/trainer.py:2095-2098,forgelm/trainer.py:2138-2147,forgelm/compliance.py:697-699
Recommended fix. Serialise first and write via tmp+os.replace (or at least compute the string before open(...,'w')) in the five writers. Make sanitize_non_finite iterative or depth-bounded, with an id()-based cycle guard that raises ValueError like json does. -
CR-A01-107 (code, Low) — lora.task_type is an unvalidated free string: values PEFT rejects pass the schema and --dry-run and fail only after the base model is loaded
severity Low · reachabilitydefault· intentintended-but-harmful· confidence likely · single reviewer · reproduced (plumbing only)
Failure scenario. task_type: causal_lm (lower case) -> dry-run OK, then 'ValueError: Invalid task type' after weights are loaded, reported as a training failure (exit 2).
Where.forgelm/config.py:386-388,forgelm/model.py:534
Recommended fix. Constrain task_type to Literal of the PEFT TaskType names (or validate against peft.TaskType lazily in the dry-run). -
CR-A01-108 (code, Low) — Config DeprecationWarnings (use_dora, use_rslora, sample_packing) are attributed to pydantic internals and hidden by default filters
severity Low · reachabilitydefault· intentcontract-violation· confidence confirmed · independently confirmed · reproduced end to end
Failure scenario. A notebook or script that builds ForgeConfig(**d) with a deprecated field sees no DeprecationWarning unless logging is visible. When the warning is shown (pytest, -W default), it points at pydantic instead of user code, which weakens the N-release migration nudge the cadence relies on.
Where.forgelm/config.py:437,forgelm/config.py:738-744,docs/standards/release.md:112-113,forgelm/config.py:738-745
Recommended fix. Use a larger stacklevel or warn_explicit with the caller module, or document that the logger line is the operator-facing signal. -
CR-A01-109 (code, Low) — The performance guide tells users to tune
dataloader_num_workers'in your training config', but the schema rejects the field (exit 1)
severity Low · reachabilitydefault· intentcontract-violation· confidence confirmed · single reviewer · reproduced end to end · already tracked: KNOWN-OPEN C31-DOC-SCHEMA-PROSE — docs/roadmap/phase-16-trust-surface-hardening.md:785-786 (S15 open)
Failure scenario. An operator profiles a slow input pipeline, follows performance.md:187, and addsdataloader_num_workers: 4undertraining:.forgelm --configthen fails validation with exit 1. The documented tuning knob does not exist.
Where.docs/guides/performance.md:187,docs/guides/performance-tr.md:187,forgelm/config.py:443-449,forgelm/trainer.py:496-521
Recommended fix. Either add a documentedtraining.dataloader_num_workersfield forwarded to TrainingArguments, with a Docker shm caveat because workers >0 use /dev/shm, or rewrite the guidance to say that ForgeLM keeps transformers' default of 0 workers. -
CR-A01-110 (code, Low) — EN/TR value drift inside YAML/CI code blocks that the key-only guard cannot see: SimPO quick example simpo_gamma 1.0 (EN) vs 0.5 (TR); GitLab audit step differs
severity Low · reachabilitydefault· intentcontract-violation· confidence likely · independently confirmed · reproduced end to end
Failure scenario. An EN reader who copies the SimPO quick example trains with gamma=1.0 (a stronger margin than the documented default 'balanced' setting) while a TR reader gets 0.5. The guard passes because the top-level key sets match.
Where.docs/usermanuals/en/training/simpo.md:44,docs/usermanuals/tr/training/simpo.md:44,docs/usermanuals/en/training/simpo.md:59,docs/usermanuals/en/training/simpo.md:78-80
Recommended fix. Set EN simpo.md:44 to 0.5, or list 2.0/1.0 in the combination table if 1.0 is intended, and keep TR in sync. Extend the guard, or check_yaml_snippets, to compare non-prose scalar values of paired YAML blocks, ignoring comments and strings with whitespace or non-ASCII. -
CR-A01-111 (code, Low) — 'Only from sources you specify' is not true for implicit defaults: Llama-Guard-3-8B, api.openai.com judge endpoint, doctor's huggingface.co probe, lm-eval task datasets
severity Low · reachabilitydocumented-opt-in· intentintended-but-harmful· confidence likely · independently confirmed · reproduced (plumbing only)
Where.site/js/translations.js:4345,forgelm/config.py:913-915,forgelm/config.py:1085-1087,forgelm/judge.py:82
Recommended fix. List these default endpoints in privacy.body (or the toolkit docs). Consider requiring judge_api_base whenever judge_api_key_env is set, so the third-party endpoint is always named. -
CR-A01-112 (code, Low) — Stable symbols are not 100% type-hinted: **kwargs/**details are unannotated
severity Low · reachabilitydefault· intentcontract-violation· confidence likely · single reviewer · reproduced end to end
Where.forgelm/config.py:1654,forgelm/config.py:1682,forgelm/compliance.py:517,docs/reference/library_api_reference.md:21
Recommended fix. Annotate **kwargs: Any, add the dict[str, Any] return type, and annotate **details: Any. -
CR-A01-113 (code, Low) — 11 Stable symbols have no integration test in tests/test_library_api.py
severity Low · reachabilitydefault· intentcontract-violation· confidence likely · single reviewer · reproduced end to end
Where.tests/test_library_api.py:447-569,tests/test_library_api.py:112-143,forgelm/__init__.py:142-177
Recommended fix. Add facade-level integration tests for the missing stable symbols. ForgeTrainer/TrainResult can use the tiny model, or the doc can point to the modules that do test them. -
CR-A01-114 (code, Low) — A missing deepspeed_config preset or file passes --dry-run and is detected only after model and dataset load
severity Low · reachabilitydefault· intentintended-but-harmful· confidence likely · independently confirmed · reproduced (plumbing only)
Failure scenario. CI validates a 70B config with --dry-run (green); the GPU job loads the model for minutes and then exits 1 on a typo in deepspeed_config.
Where.forgelm/config.py:759-762,forgelm/trainer.py:531-533,forgelm/trainer.py:664-670,forgelm/cli/_dry_run.py:61
Recommended fix. Resolve or validate deepspeed_config in --dry-run or a config validator: a preset name, or an existing file when strategy == 'deepspeed'.
Done when
- Every finding above is fixed or closed with a reason (tick it here).
- Code fixes carry a test; doc fixes update the Turkish mirror in the same PR.
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