fix(routing): let a session grounded in nothing reach the context it needs - #87
Merged
tanglearncode merged 1 commit intoAug 9, 2026
Merged
Conversation
…needs Nothing connected is the case routing exists for, and it was the one case that could not route. Two independent faults, both found driving the real Copilot bridge against a real store: a question that plainly belonged to a saved incident context came back as an offer to run /neatcontext:use. A mode nobody chose was written down. Until now the resolved mode was persisted on every routing write - deriving a card, logging a decision, noting a refusal - so a file recorded whatever default the build that last touched it happened to ship. "ask" was that default until the shortlist learned to ask on its own, so every machine that had ever saved a context had "ask" written into plugin-routing.json, and #77's new default reached none of them. Reinstalling did not help either: that file lives in ~/.neatcontext and outlives any one install. Schema 2 fixes both halves. An unchosen mode now stays out of the file entirely, so a future change of default still reaches this machine, and an "ask" in a schema 1 file is read as what it was - a default, not a choice - and dropped. "manual" was never a default, so it always stands. A machine where "ask" genuinely was chosen loses it once; one `/neatcontext:mode ask --global` puts it back, recorded under a schema where a stored mode means somebody asked for it. The nothing-connected text argued against routing. It led with a slash command, which is the first and most imperative thing the model reads, and it answered "what now?" before the menu below it ever got a turn. It now leads with the route the session can take itself, and falls back to the commands only where they are genuinely the way forward: manual mode, or a store with nothing in it. Codex keeps its no-polling rule verbatim. The menu's rules split on whether anything is connected. Every guard there - "clearly belongs", "not on a follow-up", "stands on its own" - exists to make leaving a context cost something. A session grounded in nothing has nowhere to leave from, and the same sentences read as reasons to do nothing at all. Tests drive the migration through all five core copies, since one ~/.neatcontext serves every host a user has installed, and each host's own harness covers its manual-mode and empty-store fallbacks.
tanglearncode
added a commit
that referenced
this pull request
Aug 9, 2026
The pi README still listed ask as the default. It stopped being one in PR #77, and PR #87 made that change actually reach machines whose plugin-routing.json had the old default written into it. This was the last place in the repo still describing the old behavior. Auto now leads the list, with the note that it asks first on a near-tie — which is why ask no longer has to be the default for everyone.
Merged
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.
Nothing connected is the case routing exists for, and it was the one case that could not route. Reported from a real Copilot session: a question that plainly belonged to a saved incident context came back as an offer to run
/neatcontext:use. Two independent faults.A mode nobody chose was written down. The resolved mode was persisted on every routing write, so a file recorded whatever default the build that last touched it shipped.
"ask"was that default until the shortlist learned to ask on its own — so every machine that had ever saved a context had"ask"on disk, and #77's newautodefault reached none of them. Reinstalling did not help: the file lives in~/.neatcontextand outlives any install.Schema 2: an unchosen mode stays out of the file, so a future default still reaches the machine; an
"ask"in a schema 1 file is read as the default it was and dropped."manual"was never a default, so it stands. A deliberate"ask"is lost once —/neatcontext:mode ask --globalrestores it, recorded where a stored mode means someone asked for it.The nothing-connected text argued against routing. It led with a slash command, answering "what now?" before the menu below it got a turn. It now leads with the route the session can take itself, falling back to commands only in manual mode or an empty store. Codex keeps its no-polling rule from #33 verbatim. The menu's guards — "clearly belongs", "not on a follow-up" — now apply only when connected; they exist to make leaving cost something, and a session with nowhere to leave from read them as reasons to do nothing.
Evidence
Replayed against a copy of a real store still carrying
schema=1, mode=ask:statusrouting: askrouting: autoget_contextleadConnect one with /neatcontext:use…Connect the one this request belongs to with use_context…use_contextSwitched this session to "checkedinfraissue"schema 1,mode: askschema 2,modeabsentStores self-heal on update. Retrieval was never at fault — the shortlist ranked the right context first in all six probe questions, before and after.
Tests
tests/routing-unconnected.test.mjsruns the migration against all five core copies (one~/.neatcontextserves every installed host) and drives the Copilot bridge through the regression. Each host's own harness covers its manual-mode and empty-store fallbacks.494 tests pass;
check,validate:pluginand the three E2E scripts clean; coverage 276/276 changed lines.