Skip to content

fix(routing): let a session grounded in nothing reach the context it needs - #87

Merged
tanglearncode merged 1 commit into
mainfrom
fix/routing-reaches-a-session-grounded-in-nothing
Aug 9, 2026
Merged

tanglearncode merged 1 commit into
mainfrom
fix/routing-reaches-a-session-grounded-in-nothing

Conversation

@tanglearncode

@tanglearncode tanglearncode commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

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 new auto default reached none of them. Reinstalling did not help: the file lives in ~/.neatcontext and 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 --global restores 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:

before after
status routing: ask routing: auto
get_context lead Connect one with /neatcontext:use… Connect the one this request belongs to with use_context…
unprompted use_context refused Switched this session to "checkedinfraissue"
file after one write schema 1, mode: ask schema 2, mode absent

Stores 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.mjs runs the migration against all five core copies (one ~/.neatcontext serves 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:plugin and the three E2E scripts clean; coverage 276/276 changed lines.

…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
tanglearncode merged commit a29cd57 into main Aug 9, 2026
11 checks passed
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.
@tanglearncode tanglearncode mentioned this pull request Aug 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant