Skip to content

[Wave 4] Low/info — Module sweep: CLI framework: parser, dispatch, exit-code contract, logging (part 2/3) #654

Open

Description

@cemililik

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-A05-046 (code, Low) — Ingest --help drift: --normalise-profile claims 'turkish' is the default and --keep-frontmatter quotes alpha < 0.45 / underscore thresholds the code does not use
    severity Low · reachability default · intent contract-violation · confidence likely · single reviewer · reproduced end to end
    Failure scenario. An operator reading --help believes Turkish normalisation is always on, or misjudges which ToC pages will be dropped.
    Where. forgelm/cli/_parser.py:360 (confirmed), forgelm/cli/_parser.py:441, forgelm/_pypdf_normalise.py:91 (confirmed), forgelm/ingestion.py:708 (confirmed)
    Recommended fix. Update the help strings and the architecture reference, and correct the F-034 promise wording.

  • CR-A05-047 (code, Low) — Quickstart --output help and run_quickstart docstring describe a non-existent default path
    severity Low · reachability default · intent contract-violation · confidence likely · single reviewer · reproduced end to end
    Failure scenario. CI script globs configs/customer-support-*.yaml after quickstart and finds nothing.
    Where. forgelm/cli/_parser.py:179 (confirmed), forgelm/quickstart.py:337, forgelm/quickstart.py:431 (confirmed), forgelm/quickstart.py:329
    Recommended fix. Change the help string and docstring to ./configs/-/config.yaml.

  • CR-A05-048 (code, Low) — cache-models accepts 'local path' per help, but local paths fail with a runtime-class exit 2
    severity Low · reachability default · intent contract-violation · confidence likely · single reviewer · reproduced end to end · already tracked: KNOWN-OPEN CLI-18 — docs/roadmap/phase-16-trust-surface-hardening.md:480,501 (S7 open; unit id inferred from commit-2 ordering)
    Failure scenario. CI retries on exit 2 forever for what is a usage error.
    Where. forgelm/cli/_parser.py:998, forgelm/cli/subcommands/_cache.py:243-253, forgelm/cli/subcommands/_cache.py:336-346, docs/reference/cache_subcommands.md:25
    Recommended fix. Drop 'or local path' from help and docs, or reject path-like names with exit 1.

  • CR-A05-049 (code, Low) — Library error section describes exit codes 0/1/2/3/4; the public contract is 0-6
    severity Low · reachability default · intent contract-violation · confidence likely · single reviewer · not reproduced (code trace) · already tracked: KNOWN-OPEN C31-EXIT-CODE-PROSE — docs/roadmap/phase-16-trust-surface-hardening.md:196-197,782-785,790-792 (S15 open)
    Failure scenario. A reader mapping library results onto CLI behaviour omits exit 6 for integrity failures.
    Where. docs/reference/library_api_reference.md:260, docs/reference/library_api_reference-tr.md:260, forgelm/cli/_exit_codes.py:10-14, forgelm/cli/_exit_codes.py:21
    Recommended fix. Say 0 through 6 and link the table.

  • CR-A05-050 (code, Low) — No test that a non-public SystemExit raised inside a dispatcher is clamped (G-A05-03 confirmed; the quickstart rc map is the sole barrier)
    severity Low · reachability default · intent intended-but-harmful · confidence likely · independently confirmed · reproduced end to end
    Where. forgelm/cli/_dispatch.py:113-122, forgelm/cli/_dispatch.py:210, forgelm/cli/subcommands/_quickstart.py:148, tests/test_verification_toolbelt.py:1825-1830
    Recommended fix. Add to tests/test_cli_subcommands.py: parametrize code over [7,137,143,-9] and over a few subcommands, patch the matching forgelm.cli._run_<name>_cmd to sys.exit(code), call main() with the subcommand argv, and assert the exit code is 2 (or xfail(strict=True) until the seam clamps SystemExit). Add one case where the dispatcher exits with each public code (0-6) and assert pass-through, so a clam…

  • CR-A05-051 (code, Low) — On Python 3.14.0-3.14.6 python -m forgelm[.cli] prints python3.14 -m forgelm... as prog: the sys.argv[0] normalisation is bypassed
    severity Low · reachability undocumented · intent intended-but-harmful · confidence likely (static only) · single reviewer · reproduced end to end
    Failure scenario. An operator on a distro or container shipping CPython 3.14.0-3.14.6 runs python -m forgelm.cli audit --bogus and gets python3.14 -m forgelm.cli audit: error: ... instead of forgelm audit: error:. The prog-normalisation tests fail on that interpreter and the 'identical help' contract between the two module entry points breaks.
    Where. forgelm/__main__.py:36, forgelm/cli/__main__.py:21, tests/test_main_module.py:138, tests/test_main_module.py:154
    Recommended fix. Either add 3.14 to the CI and publish matrices (setup-python gives >=3.14.7, so the fix is present) and decide the supported patch floor, or make the normalisation robust by passing prog="forgelm" explicitly to ArgumentParser instead of relying on sys.argv[0].

  • CR-A05-052 (code, Low) — Remaining docstring and comment drift around the ingest flags (help-text verdict leftovers)
    severity Low · reachability default · intent contract-violation · confidence likely · single reviewer · not reproduced (code trace)
    Failure scenario. An operator who reads the help or docstrings forms the wrong model. For example, a PDF with blank cover pages followed by a 12-page ToC gets its probe window shifted past physical page 12. A maintainer who reads DEFAULT_TIMEOUT_S expects an abort where the code skips the pattern. None of these changes the output on its own.
    Where. forgelm/cli/_parser.py:440, forgelm/ingestion.py:661, forgelm/ingestion.py:795, forgelm/cli/_parser.py:231
    Recommended fix. Reword: '--keep-frontmatter: the first/last 12 text-bearing pages (within --page-range) are probed; a contiguous edge run of pages where all three signals fire is dropped'; '--overlap default: min(200, chunk_size // 2)'; ingest_path docstring 'an INFO note'; DEFAULT_TIMEOUT_S 'skips the pattern with a WARNING'; fix the 640-642 comment.

  • CR-A05-053 (code, Low) — Doctor --offline help omits HF_DATASETS_OFFLINE; the docs agree with the code, so only the help text and the module docstring are stale
    severity Low · reachability default · intent contract-violation · confidence likely · independently confirmed · reproduced end to end
    Failure scenario. A training host exports HF_DATASETS_OFFLINE=1 only, so datasets stays offline while the Hub is reachable. Following --help, the operator expects doctor to probe Hub reachability. Doctor silently runs the offline-cache probe instead, and hf_hub.reachable is never checked.
    Where. forgelm/cli/_parser.py:487-492, forgelm/cli/subcommands/_doctor.py:24-28, forgelm/cli/subcommands/_doctor.py:1179-1194, docs/reference/doctor_subcommand.md:19
    Recommended fix. Add 'or HF_DATASETS_OFFLINE=1' to the --offline help in _parser.py:491-492 and to the env-var list in the _doctor.py module docstring.

  • CR-A05-054 (code, Low) — Roadmap records per-turn chat safety via the YAML safety block as completed, but chat reads no config and silently ignores a top-level --config
    severity Low · reachability default · intent contract-violation · confidence likely · single reviewer · reproduced end to end
    Failure scenario. An operator who believes the roadmap writes evaluation.safety.enabled: true and launches 'forgelm --config cfg.yaml chat ./model'. They get an unscreened REPL with exit 0 and nothing indicating that safety screening is off.
    Where. forgelm/cli/_dispatch.py:219-225, forgelm/cli/_parser.py:35-67, forgelm/cli/subcommands/_chat.py, docs/roadmap/completed-phases.md:673
    Recommended fix. Correct the roadmap entry to 'planned'. Warn, or exit with an error, when a top-level --config is given together with a subcommand that ignores it.

  • CR-A05-055 (code, Low) — Conflicting deferral wording for ML quality classifiers, and stale 'opt-in' labels for the default-on quality filter
    severity Low · reachability default · intent contract-violation · confidence likely · independently confirmed · reproduced end to end
    Failure scenario. An operator reading --help expects ML classifiers in a future release, while the guide says they will never come. A library caller of audit_dataset() gets no quality_summary even though the docs say the filter is default-on.
    Where. forgelm/cli/_parser.py:584-594, docs/guides/data_audit.md:357, docs/guides/data_audit.md:395-397, forgelm/data_audit/_quality.py:1
    Recommended fix. Align the parser help with the guide ('out of scope') or the reverse, update the stale opt-in labels, and document the library-vs-CLI default difference or align the defaults.

  • CR-A05-056 (code, Low) — performance.md says audit_dataset workers parallelise 'over multiple corpora'; they parallelise splits of one source
    severity Low · reachability default · intent contract-violation · confidence likely · single reviewer · not reproduced (code trace)
    Failure scenario. A user expects workers to fan out across several corpora and passes them one at a time, getting no speed-up on a single-split corpus.
    Where. docs/guides/performance.md:183, forgelm/cli/_parser.py:632-640
    Recommended fix. Say 'parallelises the per-split pipeline (train/validation/test) of one source'.

  • CR-A05-057 (code, Low) — The forgelm.cli facade exposes ~138 private names as patch targets, but only 28 are read through it; the project's own test rule and the 'surface' tests hide the difference
    severity Low · reachability unreachable · intent intended-but-harmful · confidence likely · single reviewer · reproduced end to end
    Where. forgelm/cli/__init__.py:8-14, forgelm/cli/__init__.py:258-281, forgelm/cli/_dispatch.py:69-101, forgelm/cli/subcommands/_approve.py:545
    Recommended fix. Add a guard or test that, for every facade name tests patch, proves production reads it through the facade, for example a tools/ check cross-referencing patch('forgelm.cli.X') targets with _cli_facade.X call sites. Alternatively, have tests patch the owning submodule name and drop the unconsulted re-exports. Make _approve.py:545/687 consistent with _approvals.py:186. Replace the hasattr 'surface'…

  • CR-A05-058 (code, Low) — Logger format and text summaries pass attacker-chosen file names and split names unescaped: ESC sequences and forged log lines
    severity Low · reachability default · intent intended-but-harmful · confidence likely · single reviewer · reproduced end to end
    Failure scenario. A corpus handed over as an archive with crafted member names produces forged INFO/ERROR lines or screen rewrites in CI logs and operator terminals; log-scraping based on line shape is misled.
    Where. forgelm/cli/_logging.py:29-33, forgelm/ingestion.py:2074, forgelm/ingestion.py:2185, forgelm/data_audit/_streaming.py:214
    Recommended fix. Install a logging.Formatter (or Filter) in _setup_logging that escapes control characters in the final message (newline and CR to \n/\r literals, other C0/C1 and DEL to \xNN), and pass names through !r / ascii() in the summary renderers.

  • CR-A05-059 (code, Low) — forgelm.cli is declared 'public' in code and in standards, but 'internal, zero guarantee' in the library API contract; none of main, parse_args or EXIT_* is in any library tier
    severity Low · reachability default · intent contract-violation · confidence confirmed · independently confirmed · reproduced end to end
    Where. forgelm/cli/__init__.py:1-19, forgelm/cli/__init__.py:258-281, forgelm/__init__.py:142-177, docs/reference/library_api_reference.md:29
    Recommended fix. Add one explicit tier row to library_api_reference.md (EN and TR) and docs/design/library_api.md. Suggested wording: 'forgelm.cli: main, parse_args and the seven EXIT_* constants are Stable-by-convention (console-script and exit-code contract); everything underscore-prefixed in forgelm.cli is Internal, even where re-exported for tests'. Reword the cli/init.py docstring and the '10 underscore…

  • CR-A05-060 (code, Low) — main() and parse_args() take no argv and main() never returns: the in-process contract is undocumented, and the only documented call shape (design doc) does not exist
    severity Low · reachability default · intent intended-but-harmful · confidence likely · single reviewer · reproduced end to end
    Where. forgelm/cli/_dispatch.py:156, forgelm/cli/_parser.py:1275, forgelm/__main__.py:33, docs/design/data_audit_cli_split.md:386
    Recommended fix. Document in library_api_reference.md (EN and TR) a short 'Driving the CLI in-process' note. Say main() and parse_args() read sys.argv, main() always raises SystemExit whose .code is the 0-6 contract, and library callers wanting a return value should call the subprocess form or the library functions. Alternatively, plan an additive main(argv: Sequence[str] | None = None) in a future change, whic…

  • CR-A05-061 (code, Low) — data_audit_cli_split.md describes a stale forgelm.cli surface: 5 exit codes, nonexistent import-stability test, and a lazy facade design that was not implemented
    severity Low · reachability default · intent contract-violation · confidence likely · single reviewer · reproduced end to end
    Where. docs/design/data_audit_cli_split.md:11, docs/design/data_audit_cli_split.md:380-386, docs/design/data_audit_cli_split.md:464-481, docs/design/data_audit_cli_split.md:511
    Recommended fix. Edit the design docs: correct the §2.e all and the exit-code acceptance list to 0-6, and mark the cli lazy-facade section 'not implemented / superseded'. Either ship tests/test_cli_import_stability.py (assert all names resolve, the _PUBLIC_EXIT_CODES set equals {0..6}, and main/parse_args are callable) or delete the claim. This is a docs-only edit; no code change.

  • CR-A05-062 (code, Low) — Architecture reference drift cluster: stale TXT/MD read, 'info-level' override log, stale line refs, incomplete field table, 'pre-flight' markdown overlap
    severity Low · reachability default · intent contract-violation · confidence likely · single reviewer · not reproduced (code trace)
    Failure scenario. Contributors and integrators rely on line refs, field lists and log levels that no longer exist.
    Where. docs/reference/data_ingestion_architecture.md:38, docs/reference/data_ingestion_architecture.md:193, docs/reference/data_ingestion_architecture.md:370, docs/reference/data_ingestion_architecture.md:443
    Recommended fix. Drop line numbers in favour of symbol names; regenerate the field table from dataclasses.fields(IngestionResult); fix the three stale statements; document the atomic-write semantics in the invariants list.

  • CR-A05-063 (code, Low) — configuration.md (EN+TR) implies 'forgelm doctor' would catch an unfetchable revision pin; doctor reads no config and checks no pin
    severity Low · reachability default · intent contract-violation · confidence likely · single reviewer · not reproduced (code trace)
    Failure scenario. A CI author adds 'forgelm doctor' after '--dry-run', as the known-gaps note suggests, expecting unfetchable pins to fail fast. Doctor passes, and the run still fails at model-load time.
    Where. docs/reference/configuration.md:646-648, docs/reference/configuration-tr.md:644-646, forgelm/cli/_parser.py:462-495, forgelm/cli/subcommands/_doctor.py:464-562
    Recommended fix. Rewrite the bullet: nothing before load time checks pin fetchability, doctor included. Or add a config-aware pin probe.

  • CR-A05-064 (code, Low) — Purge --row-id / reverse-pii --query are argv-only, and the docs promise the cleartext identifier never leaves the terminal and show no safe invocation
    severity Low · reachability default · intent intended-but-harmful · confidence likely · single reviewer · reproduced end to end
    Where. forgelm/cli/_parser.py:1097-1102, forgelm/cli/_parser.py:1196-1202, forgelm/cli/_parser.py:1204-1209, docs/guides/gdpr_erasure.md:31-36
    Recommended fix. Add a hardening option (e.g. --query-file / --row-id-file or '-' for stdin, or an *_env selector), and until then document the exposure: warn about ps, shell history and CI logs, and recommend a leading space or HISTCONTROL, a secret-masked CI variable, or the stdin option. Reword 'never leaves the operator's terminal' to say it is never written by ForgeLM to the audit log or envelopes. Add the j…

  • CR-A05-065 (code, Low) — GDPR guide, user manual and design spec (EN+TR) state the project-wide exit contract as 0/1/2/3/4 (new cluster; not covered by M-A05-017 or M5r1-A05-002)
    severity Low · reachability default · intent contract-violation · confidence likely · single reviewer · not reproduced (code trace) · already tracked: KNOWN-OPEN C31-EXIT-CODE-PROSE — docs/roadmap/phase-16-trust-surface-hardening.md:782-785 (S15 open)
    Failure scenario. A reader of the GDPR guide concludes that no ForgeLM subcommand can exit 5 or 6. Their CI case statement then has no branch for the integrity code, which cicd.md:22 warns 'should never fall through to a generic default'.
    Where. docs/guides/gdpr_erasure.md:71, docs/guides/gdpr_erasure-tr.md:71, docs/usermanuals/en/compliance/gdpr-erasure.md:96, docs/usermanuals/tr/compliance/gdpr-erasure.md:96
    Recommended fix. Replace the range with 'the public 0-6 contract (purge/reverse-pii emit only 0/1/2)'. Extend the :104 note to name 3-6. Update design §4.3 to cite _PUBLIC_EXIT_CODES instead of an enumerated range.

  • 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
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: cliCode area: clibacklog: 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