Repository navigation
Conversation
The implicit default route was synthesised only when the file declared no routes at all. So the moment a user created their first one, the route that every unbound key walks vanished, and loading the config failed with "`default_route` points at `默认`, but there is no such route" — that is, adding a route broke the gateway, and the message pointed at a field the user never touched. Synthesise it whenever nothing answers to `default_route` instead. A `default_route` the user wrote by hand is tracked separately, so a typo in it still fails loudly rather than being papered over by a synthesised route of that name. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Walking the desktop UI end to end against a running gateway, from a config that contains only clients and providers, five of its write paths failed. All five share a shape: the key being written is absent from the file, which is the normal state for most of the schema — the first day's config is six lines. * A top-level key went in wherever the last node ended, and a container node's byte range is an empty marker at the *start* of its content. With a block sequence last in the file, `default_route:` landed between two list items and the guard rejected the result as unparseable. `insert` and `append_first` had each hit this separately, so the block-and-indent logic now lives in one place. * Writing into a section that does not exist yet was refused. `limits` and `client_probes` are never written by default, so "change one item in it" *is* their first write; refusing made those settings dead in the UI. Missing intermediate maps are now created. Missing list *entries* are still refused — those have names, and inventing one is a guess. * A value slot that is empty (`key:` with nothing after it) has its marker on the colon, not after it, so writing through it produced `allow[]:`. * Overwriting a list with a scalar wrote a second key of the same name beside it. That is the three-state `allow` control's way back to "no restriction", and it failed with "this is a bug, please file an issue". * Removing the last entry of a list left `key:`, which is null, not an empty list. For `allow` those are "follow the client's dialect" and "allow nothing" — deleting the last pattern quietly turned the guard off. It also swallowed the blank line the user had put between two sections. Adds `clear_seq` and a `Clear` patch op: `allow: []` and an absent `allow` are different answers, so the protocol needs both. `Limits` was the one struct reachable from the config that accepted unknown fields, so a mistyped limit reported success and did nothing. 19 write paths now round-trip against a live gateway, and the resulting file differs from the original only in the lines the run meant to change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Sep 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Walking the desktop UI end to end against a running gateway — from a config that contains only
clientsandproviders— six of its write paths failed. Five were in the patch layer, one in the engine.They share a shape: the thing being written is not in the file yet. That is the normal state for most of the schema, so it is exactly what the first use of each feature hits.
Engine
The implicit default route was synthesised only when the file declared no routes. Creating the first custom route therefore deleted the route every unbound key walks, and loading the config failed pointing at a field the user never touched. It is now synthesised whenever nothing answers to
default_route; an explicitly written one is tracked separately so a typo in it still fails loudly.Patch layer
default_routelanded between two list itemsinsertandappend_firsthad each hit this separately — the block-and-indent logic now lives in one place.limits/client_probesrefusedallow[]:key:with nothing after) has its marker on the colon, not after it.allow:beside the firstkey:, which is null, not an empty list — forallowthose mean "follow the client's dialect" and "allow nothing". It also swallowed the blank line the user had put between two sections.Adds
clear_seqand aClearpatch op:allow: []and an absentalloware different answers, so the protocol needs both.Limitswas the one struct reachable from the config that accepted unknown fields, so a mistyped limit reported success and did nothing.Checks
1109 tests, 46 smoke checks, clippy clean, formatted.
19 write paths round-trip against a live gateway, and the resulting file differs from the original only in the lines the run meant to change — comments, blank lines and ordering all survive.
🤖 Generated with Claude Code