Skip to content

[Wave 4] Low/info — Module sweep: Config schema & public library API (part 4/4) #664

Open

Description

@cemililik

Wave 4 · 16 finding(s) in 16 fix package(s). Fix these whenever a pull request touches this module ("clean the module you touch").

Findings

  • CR-A01-135 (code, Low) — model-merging.md presents DARE as pairing with TIES ('DARE-TIES'); ForgeLM has no DARE-TIES method, and its DARE has no sign election
    severity Low · reachability default · intent contract-violation · confidence likely · single reviewer · not reproduced (code trace)
    Failure scenario. An operator sets method: dare expecting DARE-TIES behaviour and gets plain DARE with no sign-conflict resolution.
    Where. docs/usermanuals/en/deployment/model-merging.md:27, docs/usermanuals/tr/deployment/model-merging.md:27, forgelm/config.py:186, forgelm/merging.py:432-456
    Recommended fix. State that only plain DARE is implemented, or add a dare_ties method.

  • CR-A01-136 (code, Low) — exit-codes manual says '${HF_TOKEN} set in YAML but env var missing' exits 1; ForgeLM does not expand it, dry-run exits 0 and the run continues with the literal string
    severity Low · reachability default · intent contract-violation · confidence likely · independently confirmed · reproduced with stubs
    Failure scenario. A CI author follows the exit-code table and alarms on 1 for a missing token. The job either succeeds unauthenticated (public model) or fails with 2 at model load, so the alarm never fires.
    Where. docs/usermanuals/en/reference/exit-codes.md:85, forgelm/config.py:1507-1513, forgelm/utils.py:47-54, docs/usermanuals/tr/reference/exit-codes.md:85
    Recommended fix. Remove the row, or implement explicit ${VAR} expansion for secret fields that fails with ConfigError (exit 1) when the variable is unset.

  • CR-A01-137 (code, Info) — load_config and _load_config_or_exit convert only an enumerated set of exceptions; UnicodeDecodeError, RecursionError and -W error DeprecationWarning escape as raw tracebacks with no JSON envelope
    severity Info · reachability undocumented · intent intended-but-harmful · confidence confirmed · independently confirmed · reproduced end to end · already tracked: KNOWN-OPEN C33-CLI-ERROR-ENVELOPE — docs/roadmap/phase-16-trust-surface-hardening.md:499,507-508 (S7 open)
    Failure scenario. A Windows-edited cp1252 config breaks a CI JSON parser: there is no {success:false} object and the log holds only a raw traceback.
    Where. forgelm/config.py:2250-2254, forgelm/cli/_config_load.py:26-47 (confirmed), forgelm/cli/subcommands/_purge.py:1438-1441 (confirmed), forgelm/config.py:2259-2269
    Recommended fix. Catch UnicodeDecodeError in load_config and raise ConfigError(...) from it.

  • CR-A01-138 (code, Info) — dumps_strict sanitises only non-finite values: finite non-float64 numpy scalars, tensors and non-finite dict keys escape
    severity Info · reachability undocumented · intent intended-but-harmful · confidence likely · 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. A future metric path hands np.float32 to the audit logger. The value is written as a string, so a consumer computing on the field silently gets a str, unlike float64 metrics.
    Where. forgelm/_strict_json.py:53-56, forgelm/_strict_json.py:62-84, forgelm/_strict_json.py:87-95, forgelm/compliance.py:574-582 (confirmed)
    Recommended fix. For NumPy scalars, return value.item() after the finiteness check (and sanitise or str() float keys).

  • CR-A01-139 (code, Info) — forgelm.version (stamped into compliance, model card and pipeline manifests) comes from distribution metadata, not the running package tree
    severity Info · reachability undocumented · intent intended-but-harmful · confidence likely · independently confirmed · reproduced end to end
    Failure scenario. After a version bump in a checkout that is run without re-installing, or with a leftover dist-info from an older install, Annex IV manifests record the old forgelm_version. An auditor then reads provenance for a release that did not produce the artefact.
    Where. forgelm/_version.py:24-29 (confirmed), forgelm/compliance.py:24 (confirmed), forgelm/compliance.py:2359, forgelm/model_card.py:279-338 (confirmed)
    Recommended fix. Either compare the tree's own version (a generated _version file or pyproject) with the metadata at import and log a mismatch warning, or record the module's file origin alongside the version in provenance records.

  • CR-A01-140 (code, Info) — mix_ratio of large finite weights passes validation but overflows to inf on sum, sampling zero rows from every dataset
    severity Info · reachability undocumented · intent intended-but-harmful · confidence confirmed · independently confirmed · reproduced end to end
    Failure scenario. mix_ratio: [1e308, 1e308] with one extra dataset: config validates, sum = inf, _apply_mix_ratio returns datasets of length [0, 0].
    Where. forgelm/config.py:828-843, forgelm/data.py:496-509, forgelm/data.py:521-529, forgelm/data.py:698-708
    Recommended fix. In the validator, also require math.isfinite(sum(v)) (or normalise by max first). Correct the 'before anything is loaded' comment, or move the length check ahead of the primary load.

  • CR-A01-141 (code, Info) — Refuted for torch/transformers/trl/peft/datasets/accelerate and the optional extras. ModuleNotFoundError escapes hasattr/getattr/star-import/getmembers only when a core dependency (requests or huggin…
    severity Info · reachability undocumented · intent intended-and-acceptable · confidence likely · independently confirmed · reproduced end to end
    Where. forgelm/__init__.py:301-313, forgelm/utils.py:10, forgelm/webhook.py:6, forgelm/_http.py:56
    Recommended fix. Document the contract in library_api_reference.md under 'Lazy-import discipline': resolving a name imports its submodule, a missing core dependency surfaces as ModuleNotFoundError (also from hasattr and star-import), and feature detection should use api_version. Optionally add a parametrised subprocess test that blocks each heavy package and asserts every name resolves, to pin RC-0064.

  • CR-A01-142 (code, Info) — Config-level warnings repeat once per ForgeConfig instantiation: 7 copies in a 3-stage pipeline run
    severity Info · reachability default · intent intended-but-harmful · confidence likely · independently confirmed · reproduced end to end
    Failure scenario. Operators and log-based alerting see repeated identical warnings and learn to ignore them. Cosmetic, but inconsistent with the dedupe rationale applied to the tier warning.
    Where. forgelm/config.py:304-342, forgelm/config.py:1707-1748, forgelm/config.py:2233, forgelm/cli/_pipeline.py:970-1011
    Recommended fix. Apply one dedupe policy to all config warnings within a pipeline run, or suppress validator warnings on the internal re-validation in merge_pipeline_stage_config.

  • CR-A01-143 (code, Info) — Lazy-import section says import forgelm touches only importlib.metadata; the package eagerly imports forgelm.config (pydantic, yaml)
    severity Info · reachability default · intent contract-violation · confidence likely · single reviewer · reproduced end to end
    Failure scenario. A minimal-footprint consumer reads the claim and is surprised by pydantic and yaml being required at import.
    Where. docs/reference/library_api_reference.md:229, docs/reference/library_api_reference-tr.md:229, forgelm/__init__.py:13-15, forgelm/__init__.py:62
    Recommended fix. Reword to 'no heavy ML dependency'. Name pydantic and yaml as the cheap eager imports.

  • CR-A01-144 (code, Info) — Deployment manuals and post-training notebook teach reach-ins to modules the library API design marks Internal ('reach-in is unsupported')
    severity Info · reachability undocumented · intent contract-violation · confidence likely · independently confirmed · reproduced (plumbing only)
    Failure scenario. An automation pipeline built on the manual's 'Programmatic merging' recipe breaks on a minor release that renames or removes merge_peft_adapters, which the design doc allows without notice.
    Where. docs/design/library_api.md:122, docs/usermanuals/en/deployment/model-merging.md:128-145, docs/usermanuals/tr/deployment/model-merging.md:133, notebooks/post_training_workflow.ipynb:145
    Recommended fix. Either promote merge_peft_adapters and inference.load_model/generate/generate_stream to Experimental via all and _STABILITY_TIERS, or add an 'Internal, unsupported, may change without notice' callout to model-merging.md (EN and TR), vram-fit-check.md and the notebook.

  • CR-A01-145 (code, Info) — model-merging.md implies a DARE-TIES combination that does not exist
    severity Info · reachability default · intent contract-violation · confidence likely · independently confirmed · not reproduced (code trace)
    Failure scenario. A user sets method: dare expecting DARE-TIES behaviour (sign-resolved) and gets plain DARE.
    Where. docs/usermanuals/en/deployment/model-merging.md:27, docs/usermanuals/tr/deployment/model-merging.md:27, forgelm/config.py:186, forgelm/merging.py:431-451
    Recommended fix. Reword to say that DARE-TIES is not offered and that mergekit provides it.

  • CR-A01-146 (code, Info) — Deprecation start of evaluation.staging_ttl_days recorded inconsistently (v0.7.0 vs v0.5.5)
    severity Info · reachability default · intent contract-violation · confidence likely · independently confirmed · not reproduced (code trace)
    Failure scenario. An auditor cannot use the shipped artefacts to establish that the removed field was deprecated for the required window.
    Where. forgelm/config.py:1224-1226, docs/reference/configuration.md:268, docs/standards/release.md:109-111, docs/design/gdpr_erasure.md:79
    Recommended fix. Correct whichever statement is wrong so the code comment and the reference doc name the same deprecation release.

  • CR-A01-147 (code, Info) — baseline_loss allow_inf_nan=False (M4b) has no test in the five task files; the +inf case relies on a test in tests/test_trainer.py
    severity Info · reachability default · intent intended-and-acceptable · confidence likely · independently confirmed · reproduced end to end
    Failure scenario. A refactor drops allow_inf_nan from baseline_loss. The matrix and the other config tests still pass. baseline_loss: .inf then loads. The trainer demotes it to a warning and sets baseline_loss to None, so the configured regression-vs-baseline gate never fires and the run reports passed with no revert.
    Where. forgelm/config.py:1207-1211, tests/test_config_non_finite_matrix.py:43-47, forgelm/trainer.py:826-829, forgelm/trainer.py:892-893
    Recommended fix. Add ("evaluation.baseline_loss", ".inf", "a +inf baseline disarms the regression check") to the matrix at tests/test_config_non_finite_matrix.py:46-47. Fix the trainer comment that calls the baseline check informational.

  • CR-A01-148 (code, Info) — lora.task_type values other than CAUSAL_LM pass peft validation and silently train a CausalLM under the wrong PeftModel class, recording a wrong task_type and phantom modules_to_save
    severity Info · reachability undocumented · intent intended-but-harmful · confidence likely · independently confirmed · reproduced end to end
    Failure scenario. An operator experimenting with an encoder-style config sets task_type: SEQ_CLS. The run completes with exit 0 and success:true. The produced adapter is labelled SEQ_CLS with a classifier/score modules_to_save that does not exist. It is registered in the model card and compliance bundle as a sequence-classification fine-tune, although the training was causal-LM SFT. It is later loaded by a tool that trusts adapter_config.json.
    Where. forgelm/config.py:386-388, forgelm/model.py:534, forgelm/model.py:609, forgelm/inference.py:111-113
    Recommended fix. Constrain task_type to Literal['CAUSAL_LM'], since every ForgeLM trainer (SFT/DPO/SimPO/KTO/ORPO/GRPO) is causal-LM only. Alternatively, validate against the supported subset and reject the rest at schema time with exit 1. Add a test that every non-CAUSAL_LM value is rejected.

  • CR-A01-149 (code, Info) — pipeline.output_dir is never checked against stage dirs; nested inside a stage's final_model, that stage's auto-revert deletes the pipeline audit log, state and manifest mid-run, and verify-audit the…
    severity Info · reachability undocumented · intent intended-but-harmful · confidence likely · independently confirmed · reproduced end to end
    Failure scenario. Operator points pipeline.output_dir under a stage's final_model, for example to keep the index next to the deliverable. A failed gate in that stage erases the pipeline's Art. 12 records for the start of the run, and the verifiers report the remaining log as intact.
    Where. forgelm/config.py:2110-2119, forgelm/cli/_pipeline.py:1416-1417, forgelm/compliance.py:542-544, forgelm/compliance.py:607-608
    Recommended fix. Include pipeline.output_dir in the pre-flight scan. Refuse it inside any stage's output_dir/<final_model_dir>, or inside any stage output_dir at all, and either enforce 'Distinct' or reword the field description to match the guide.

  • CR-A01-150 (code, Info) — neftune_noise_alpha documentation and prompts are SFT-centric and misdescribe the mechanism
    severity Info · reachability default · intent intended-but-harmful · confidence likely · single reviewer · not reproduced (code trace)
    Failure scenario. Operators enable NEFTune on non-SFT trainers on the strength of 'improves training quality' wording.
    Where. forgelm/config.py:582-585, forgelm/wizard/_collectors.py:605-609, docs/usermanuals/en/training/long-context.md:107-115, tests/test_long_context.py:46-57
    Recommended fix. State 'uniform noise, SFT-oriented' in the field description, bound the value, and add a test that exercises each trainer's config build with the field set.

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.

Activity

  1. added
    bugSomething isn't working
    backlog: knownAlready tracked in docs/roadmap
    securitySecurity-relevant
    severity: lowMinor defect, inaccuracy or rough edge
    source: review-2026-10Found by the October 2026 code and documentation review
    wave: 4Roadmap wave 4: low / info / watch, when touching the module
    on Oct 9, 2026
  2. cemililik commented on Oct 9, 2026

    @cemililik
    CollaboratorAuthor

    Progress on development — verified 2026-10-09 at 08f2426.

    Fixed (ticked in the list above):

    • CR-A01-147 — a schema-derived test now feeds NaN and ±inf to every scalar float field, evaluation.baseline_loss included (08f2426)

    Partly fixed (still unticked):

    • CR-A01-138 — finite NumPy scalars are written as JSON numbers now (08f2426), but a torch scalar tensor and a NaN dict key still fail the strict writer

    Everything else in this issue is unchanged.

  3. cemililik commented on Oct 23, 2026

    @cemililik
    CollaboratorAuthor

    Note from #1058: forgelm purge --check-policy now reads its --config through _load_retention_policy (forgelm/cli/_config_load.py). That function reads and parses the YAML itself before it decides whether to call load_config, so a fix for CR-A01-137 has to cover that read as well. Today, a retention-only file with invalid UTF-8 still raises a raw UnicodeDecodeError there, just as load_config does for a full config.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: configCode area: configbacklog: knownAlready tracked in docs/roadmapbugSomething isn't workingsecuritySecurity-relevantseverity: lowMinor defect, inaccuracy or rough edgesource: review-2026-10Found by the October 2026 code and documentation reviewwave: 4Roadmap wave 4: low / info / watch, when touching the module

    Type

    No type

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions