Fix --configure-network comma splice after string-valued last members (#2073) - #2075
Conversation
…#2073) InsertAsLastMember found the previous member's end with a code-only backward scan, but a string value is entirely string-literal region (quotes included), so a section ending in a comma-less string member walked past the whole value and spliced the synthesized separator after the member's COLON -- invalid JSON, which the write-time parse gate then refused ("No changes were written"), leaving --configure-network unable to configure such files at all. New member-end-aware scan treats a string-literal hit as the value's closing quote (comment-quoted runs classify as comment; a real trailing comma is code and found first). Regression fixture is the reporter's exact minimal-config repro. Root cause as diagnosed by gotqn in the report -- verified against the classifier before fixing. Closes #2073 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| /* Member-end, not code-only (#2073): the previous member's value may be a string, whose every | ||
| character (quotes included) is StringLiteral region — the code-only walk would skip it and put | ||
| the synthesized comma after the member's COLON. */ | ||
| var lastCodeIdx = PreviousMemberEndIndex(json, regions, objectClose, objectOpen); |
There was a problem hiding this comment.
Nit: downstream of this call, lastCodeIdx/lastCode (a few lines below) are now stale names — the whole point of this fix is that the index can land on a StringLiteral closing quote, not just Code region. Worth renaming to something like lastMemberEndIdx/lastMemberEndChar so a future reader doesn't assume "Code" and reintroduce the #2073 assumption elsewhere. Not a functional issue — the != ',' check is correct regardless of region.
ReviewWhat it does: Fixes a real bug in the Fix: New Correctness
Test coverageGood regression test: parses through the actual write gate ( Minor/optional: the fix lives in shared logic used by all three sections (postgres/mcp/web) and by the top-level section-insert call site, so one test is enough to cover the code path — but a second case (e.g. mcp/web, or a value with a trailing block comment before the brace) would tighten confidence further. Not blocking. Lite/Darling parityNo parity concern — Style / docs / changelogXML doc comments on the new private helper are consistent with the rest of the file (which documents private helpers too, beyond the "public APIs only" guidance in CONTRIBUTING.md). CHANGELOG entry is well-written and consistent with existing entries' format, and the Left one inline nit (non-blocking): Overall: solid, minimal, well-reasoned fix with a real regression test tied to the actual bug mechanism. No security, correctness, or performance concerns. |
Closes #2073.
What
--configure-networkproduced invalid JSON ("dataDirectory":, "…") when the target section's last member is a string with no trailing comma — the write-time parse gate then refused to write, so the wizard simply could not configure LAN exposure for files of that shape (no on-disk corruption ever occurred).Root cause (as diagnosed in the report — verified against the classifier before fixing)
InsertAsLastMemberlocated the previous member's end viaPreviousCodeIndex, a code-only backward scan. A string value is entirelyStringLiteralregion — quotes included — so the scan skipped the whole value, landed on the member's colon, and spliced the synthesized comma there. Only a string-valued, comma-less last member trips it: objects/arrays/primitives end in Code characters, and a trailing comma is Code and found first — which is why the shipped sample's fixtures never exercised the shape.Fix
New
PreviousMemberEndIndex: same walk, but aStringLiteralhit terminates it too — that hit is always a real value's closing quote (quoted runs inside comments classify as Comment). The comma now lands after the value. The otherPreviousCodeIndexcall site (member removal) only ever looks for,/{, both always Code — checked, not affected.Tests
Regression fixture is the reporter's exact minimal-config repro: parses through
DarlingConfig.Parse(the wizard's write gate), asserts the comma rides after the value and the:,shape never appears, and confirms the block is live through the realResolveNetworkExposure.🤖 Generated with Claude Code