You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Triage] Help parsing is sensitive to ANSI colour (latent on Python 3.14): coloured {choices} silently disable choice-value drift checking (CR-A17a-053) #829
Needs triage. Reviewers disagreed on this finding, so it is not counted in the backlog. Decide whether it is a real defect: if yes, set severity and wave; if not, close it with the reason.
CR-A17a-053 — Help parsing is sensitive to ANSI colour (latent on Python 3.14): coloured {choices} silently disable choice-value drift checking
severity Info · confidence disputed · single reviewer · reproduced with stubs
What happens. The tool does not scrub FORCE_COLOR, PYTHON_COLORS or NO_COLOR for the child and does not strip ANSI. On the real default lane (Python 3.13.14), FORCE_COLOR=1 and PYTHON_COLORS=1, alone and together, change nothing: 0 ESC bytes, 130 identical help lines, and the tool prints OK 515, exit 0. Python 3.14's coloured argparse is not in the classifiers (3.10-3.13) or the ci.yml matrix and no 3.14 interpreter was available here, so the following is a stub-level test only. With synthetic ANSI wrapped around the COMMAND metavar, _parse_subcommand_list returns [] (a loud RuntimeError, exit 1). With ANSI wrapped around {a,b,c}, _FLAG_CHOICES_RE no longer matches: the choices map becomes {} while the flag set stays equal, which silently disables the choice-value check.
Failure scenario. On a future 3.14 lane or any harness exporting FORCE_COLOR=1, if argparse colours the choice braces (exact 3.14 layout not verified), 'forgelm export --quant q9' in docs would pass although the parser rejects it. The failure is not visible in the run output.
Recommended fix. Run the child with env NO_COLOR=1 and without FORCE_COLOR/PYTHON_COLORS (or strip ANSI before parsing). Add a test with injected ANSI text. Fail loudly if any subcommand ends with an empty choices map where the previous release had one.
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.
Checked on development: on Python 3.13, FORCE_COLOR=1 and PYTHON_COLORS=1 change nothing (no escape bytes, identical help, same parsed surface), so nothing is broken on a supported interpreter today.
With synthetic ANSI around the flags and {choices}, the parser keeps the flags but returns an empty choice map, and a coloured COMMAND line makes the subcommand list parse fail loudly. We have no 3.14 interpreter to confirm the real layout. It is less silent than described: test_deploy_target_choices_recovered asserts the choices are recovered and would fail in the same environment.
Kept as low-priority hardening: run the child with colour disabled (and/or strip ANSI) and add a test with injected ANSI, ideally together with adding 3.14 to CI (#526).
_run_help() (about line 123) runs python3 -m forgelm.cli ... --help with the parent's environment and parses the text. Python 3.14's argparse can colour its help; whether it does depends on FORCE_COLOR, PYTHON_COLORS and NO_COLOR. If it does, the escape bytes break two parsers:
_parse_subcommand_list stops finding the COMMAND line, which raises a loud RuntimeError;
_FLAG_CHOICES_RE stops matching --flag {a,b,c}, so the choice map comes back empty while the flag set looks fine, and drift in choice values goes unchecked.
On Python 3.13 colour changes nothing, so nothing is broken today; this is hardening.
What to change (decided, so you do not need to choose):
In _run_help, pass env= to subprocess.run: a copy of os.environ without FORCE_COLOR, with NO_COLOR=1 and PYTHON_COLORS=0.
Add a small _strip_ansi(text) helper and apply it to the text _run_help returns, as a second line of defence. Use a bounded pattern such as \x1b\[[0-9;]{0,32}m (regex standard).
Add the tests to tests/test_check_cli_help_consistency.py. Copy test_deploy_target_choices_recovered in TestParserSurfaceDiscovery and use the tool fixture:
Run _strip_ansi on a --target {a,b} line with escape codes around the flag and around the braces. Then _parse_usage_flags(...) returns the choice map. Do the same for a coloured COMMAND line and _parse_subcommand_list.
monkeypatch.setenv("FORCE_COLOR", "1"), replace tool.subprocess.run with a fake that records its keyword arguments, and call _run_help(["--help"]). Assert that the recorded env has no FORCE_COLOR, that NO_COLOR == "1" and that PYTHON_COLORS == "0".
No GPU, network access or model download is needed. Add an entry under ## [Unreleased] in CHANGELOG.md, where earlier guard changes are listed. The change is tooling only, so there is no Turkish mirror to update.
Open the PR against development with Fixes #829 (finding CR-A17a-053).
Activity
cemililik commentedon Oct 20, 2026
Checked on development: on Python 3.13, FORCE_COLOR=1 and PYTHON_COLORS=1 change nothing (no escape bytes, identical help, same parsed surface), so nothing is broken on a supported interpreter today.
With synthetic ANSI around the flags and {choices}, the parser keeps the flags but returns an empty choice map, and a coloured COMMAND line makes the subcommand list parse fail loudly. We have no 3.14 interpreter to confirm the real layout. It is less silent than described: test_deploy_target_choices_recovered asserts the choices are recovered and would fail in the same environment.
Kept as low-priority hardening: run the child with colour disabled (and/or strip ANSI) and add a test with injected ANSI, ideally together with adding 3.14 to CI (#526).
Triage result:
enhancement,area: dev-tooling,severity: info,wave: 4.Triage round 1, checked against
developmenton 2026-10-20.cemililik commentedon Oct 22, 2026
Where to start
Thanks for taking a look. Claim it by starting a comment with
/assignso nobody duplicates the work.Start with these files on
development:_run_help()(about line 123) runspython3 -m forgelm.cli ... --helpwith the parent's environment and parses the text. Python 3.14's argparse can colour its help; whether it does depends onFORCE_COLOR,PYTHON_COLORSandNO_COLOR. If it does, the escape bytes break two parsers:_parse_subcommand_liststops finding theCOMMANDline, which raises a loudRuntimeError;_FLAG_CHOICES_REstops matching--flag {a,b,c}, so the choice map comes back empty while the flag set looks fine, and drift in choice values goes unchecked.On Python 3.13 colour changes nothing, so nothing is broken today; this is hardening.
What to change (decided, so you do not need to choose):
_run_help, passenv=tosubprocess.run: a copy ofos.environwithoutFORCE_COLOR, withNO_COLOR=1andPYTHON_COLORS=0._strip_ansi(text)helper and apply it to the text_run_helpreturns, as a second line of defence. Use a bounded pattern such as\x1b\[[0-9;]{0,32}m(regex standard).Add the tests to
tests/test_check_cli_help_consistency.py. Copytest_deploy_target_choices_recoveredinTestParserSurfaceDiscoveryand use thetoolfixture:_strip_ansion a--target {a,b}line with escape codes around the flag and around the braces. Then_parse_usage_flags(...)returns the choice map. Do the same for a colouredCOMMANDline and_parse_subcommand_list.monkeypatch.setenv("FORCE_COLOR", "1"), replacetool.subprocess.runwith a fake that records its keyword arguments, and call_run_help(["--help"]). Assert that the recordedenvhas noFORCE_COLOR, thatNO_COLOR == "1"and thatPYTHON_COLORS == "0".No GPU, network access or model download is needed. Add an entry under
## [Unreleased]inCHANGELOG.md, where earlier guard changes are listed. The change is tooling only, so there is no Turkish mirror to update.Open the PR against
developmentwithFixes #829(findingCR-A17a-053).