Skip to content

fix: scanruler-mcp connection and job items from #34 - #53

Open
Jozkah wants to merge 6 commits into
CNCKitchen:mainfrom
Jozkah:review/mcp-link-jobs
Open

Jozkah wants to merge 6 commits into
CNCKitchen:mainfrom
Jozkah:review/mcp-link-jobs

Conversation

@Jozkah

@Jozkah Jozkah commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

The scanruler-mcp connection and job items from #34, rebased on 0.9.3, one commit per item, each with a regression test that fails without it:

  • fix: turn down a closing page's calls when another page takes over
  • fix: keep the answer limit and wait timeouts within what a timer can wait
  • fix: let a batch of very many calls answer after it has run them
  • fix: stop a torn folders.json read from wiping the folder list
  • fix: keep the pairing token out of call traces
  • fix: answer within the limit when the connected page stops answering

Notes:

  • A page that never answers no longer holds a call past the answer limit. Read-only calls, scanruler_wait for idle and for a job, and the session readout all give up at the limit and leave nothing pending. Not done: forwarding the client's cancel signal through a relaying copy.
  • The trace redacts the pairing token. The token is still in the connection help sent to the model, since agents rely on it to connect.
  • The batch fix swaps a spread for a loop. The 200-call cap is still not enforced, as scripted batch files are meant to be long.
  • folders.json is written to a temp file and renamed, and a failed read no longer replaces the list with [].

Build: npm run build passes. npm test (3094), npm --prefix mcp test (133), the plugin boundary and units checks, and npm run e2e:ci all pass.

A page whose connection was still closing did not count as connected, so a
new page was let in over it. The old socket's close then arrived after the
link had moved on, and returned early before turning down what was still
waiting, so those calls never settled and their jobs stayed running.

The link now turns down everything still pending before it takes in the new
page.
…wait

An answer limit above about 24.8 days, or a scanruler_wait timeout of that
size with no limit set, overflowed Node's timer, which then fired after 1 ms:
every change answered queued at once and every wait returned straight away.
The tool arguments are not checked against their schema either, so a
timeoutSeconds that was not a number made the wait end at once as well.

The answer limit is now cut to the longest a timer can wait, and a
timeoutSeconds that is not a number above 0 falls back to the default, with
600 seconds the most it waits, as its schema says.
The batch found its answer cap by spreading every call into Math.max, which
throws once there are more than about 125,000 of them. A batch read from a
file can hold that many, since the 200-call limit in the schema is not
enforced, so it ran every call and then failed, losing all their results.

The cap is now found with a reduce, which takes any number of calls.
folders.json was written in place, so another copy could read it half
written. Saving the last project read the folders back that way, took the
failed read as no folders, and wrote an empty list over them; scanruler_write,
_files and _read then refused as if no scan had been opened.

The file is now written whole and renamed into place, as update.json is,
and saving the last project leaves a folders.json it cannot read as it is
rather than replacing its folders with an empty list.
The help on connecting gives the pairing token in full, and every reply
while no page is connected carries that help. With --trace-args the head of
each reply is written to the trace, so the token ended up in a file that is
meant to be shared.

The trace now writes the token as [redacted] wherever it appears in a
line, which covers both the reply heads and the arguments.
A frozen or throttled tab still answers the heartbeat, so its link stays up
while nothing it is asked comes back. Requests to the page had no timeout:
a read-only tool call, which does not run as a job, skipped the answer-limit
race altogether, and scanruler_wait for idle or for a job of an earlier copy
asked the page with no bound, so each could hang well past the answer limit
and past the timeout it was given. Every such request also stayed in the
link's pending list for good.

A request to the page can now carry a timeout, after which it is rejected
with code timeout and taken off the pending list. A read-only call is held
no longer than the answer limit, the page reads behind scanruler_wait end at
its deadline (a page that has not answered by then is not taken as idle),
and the session read that already raced a timer now uses the same timeout,
so its request no longer lingers either.

This branch has not been deployed

No deployments
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