fix(cli): parse-failure guard must not refuse valid empty {} config - #65975
ruangraung wants to merge 1 commit into
Conversation
tonydwb
left a comment
There was a problem hiding this comment.
Looks good. No obvious issues found.
Reviewed by Hermes Agent
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Comment
Summary
Fix: deduplicates model-switch markers in gateway. Ensures only the latest marker is retained in history.
Clean fix. No security concerns.
Reviewed by Hermes Agent
|
Thanks for identifying the empty- Problems
Suggested changes
Automated hermes-sweeper review. |
…es non-mapping roots
read_raw_config() collapses both a parse exception AND a top-level list/scalar
root to {}, so save_config / set_config_value could wipe every non-default
section on the next write. The previous commit only caught exceptions, leaving
list/scalar roots to slip through.
- Extract _refuse_write_if_unparsable() as the single chokepoint (config.py),
used by save_config(), set_config_value(), and the auth provider writer so the
guard cannot be skipped via a different write path.
- Refuse when the existing file parses to a non-dict root (list/scalar), not only
on a parse error; a genuinely valid empty {} still passes through.
- Cover the auth.py provider writer (_update_config_for_provider) with the same guard.
- Drop the unrelated .local-hooks/ .gitignore rule added in 368c91f.
- Extend tests: list-root, scalar-root, valid-empty-{} pass, and auth-writer-refuses.
refs NousResearch#65975
368c91f to
998c28d
Compare
|
@teknium1 thanks for the thorough review, and fair call on the empty- Shared guard + the auth path. You're right that a two-site guard doesn't close the class, so I collapsed it into one chokepoint, Non-dict roots. Exactly the trap you flagged:
Tests. Extended CI green now on |
|
Following up on your coordination comment — thanks for the constructive approach, and you were right that the two PRs together close the whole family. The set/unset side merged via #96169 (salvage of #71385, authorship preserved). During review we widened the shared guard itself: That makes this PR's mechanism ( |
What does this PR do?
Fixes a regression in #14276's config-parse-failure guard. The original guard added by @Societus used
if _existing_size > 0 and not read_raw_config()to detect parse failures — butread_raw_config()returns{}for both a genuinely unparseable file and a valid empty{}config. The guard cannot tell them apart, so it incorrectly blocks legitimate writes to a fresh empty config.This PR replaces the emptiness check with a real inline YAML parse using
fast_safe_load(the same parserread_raw_config()uses). The new guard refuses to write only when the file is non-empty and parsing actually raises ayaml.YAMLError. A valid empty{}parses cleanly and passes straight through. Applied to bothsave_config()andset_config_value().Related Issue
Directly addresses the CI regression introduced in #14276. The original bug (class of config-write-unsafe errors) is tracked in #58781 (closed P1). An alternative comprehensive approach is tracked in #62232.
Type of Change
Changes Made
hermes_cli/config.py— Added inline-parse guard insave_config()at line 7403 (afterrequire_readable_config_before_write, beforeread_raw_config()) and inset_config_value()at line 8425 (sameposition). The guard calls
fast_safe_load()directly; if it raises, the file is genuinely unparseable and the write is refused with a warning. A valid{}document parses without error and is allowed through.tests/hermes_cli/test_save_config_wipe_guard.py— 8 tests covering valid empty{}, valid non-empty, unparseable garbage (unclosed bracket), and missing file, for bothsave_config()andset_config_value().How to Test
Checklist
Code
fix(cli): ...)save_configlost-update — three-way merge-preserve + loud CAS conflict refusal at theatomic_config_writeseam #62232pytest tests/ -qand all tests pass — targeted coverage on the blast radius (67 tests)Linux 6.12.95+deb13-amd64Documentation & Housekeeping
Screenshots / Logs
Guard tests — 8/8 pass:
Dashboard profile tests (regressed by #14276's guard) — 59/59 pass:
Guard blocking a genuinely unparseable config (the
save_configwarning):Guard blocking
set_config_valueon the same unparseable file:Pre-existing CI failure from #14276 run 29447346642 (for reference — these are the failures this PR fixes):
All three slices are green on main (run 29464923384), confirming the regression was introduced by the guard in #14276.