Skip to content

[Wave 3] Medium — Module sweep: CLI framework: parser, dispatch, exit-code contract, logging #542

Open

Description

@cemililik

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

Findings

  • CR-A05-007 (code, Medium) — Top-level --output DIR (documented as the --compliance-export directory, default ./compliance) is parsed but never read
    severity Medium · reachability default · intent contract-violation · confidence confirmed · independently confirmed · reproduced end to end
    Failure scenario. An operator expects artefacts in B and archives an empty or stale directory.
    Where. forgelm/cli/_parser.py:1454-1460 (--output declaration; --compliance-export at 1443-1453 takes a required OUTPUT_DIR), forgelm/cli/_no_train_modes.py:281-283 (only args.compliance_export passed), forgelm/cli/_parser.py:1452-1458, forgelm/cli/_no_train_modes.py:281-283 (confirmed)
    Recommended fix. Remove the flag, or wire it and reject a conflicting combination.

  • CR-A05-008 (code, Medium) — Chat --temperature 0 passes CLI validation, then every generation fails because sampling always uses do_sample=True
    severity Medium · reachability default · intent contract-violation · confidence confirmed · independently confirmed · reproduced end to end · already tracked: KNOWN-OPEN CLI-17 — docs/roadmap/phase-16-trust-surface-hardening.md:480,500-501 (S7 open; unit id inferred from commit-2 ordering)
    Failure scenario. Operator wanting deterministic output passes --temperature 0 and gets an error on every turn (exit 0 at EOF).
    Where. forgelm/cli/_argparse_types.py:60-74, forgelm/cli/_parser.py:48-53, forgelm/inference.py:248-249 (confirmed), forgelm/inference.py:306-307 (confirmed)
    Recommended fix. Map temperature<=0 to do_sample=False in generate/generate_stream, or make the CLI type exclusive of 0 and align help/docs.

  • ↳ same root cause: DOC-BHELP-005 (docs, Medium) — forgelm: wrong detail — 'Sampling temperature in [0.0, 2.0] (default: 0.7).'
    severity Medium · already tracked: KNOWN-OPEN CLI-17/CLI-18 (inferred) — docs/roadmap/phase-16-trust-surface-hardening.md:500
    Where. forgelm/cli/_parser.py:48-53 (--temperature) · type: wrong detail
    The document says. 'Sampling temperature in [0.0, 2.0] (default: 0.7).'
    What the code does. The CLI accepts 0.0, but every generation then fails. Verified on env/tiny-qwen: generate(temperature=0.0) raises ValueError 'temperature (=0.0) has to be a strictly positive float'. The REPL swallows it as '[Generation error]' on every turn. In-session /temperature requires 0.0 < t <= 2.0.
    Code references. forgelm/cli/_argparse_types.py:78-92, forgelm/inference.py:219-249, forgelm/chat.py:204,262-285
    Proposed correction. Reject 0.0 at parse time (range (0.0, 2.0]) or map 0 to do_sample=False. Update the help to match.

  • CR-A05-009 (code, Medium) — Top-level --offline is accepted with every subcommand but never applied; quickstart forwards it to a chat child that ignores it
    severity Medium · reachability default · intent contract-violation · confidence confirmed · independently confirmed · reproduced end to end · already tracked: KNOWN-OPEN CLI-04 — docs/roadmap/phase-16-trust-surface-hardening.md:482-489,509-510 (S7 open)
    Failure scenario. An operator on a policy-offline (but connected) host runs forgelm --offline safety-eval --model org/model --default-probes. The model and the Llama Guard classifier are fetched from the Hub, so the operator does not get the local-only evaluation the flag implies. On a truly air-gapped host, the run instead fails on a network timeout rather than a clear 'not cached' error.
    Where. forgelm/cli/_parser.py:1368-1372, forgelm/cli/_dispatch.py:221-225, forgelm/cli/_dispatch.py:243 (confirmed), forgelm/cli/_config_load.py:50-56
    Recommended fix. Call _apply_offline_flag-equivalent env setting before _dispatch_subcommand when args.offline is set, or reject top-level --offline with subcommands that ignore it. Remove the dead forwarding in quickstart or make chat honour it.

  • CR-A05-010 (code, Medium) — Ingest --chunk-tokens 0 is accepted and silently falls back to character chunking, although --help says 0 is rejected
    severity Medium · reachability default · intent contract-violation · confidence confirmed · independently confirmed · reproduced end to end
    Failure scenario. A script computes --chunk-tokens $BUDGET and the budget evaluates to 0. Ingest succeeds with 2048-character chunks that can exceed the model's max_length, so training silently truncates. The run's notes claim token mode was used.
    Where. forgelm/cli/_parser.py:282-293, forgelm/cli/_parser.py:291, forgelm/cli/_parser.py:213, forgelm/cli/_parser.py:225
    Recommended fix. Type --chunk-tokens with _positive_int (and --chunk-size with _positive_int, --overlap with _non_negative_int). Change ingestion.py:2092 to chunk_tokens is not None. Reject or log a non-zero --overlap under paragraph.

  • CR-A05-011 (code, Medium) — --resume is silently ignored on a pipeline: config; the run restarts every stage and exits 0
    severity Medium · reachability default · intent contract-violation · confidence confirmed · independently confirmed · reproduced end to end
    Failure scenario. 'forgelm --config minimal_3_stage.yaml --resume' starts every stage from scratch with no warning, retraining completed stages and overwriting their outputs.
    Where. forgelm/cli/_dispatch.py:253-260 (the asymmetric single-stage guard), forgelm/cli/_pipeline.py:1738-1754 (the tuple and its loop; 1725-1737 is the explanatory comment), forgelm/cli/_pipeline.py:1738-1754, forgelm/cli/_parser.py:1360-1366 (--resume defined as a global flag; its help does not say it is single-stage only)
    Recommended fix. Add ('resume', '--resume') to _UNSUPPORTED_ON_PIPELINE, pointing the operator at --resume-from.

  • CR-A05-013 (code, Medium) — --pii-ml-language help advertises 'tr', which is unsupported; the ValueError escapes as a traceback with exit 1 and no JSON envelope
    severity Medium · reachability documented-opt-in · intent contract-violation · confidence confirmed · independently confirmed · reproduced end to end
    Failure scenario. A Turkish operator follows the help text and the run aborts with a Python traceback instead of a clear config error.
    Where. forgelm/cli/_parser.py:618-630 (the --pii-ml-language add_argument), forgelm/data_audit/_pii_ml.py:36-53, forgelm/data_audit/_pii_ml.py:101-110 (the ValueError raise), forgelm/data_audit/_orchestrator.py:268-272 (the docstring that also advertises 'tr')
    Recommended fix. Fix the help text to name 'xx' for unsupported languages, and handle ValueError in _run_data_audit as a config error with the JSON envelope.

  • CR-A05-017 (code, Medium) — product_strategy.md:74 documents a nonexistent forgelm wizard subcommand (and configuration.md a nonexistent forgelm compliance-only)
    severity Medium · reachability default · intent contract-violation · confidence confirmed · independently confirmed · reproduced end to end
    Failure scenario. A new user reads product_strategy.md and types forgelm wizard. argparse rejects it with exit 2, with no hint that the flag form is --wizard.
    Where. docs/product_strategy.md:74, docs/product_strategy-tr.md:74, docs/guides/pipeline.md:293, docs/guides/pipeline-tr.md:296
    Recommended fix. Use forgelm --wizard (EN and TR) in product_strategy and the pipeline guides, and change 'will provide' to the present tense for the shipped quickstart templates.

  • CR-A05-018 (code, Medium) — No test parses a top-level flag placed before a subcommand that re-declares the dest (G-A05-01 confirmed; destructive consequence shown for purge)
    severity Medium · reachability default · intent contract-violation · confidence confirmed · independently confirmed · reproduced end to end
    Where. forgelm/cli/_parser.py:182, forgelm/cli/_parser.py:485, forgelm/cli/_parser.py:1159, tests/test_cli_subcommands.py
    Recommended fix. Add to tests/test_cli_subcommands.py (or a new tests/test_cli_parser_precedence.py), calling parse_args with patched sys.argv. (1) Parametrized table asserting the parsed value for ['--dry-run','purge','--row-id','1','--corpus','c.jsonl'] -> dry_run is True; ['--dry-run','quickstart','customer-support'] -> dry_run True; ['--config','a.yaml','purge','--row-id','1','--corpus','c'] -> config == 'a…

  • CR-A05-019 (code, Medium) — Extends M-A09-006 (not a new defect): H-A09-10 is a duplicate. More places tell operators that verify-annex-iv --pipeline exits 0 without saying it needs FORGELM_AUDIT_SECRET and a root audit log sig…
    severity Medium · reachability default · intent contract-violation · confidence confirmed · independently confirmed · reproduced end to end
    Failure scenario. An operator follows docs/guides/pipeline.md or verify_annex_iv_subcommand.md and runs a pipeline without exporting FORGELM_AUDIT_SECRET, or later appends one unsigned line to the pipeline root log. Every later forgelm verify-annex-iv --pipeline <run_dir> then exits 1 ('FAIL', unattested), even when every structural, chain and evidence check passes. --help says 'Exits 0 on valid', and the reference doc's examples show exit 0, so the operator cannot tell from those docs why. The run can never b…
    Where. forgelm/cli/_parser.py:829-836, forgelm/cli/_parser.py:850-855, forgelm/compliance.py:3396-3404, forgelm/compliance.py:3437-3443
    Recommended fix. Merge H-A09-10 into M-A09-006. Extend M-A09-006's locations with _parser.py:833-835 and :850-855, the reference-doc lines above (EN and TR), docs/guides/pipeline.md:241-255 (EN and TR), and the stale docstrings. One fix covers them all: state in --help, the reference doc and the pipeline guide that a pipeline exits 0 only when FORGELM_AUDIT_SECRET was set during the run and at verification time a…

  • CR-A05-020 (code, Medium) — Docs, site, wizard and the cache-tasks docs show a 'truthfulqa' score/status key that the code never produces
    severity Medium · reachability default · intent contract-violation · confidence likely (static only) · independently confirmed · not reproduced (code trace)
    Where. docs/usermanuals/en/evaluation/benchmarks.md:43, docs/usermanuals/en/evaluation/benchmarks.md:78-96, docs/usermanuals/en/evaluation/benchmarks.md:111-114, docs/usermanuals/en/operations/experiment-tracking.md:116
    Recommended fix. Use one concrete leaf (truthfulqa_mc2 is the usual headline) in all examples and help text, or document the expansion and the resulting key names.

  • CR-A05-021 (code, Medium) — Audit has no rendered-sample / chat-template preview promised by the SFT guide
    severity Medium · reachability default · intent contract-violation · confidence confirmed · independently confirmed · reproduced end to end
    Failure scenario. An operator who switches model.name_or_path and follows the pitfall advice finds no preview and cannot do the check the guide describes. The tokenizer-mismatch diagnosis it offers cannot be carried out.
    Where. forgelm/cli/_parser.py:498-680, forgelm/data_audit/_orchestrator.py:227-240, docs/usermanuals/en/training/sft.md:117, docs/usermanuals/tr/training/sft.md:117
    Recommended fix. Remove the claim, or add an optional --model to audit that renders N samples the same way the trainer does.

  • CR-A05-022 (code, Medium) — pii-masking.md tells users to pass --pii-ml-language over a forgelm ingest example; ingest rejects the flag
    severity Medium · reachability default · intent contract-violation · confidence confirmed · independently confirmed · reproduced end to end
    Failure scenario. A user follows the paragraph, gets an argparse error, or believes a locale-aware ML pass ran during ingest.
    Where. docs/usermanuals/en/data/pii-masking.md:94-98, docs/usermanuals/tr/data/pii-masking.md:93-97, forgelm/cli/_parser.py:618-629
    Recommended fix. Delete the paragraph and its ingest example, or reword it to point to forgelm audit --pii-ml --pii-ml-language.

  • CR-A05-023 (code, Medium) — QMS SoA/RTP credit forgelm audit with masking and Presidio ML-NER as the A.8.11 data-masking control; the audit only counts, and ML-NER never masks anywhere
    severity Medium · reachability default · intent contract-violation · confidence confirmed · independently confirmed · reproduced end to end
    Failure scenario. An ISO auditor accepts A.8.11 as implemented by forgelm audit. The deployer runs the audit, gets counts, and trains on the unmasked corpus, believing masking happened. A PERSON/ORG name found only by Presidio is never masked by any ForgeLM path.
    Where. docs/qms/statement_of_applicability.md:63, docs/qms/statement_of_applicability.md:119, docs/qms/statement_of_applicability-tr.md:64, docs/qms/statement_of_applicability-tr.md:120
    Recommended fix. Re-attribute A.5.34 and A.8.11 masking to forgelm ingest --pii-mask/--secrets-mask (regex only). Describe Presidio as opt-in detection only. Either drop 'review of flagged rows' or add row locators to the report.

  • CR-A05-024 (code, Medium) — Data-management SOP documents a non-existent forgelm ingest --pii-ml and calls the default-on quality filter optional
    severity Medium · reachability default · intent contract-violation · confidence confirmed · independently confirmed · reproduced end to end
    Failure scenario. An SOP-following operator plans ML-NER redaction at ingest. The command fails, or they assume names were scrubbed when no ingest path can do it.
    Where. docs/qms/sop_data_management.md:104-106, docs/qms/sop_data_management.md:84, docs/qms/sop_data_management-tr.md:106, docs/qms/sop_data_management-tr.md:96-97
    Recommended fix. Remove --pii-ml from the ingest bullet (it is audit-only, detection-only), describe the quality filter as default-on with --no-quality-filter, and complete the secrets family list.

  • CR-A05-025 (code, Medium) — PII masking presented as an inherent ingest step ('Masks at ingest time', 'PII redacted at ingest'), but forgelm ingest masks nothing unless --pii-mask/--all-mask is passed
    severity Medium · reachability default · intent contract-violation · confidence confirmed · independently confirmed · not reproduced (code trace)
    Failure scenario. An operator follows the homepage use case ('drop your corpus into forgelm ingest') and runs forgelm ingest docs/ --output data.jsonl. Emails, phone numbers and IBANs from the regulatory PDFs reach the training JSONL unmasked, although the site said PII is redacted at ingest.
    Where. forgelm/cli/_parser.py:256-280, forgelm/data_audit/_pii_regex.py:39-88, site/js/translations.js:986, site/js/translations.js:1091
    Recommended fix. Name the flag in both keys across six locales ('pass --all-mask to redact PII and secrets at ingest').

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
    documentationImprovements or additions to documentation
    backlog: knownAlready tracked in docs/roadmap
    severity: mediumReal defect with limited reach or a workaround
    source: review-2026-10Found by the October 2026 code and documentation review
    wave: 3Roadmap wave 3: medium severity, module sweeps
    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 workingdocumentationImprovements or additions to documentationseverity: mediumReal defect with limited reach or a workaroundsource: review-2026-10Found by the October 2026 code and documentation reviewwave: 3Roadmap wave 3: medium severity, module sweeps

    Type

    No type

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions