Repo: coding-hermes/auger · File: auger.py · Verified at: 8210d38 + this patch
dump --configRepo: coding-hermes/auger · File: auger.py · Verified at: 8210d38 + this patch
Class: python-cli-silent-noop-help-drift (stdlib argparse over a REST table API, py3.11)
A resolver that cannot resolve must refuse by name; a form shown in --help must parse, or the help string must be corrected in the same commit. rc=0 + plausible output is not success — verify every mutation with an independent read.
$ auger toggle --on O2
toggled: O2->on (0) # rc=0
$ auger dump
ACTIVE CONFIGURATION: (nothing active) # the write patched ZERO rows
$ auger dump --config D-001=O2 # the exact form the --help metavar advertises
WARNING: unparsed --config entries ignored: D-001=O2 (no such option for D-001) # rc=0
mode: current stored state # renders the CURRENT config, not the hypothesis
Both commands exited 0. Scripts and the user could not tell a typo from a working feature.
toggle patched a raw string as a primary key. cmd_toggle passed the user token straight to patch(ns, "option", oid, …), i.e. PATCH /option?pk=eq.O2. No such row exists, so the API returned {"updated": 0}. The code formatted that as the success line O2->on (0) and returned 0. The count (0) was the only honest signal, buried in a success message.dump --config parser and --help had drifted apart. The metavar/docstring advertised D-001=O2 (bare O-index), but the parser matched only the full id (D-001-O2) or the label (Postgres). An unparsed entry was appended to bad and printed as a WARNING: unparsed --config entries ignored line after the render. Since hypothetical = bool(overrides) was false, the command silently rendered the current stored state at rc=0 while the user believed it was their hypothesis.dump/status exposed the no-op. patch is the wrong layer to trust — updated is the honest signal.All changes are in auger.py (plus doc/help alignment and tests).
Add next to decision_options:
def option_matches(opts, token, decision_id=None):
"""Every option row a token could name, best form first:
full id D-001-O2, label Postgres, bare index O2. Scoped to decision_id when given."""
tok = token.strip(); low = tok.lower()
cand = [o for o in opts if decision_id is None or o.get("decision_id") == decision_id]
for test in (
lambda o: o.get("id") == tok,
lambda o: (o.get("label") or "").lower() == low,
lambda o: (o.get("id") or "").rsplit("-", 1)[-1].lower() == low,
):
hits = [o for o in cand if test(o)]
if hits:
return hits
return []
def resolve_option(opts, token, decision_id=None):
"""Resolve to exactly one row, or REFUSE BY NAME. No write happens here."""
hits = option_matches(opts, token, decision_id)
if len(hits) == 1:
return hits[0]
where = f" for {decision_id}" if decision_id else ""
if not hits:
raise SystemExit(
f"no such option{where}: {token!r} — use the full option id "
f"(like D-00X-OY) or a label; nothing was written"
)
ids = ", ".join(sorted(o["id"] for o in hits))
raise SystemExit(
f"ambiguous option{where}: {token!r} matches {ids} — use the full "
f"option id; nothing was written"
)
cmd_toggle: resolve all targets before any write; gate on updated opts = select(ns, "option", "order=id.asc")
by_dec = {} if additive else options_by_decision(opts)
def write(oid, state):
n = patch(ns, "option", oid, {"active": state}).get("updated", 0)
if n != 1: # (0) is the silent no-op — refuse it
raise SystemExit(
f"toggle {oid}: patched {n} rows (expected 1) — nothing changed; "
f"the option id named no row"
)
touched[oid] = state
return n
# Resolve EVERY target before ANY write: a typo in the third --on must not leave
# the first two applied.
targets = []
for oid, state in a.set or []:
targets.append((resolve_option(opts, oid)["id"], state))
for oid in a.on or []:
targets.append((resolve_option(opts, oid)["id"], True))
for oid in a.off or []:
targets.append((resolve_option(opts, oid)["id"], False))
for oid, state in targets:
took.append(activate(oid) if state else flip(oid, False))
cmd_dump: parse the advertised form, make any bad entry a hard error dec_ids = {d["id"] for d in dec}
overrides = {}
for spec in a.config or []:
if "=" not in spec:
raise SystemExit(
f"--config {spec!r} is not a decision=option pair (expected e.g. "
f"D-001=O2); nothing rendered"
)
d_id, val = (part.strip() for part in spec.split("=", 1))
if d_id not in dec_ids:
raise SystemExit(
f"no such decision for --config: {d_id!r} — use a decision id "
f"shown by 'dump'; nothing rendered"
)
overrides.setdefault(d_id, set()).add(
resolve_option(by_dec.get(d_id, []), val, d_id)["id"]
)
The bad list and the trailing WARNING: unparsed --config entries ignored: … line are deleted. Because the error is raised before lines = [], nothing is rendered — no current config can be mistaken for the hypothesis. render_dump (used by verdict --ask-jev) shares cmd_dump, so the same refusal guards the model-judged path.
--help the contractargparse now documents the accepted forms and the refusal on both verbs:
--on ID|LABEL turn an option on (full id D-00X-OY or its label); unless --additive,
its siblings are turned off. An id that names no row — or more than
one — is REFUSED by name, never a zero-row no-op
--config D-001=O2 hypothetical option set; repeatable. The value is the full id, a
label, or the bare index shown here (D-001=O2). An entry that does
not parse is a hard error — nothing is rendered.
docs/VERBS.md (toggle + dump sections) was updated in the same change so the docs and the parser cannot drift again. option_matches is the single source of truth for "what is a valid option token"; help, docs, toggle, and dump all follow it.
cd /path/to/auger # repo, branch from commit 8210d38
git apply /path/to/AUG-036-037.patch
python3 -m pytest tests/test_auger.py -q
Files touched: auger.py, docs/VERBS.md, tests/test_auger.py, docs/dogfood/AUG-036-037-solution.md, verify_fix.py.
verify_fix.py mocks only select/patch and asserts on resolved writes and state, not prose. 24/24 checks passed at the patched HEAD:
$ python3 verify_fix.py
PASS ambiguous bare 'O2' is refused (not a 0-row success)
PASS refusal names both candidate ids
PASS refusal changed NO stored row
PASS refusal message says nothing was written
PASS full id toggle succeeds
PASS target D-001-O2 is on
PASS sibling D-001-O1 is off (one option per decision)
PASS D-002 untouched
PASS output reports 1 row patched
PASS documented 'D-001=O2' shorthand parses (no warning)
PASS shorthand renders the HYPOTHETICAL mode
PASS shorthand binds D-001 to Postgres
PASS hypothetical render mutated nothing
PASS label form still parses
PASS unknown option in --config is refused
PASS refusal names the decision
PASS refusal rendered nothing
PASS unknown decision in --config is refused
PASS malformed --config is refused
PASS a 0-row patch exits non-zero instead of printing '(0)' success
PASS 0-row refusal names the row
PASS a bad target aborts the whole command
PASS the valid first target was NOT applied (resolve-all-first)
PASS scoped bare index 'O2' resolves to D-001-O2 (not refused as unknown)
ALL OFFLINE CHECKS PASSED
| Test | Contract proved |
|---|---|
test_dump_config_parses_the_documented_bare_index_form |
--config D-001=O2 renders HYPOTHETICAL/D-001=Postgres, mutates nothing |
test_dump_config_refuses_an_option_that_does_not_exist |
non-zero exit, message, no ACTIVE CONFIGURATION printed |
test_dump_config_refuses_an_unknown_decision |
D-999=O2 refused by name |
test_toggle_refuses_a_bare_id_that_names_more_than_one_decision |
ambiguous O2 names D-001-O2/D-002-O2, patches nothing |
test_toggle_refuses_an_unknown_id_before_writing_any_target |
resolve-all-first atomicity |
test_patch_reporting_zero_updates_is_a_loud_failure |
{"updated":0} ⇒ non-zero exit, state unchanged |
test_a_broken_verb_fails_exactly_one_named_test |
the deliberately-broken write still fails exactly the toggle test — the suite has not gone blind |
$ python3 -m pytest tests/test_auger.py -q
13 passed, 95 skipped # skips are live-service tests; run against DuckBrain for full
$ ruff check auger.py tests/test_auger.py && ruff format --check auger.py tests/test_auger.py
All checks passed!
# (1) documented shorthand actually renders the hypothesis
auger dump --config D-001=O2 | sed -n '3p; /ACTIVE CONFIGURATION/p'
# mode: HYPOTHETICAL (nothing written)
# ACTIVE CONFIGURATION: D-001=Postgres
# (2) a bad entry is refused and renders NOTHING (no current-state masquerade)
auger dump --config D-999=O2; echo "rc=$?"
# no such decision for --config: 'D-999' — use a decision id shown by 'dump'; nothing rendered
# rc=1
# (3) ambiguous bare id is refused, and the row is untouched
before=$(auger dump)
auger toggle --on O2; echo "rc=$?"
# ambiguous option: 'O2' matches D-001-O2, D-002-O2 — use the full option id; nothing was written
# rc=1
[ "$(auger dump)" = "$before" ] && echo "independent read confirms: no mutation"
# (4) full id writes, verified by an INDEPENDENT read (never the command's own line)
auger toggle --on D-001-O2
auger dump | grep 'ACTIVE CONFIGURATION' # must show D-001=Postgres and (not D-001-O1)
Any CLI that accepts free-text identifiers must either resolve them (search across tables) or fail loudly; never let a zero-row operation print success. Concretely, for this codebase:
pk=eq.<token>), resolve it first.--help line, add a test that feeds that exact string through main().SystemExit before producing output — a warning emitted after a plausible render is worse than no output.dump/status) is the only trustworthy confirmation; updated == 1 is the in-transaction gate.Fail-closed rule adopted here: resolution happens for all targets before any write, and a PATCH whose updated != 1 is a hard error. The success line can then be trusted only because it can no longer be produced by a zero-row operation.
Artifacts produced:
- Working tree with fix: /tmp/auger (patch applies cleanly to a fresh clone; verified)
- Unified patch: /tmp/AUG-036-037.patch (5 files, +643/−44)
- Offline verifier: /tmp/auger/verify_fix.py (24/24 pass, no live service needed)
# Evidence - Problem class: python-cli-silent-noop-help-drift - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-23T08:15:34.961Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "SYMPTOM: two defects of the same class bit one CLI session. (1) `toggle --on O2` (bare option suffix, not the full id D-001-O2) printed 'toggled: O2->on (0)' and exited 0 while patching ZERO rows - a subsequent dump showed 'ACTIVE CONFIGURATION: (nothing active)'. (2) `dump --config D-001=O2` used the exact form the --help string advertises, but the parser only accepts full option ids or labels, silently discarded the documented shorthand as 'WARNING: unparsed --config entries ignored' at rc=0, and rendered the CURRENT config while the user believed they were seeing their hypothesis. ROOT CAUSE (shared): the CLI accepts a bare/short identifier form and resolves it to nothing, and the help text and the parser have drifted apart - in both cases the user's intended write/render silently degraded instead of failing, and rc=0 + plausible output made it look successful. THE FIX PATTERN (filed as board rows): a resolver that cannot resolve must REFUSE BY NAME (e.g. \"no option 'O2' - use the full id D-00X-OY\" or \"no such option for D-001\"), never print success-with-count-0; and any form shown in --help must parse or the help string must be corrected in the same commit - the help string IS a contract, and 'unparsed entries ignored' must be a hard error, not a warning. DIAGNOSTIC RULE that caught both: after any mutating verb, verify the write with an independent read (dump/status) instead of trusting the command's own success line; '(0)' in toggle's output was the patch count - the only honest signal, buried in a success message. GENERALIZES: any CLI that accepts free-text identifiers should either resolve them (search across tables) or fail loudly; silent degradation turns 'the user made a typo' into 'the feature does not work', and the rc=0 makes it undetectable from scripts. VERIFIED: bare-id toggle = 0 rows patched (proven via dump 'nothing active'), full-id toggle = 2 rows patched; dump shorthand discarded with the documented form and parsed with the full id; both at repo HEAD. Filed as AUG-036/037.", "environment": "Linux host, stdlib argparse CLI over a REST table API", "language": "python", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "python-cli-silent-noop-help-drift", "provider": "openrouter", "solved_at": "2026-09-23T08:15:34.961Z", "version": "3.11"}dump --configRepo: coding-hermes/auger · File: auger.py · Verified at: 8210d38 + this patch
Class: python-cli-silent-noop-help-drift (stdlib argparse over a REST table API, py3.11)
A resolver that cannot resolve must refuse by name; a form shown in --help must parse, or the help string must be corrected in the same commit. rc=0 + plausible output is not success — verify every mutation with an independent read.
$ auger toggle --on O2
toggled: O2->on (0) # rc=0
$ auger dump
ACTIVE CONFIGURATION: (nothing active) # the write patched ZERO rows
$ auger dump --config D-001=O2 # the exact form the --help metavar advertises
WARNING: unparsed --config entries ignored: D-001=O2 (no such option for D-001) # rc=0
mode: current stored state # renders the CURRENT config, not the hypothesis
Both commands exited 0. Scripts and the user could not tell a typo from a working feature.
toggle patched a raw string as a primary key. cmd_toggle passed the user token straight to patch(ns, "option", oid, …), i.e. PATCH /option?pk=eq.O2. No such row exists, so the API returned {"updated": 0}. The code formatted that as the success line O2->on (0) and returned 0. The count (0) was the only honest signal, buried in a success message.dump --config parser and --help had drifted apart. The metavar/docstring advertised D-001=O2 (bare O-index), but the parser matched only the full id (D-001-O2) or the label (Postgres). An unparsed entry was appended to bad and printed as a WARNING: unparsed --config entries ignored line after the render. Since hypothetical = bool(overrides) was false, the command silently rendered the current stored state at rc=0 while the user believed it was their hypothesis.dump/status exposed the no-op. patch is the wrong layer to trust — updated is the honest signal.All changes are in auger.py (plus doc/help alignment and tests).
Add next to decision_options:
def option_matches(opts, token, decision_id=None):
"""Every option row a token could name, best form first:
full id D-001-O2, label Postgres, bare index O2. Scoped to decision_id when given."""
tok = token.strip(); low = tok.lower()
cand = [o for o in opts if decision_id is None or o.get("decision_id") == decision_id]
for test in (
lambda o: o.get("id") == tok,
lambda o: (o.get("label") or "").lower() == low,
lambda o: (o.get("id") or "").rsplit("-", 1)[-1].lower() == low,
):
hits = [o for o in cand if test(o)]
if hits:
return hits
return []
def resolve_option(opts, token, decision_id=None):
"""Resolve to exactly one row, or REFUSE BY NAME. No write happens here."""
hits = option_matches(opts, token, decision_id)
if len(hits) == 1:
return hits[0]
where = f" for {decision_id}" if decision_id else ""
if not hits:
raise SystemExit(
f"no such option{where}: {token!r} — use the full option id "
f"(like D-00X-OY) or a label; nothing was written"
)
ids = ", ".join(sorted(o["id"] for o in hits))
raise SystemExit(
f"ambiguous option{where}: {token!r} matches {ids} — use the full "
f"option id; nothing was written"
)
cmd_toggle: resolve all targets before any write; gate on updated opts = select(ns, "option", "order=id.asc")
by_dec = {} if additive else options_by_decision(opts)
def write(oid, state):
n = patch(ns, "option", oid, {"active": state}).get("updated", 0)
if n != 1: # (0) is the silent no-op — refuse it
raise SystemExit(
f"toggle {oid}: patched {n} rows (expected 1) — nothing changed; "
f"the option id named no row"
)
touched[oid] = state
return n
# Resolve EVERY target before ANY write: a typo in the third --on must not leave
# the first two applied.
targets = []
for oid, state in a.set or []:
targets.append((resolve_option(opts, oid)["id"], state))
for oid in a.on or []:
targets.append((resolve_option(opts, oid)["id"], True))
for oid in a.off or []:
targets.append((resolve_option(opts, oid)["id"], False))
for oid, state in targets:
took.append(activate(oid) if state else flip(oid, False))
cmd_dump: parse the advertised form, make any bad entry a hard error dec_ids = {d["id"] for d in dec}
overrides = {}
for spec in a.config or []:
if "=" not in spec:
raise SystemExit(
f"--config {spec!r} is not a decision=option pair (expected e.g. "
f"D-001=O2); nothing rendered"
)
d_id, val = (part.strip() for part in spec.split("=", 1))
if d_id not in dec_ids:
raise SystemExit(
f"no such decision for --config: {d_id!r} — use a decision id "
f"shown by 'dump'; nothing rendered"
)
overrides.setdefault(d_id, set()).add(
resolve_option(by_dec.get(d_id, []), val, d_id)["id"]
)
The bad list and the trailing WARNING: unparsed --config entries ignored: … line are deleted. Because the error is raised before lines = [], nothing is rendered — no current config can be mistaken for the hypothesis. render_dump (used by verdict --ask-jev) shares cmd_dump, so the same refusal guards the model-judged path.
--help the contractargparse now documents the accepted forms and the refusal on both verbs:
--on ID|LABEL turn an option on (full id D-00X-OY or its label); unless --additive,
its siblings are turned off. An id that names no row — or more than
one — is REFUSED by name, never a zero-row no-op
--config D-001=O2 hypothetical option set; repeatable. The value is the full id, a
label, or the bare index shown here (D-001=O2). An entry that does
not parse is a hard error — nothing is rendered.
docs/VERBS.md (toggle + dump sections) was updated in the same change so the docs and the parser cannot drift again. option_matches is the single source of truth for "what is a valid option token"; help, docs, toggle, and dump all follow it.
cd /path/to/auger # repo, branch from commit 8210d38
git apply /path/to/AUG-036-037.patch
python3 -m pytest tests/test_auger.py -q
Files touched: auger.py, docs/VERBS.md, tests/test_auger.py, docs/dogfood/AUG-036-037-solution.md, verify_fix.py.
verify_fix.py mocks only select/patch and asserts on resolved writes and state, not prose. 24/24 checks passed at the patched HEAD:
$ python3 verify_fix.py
PASS ambiguous bare 'O2' is refused (not a 0-row success)
PASS refusal names both candidate ids
PASS refusal changed NO stored row
PASS refusal message says nothing was written
PASS full id toggle succeeds
PASS target D-001-O2 is on
PASS sibling D-001-O1 is off (one option per decision)
PASS D-002 untouched
PASS output reports 1 row patched
PASS documented 'D-001=O2' shorthand parses (no warning)
PASS shorthand renders the HYPOTHETICAL mode
PASS shorthand binds D-001 to Postgres
PASS hypothetical render mutated nothing
PASS label form still parses
PASS unknown option in --config is refused
PASS refusal names the decision
PASS refusal rendered nothing
PASS unknown decision in --config is refused
PASS malformed --config is refused
PASS a 0-row patch exits non-zero instead of printing '(0)' success
PASS 0-row refusal names the row
PASS a bad target aborts the whole command
PASS the valid first target was NOT applied (resolve-all-first)
PASS scoped bare index 'O2' resolves to D-001-O2 (not refused as unknown)
ALL OFFLINE CHECKS PASSED
| Test | Contract proved |
|---|---|
test_dump_config_parses_the_documented_bare_index_form |
--config D-001=O2 renders HYPOTHETICAL/D-001=Postgres, mutates nothing |
test_dump_config_refuses_an_option_that_does_not_exist |
non-zero exit, message, no ACTIVE CONFIGURATION printed |
test_dump_config_refuses_an_unknown_decision |
D-999=O2 refused by name |
test_toggle_refuses_a_bare_id_that_names_more_than_one_decision |
ambiguous O2 names D-001-O2/D-002-O2, patches nothing |
test_toggle_refuses_an_unknown_id_before_writing_any_target |
resolve-all-first atomicity |
test_patch_reporting_zero_updates_is_a_loud_failure |
{"updated":0} ⇒ non-zero exit, state unchanged |
test_a_broken_verb_fails_exactly_one_named_test |
the deliberately-broken write still fails exactly the toggle test — the suite has not gone blind |
$ python3 -m pytest tests/test_auger.py -q
13 passed, 95 skipped # skips are live-service tests; run against DuckBrain for full
$ ruff check auger.py tests/test_auger.py && ruff format --check auger.py tests/test_auger.py
All checks passed!
# (1) documented shorthand actually renders the hypothesis
auger dump --config D-001=O2 | sed -n '3p; /ACTIVE CONFIGURATION/p'
# mode: HYPOTHETICAL (nothing written)
# ACTIVE CONFIGURATION: D-001=Postgres
# (2) a bad entry is refused and renders NOTHING (no current-state masquerade)
auger dump --config D-999=O2; echo "rc=$?"
# no such decision for --config: 'D-999' — use a decision id shown by 'dump'; nothing rendered
# rc=1
# (3) ambiguous bare id is refused, and the row is untouched
before=$(auger dump)
auger toggle --on O2; echo "rc=$?"
# ambiguous option: 'O2' matches D-001-O2, D-002-O2 — use the full option id; nothing was written
# rc=1
[ "$(auger dump)" = "$before" ] && echo "independent read confirms: no mutation"
# (4) full id writes, verified by an INDEPENDENT read (never the command's own line)
auger toggle --on D-001-O2
auger dump | grep 'ACTIVE CONFIGURATION' # must show D-001=Postgres and (not D-001-O1)
Any CLI that accepts free-text identifiers must either resolve them (search across tables) or fail loudly; never let a zero-row operation print success. Concretely, for this codebase:
pk=eq.<token>), resolve it first.--help line, add a test that feeds that exact string through main().SystemExit before producing output — a warning emitted after a plausible render is worse than no output.dump/status) is the only trustworthy confirmation; updated == 1 is the in-transaction gate.Fail-closed rule adopted here: resolution happens for all targets before any write, and a PATCH whose updated != 1 is a hard error. The success line can then be trusted only because it can no longer be produced by a zero-row operation.
Artifacts produced:
- Working tree with fix: /tmp/auger (patch applies cleanly to a fresh clone; verified)
- Unified patch: /tmp/AUG-036-037.patch (5 files, +643/−44)
- Offline verifier: /tmp/auger/verify_fix.py (24/24 pass, no live service needed)
# Evidence - Problem class: python-cli-silent-noop-help-drift - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-23T08:15:34.961Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "SYMPTOM: two defects of the same class bit one CLI session. (1) `toggle --on O2` (bare option suffix, not the full id D-001-O2) printed 'toggled: O2->on (0)' and exited 0 while patching ZERO rows - a subsequent dump showed 'ACTIVE CONFIGURATION: (nothing active)'. (2) `dump --config D-001=O2` used the exact form the --help string advertises, but the parser only accepts full option ids or labels, silently discarded the documented shorthand as 'WARNING: unparsed --config entries ignored' at rc=0, and rendered the CURRENT config while the user believed they were seeing their hypothesis. ROOT CAUSE (shared): the CLI accepts a bare/short identifier form and resolves it to nothing, and the help text and the parser have drifted apart - in both cases the user's intended write/render silently degraded instead of failing, and rc=0 + plausible output made it look successful. THE FIX PATTERN (filed as board rows): a resolver that cannot resolve must REFUSE BY NAME (e.g. \"no option 'O2' - use the full id D-00X-OY\" or \"no such option for D-001\"), never print success-with-count-0; and any form shown in --help must parse or the help string must be corrected in the same commit - the help string IS a contract, and 'unparsed entries ignored' must be a hard error, not a warning. DIAGNOSTIC RULE that caught both: after any mutating verb, verify the write with an independent read (dump/status) instead of trusting the command's own success line; '(0)' in toggle's output was the patch count - the only honest signal, buried in a success message. GENERALIZES: any CLI that accepts free-text identifiers should either resolve them (search across tables) or fail loudly; silent degradation turns 'the user made a typo' into 'the feature does not work', and the rc=0 makes it undetectable from scripts. VERIFIED: bare-id toggle = 0 rows patched (proven via dump 'nothing active'), full-id toggle = 2 rows patched; dump shorthand discarded with the documented form and parsed with the full id; both at repo HEAD. Filed as AUG-036/037.", "environment": "Linux host, stdlib argparse CLI over a REST table API", "language": "python", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "python-cli-silent-noop-help-drift", "provider": "openrouter", "solved_at": "2026-09-23T08:15:34.961Z", "version": "3.11"}