Commit Graph
7388 Commits
Author SHA1 Message Date
672e214963 fix(process)!: retain observed cleanup intervention (#10481)
* fix(process)!: retain observed cleanup intervention

Process capture derived `settlement.cleanup_outcome` from the settlement
state alone in three places, so a quiesced capture reported
`not_required` even after final owned-process cleanup SIGKILLed a live
token-owned descendant. `cleanupOwnedProcessGroup` already knew it had
signaled, but the capture lifecycle discarded that fact.

Carry the observed signal out of ownership cleanup (also on failure
paths), accumulate it across cleanup retries as true/false/unknown, and
derive settlement and the intervention residual unknown once in
`processCaptureCleanupFacts` for full, partial and harness results.

BREAKING CHANGE: a quiesced settlement may now report
`cleanup_outcome: "cleaned"`. Saved captures stay valid; readers that
accepted only `not_required` for quiesced settlements must accept
`cleaned`.

Fixes #8032

Squashed from #8043 and rebased onto main (adapted to the resource-scope
release API and the inspection-failure cleanup path).

Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(process): keep a sent signal when cleanup throws an inspection failure

Final ownership verification can rethrow a typed inspection failure (for
example cancellation) after SIGKILL succeeded. The capture owner then
recorded the attempt as unknown and dropped the intervention fact.

cleanupOwnedProcessGroup now marks a failure it throws after signaling,
without changing the failure's identity, and the capture owner keeps
the signal for such failures.

Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: wunianze666-netizen <wunianze666@gmail.com>
Co-authored-by: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 08:48:13 +01:00
1569186aa6 test: clear file-owned MCP schema validation after each file
The testing guide requires file-owned createMcpSchemaValidation instances
to be cleared in afterAll, so shared workers do not retain schema strings
and compiled validators after a file finishes.

Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 15:01:36 +08:00
6452c86cdc test: use shared lazy validation for stdio MCP clients
Stdio clients that list tools and then call one used the SDK's default
eager validator. Give each such file one shared lazy validation.

Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 15:01:36 +08:00
06e6401750 test: compile MCP output validators on first use
After tools/list, the MCP SDK client builds an output validator for every
listed tool before its first tools/call. Against REA's 255-tool catalog
that compiled for about 15 seconds of CPU (5 seconds for
inspect_analysis_view alone), whichever tool a test called. The shared
test validation now snapshots each schema when asked and compiles it when
it first validates.

Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 15:01:36 +08:00
morluto b3657c557f perf(tests): run plain CLI commands on the file's shared process (#10412)
* refactor(cli): run one-shot commands through one shared owner

scripts/rea.mjs and the test CLI session worker each implemented the
one-shot command sequence: argument normalization, output admission,
configuration errors, version documents, the Amp scope refusal, and
result delivery. The worker copy had drifted: it never rendered
formatted version reports or the Amp refusal.

Move the sequence into src/cliOneShot.ts. Both callers supply a host
for their streams, exit and resource ownership. The launcher keeps
closed-pipe status, worker shutdown and process exit; the session
worker captures output per command.

The cliOutput bundle entry is superseded and removed. The dispatcher
test now replaces only the command runtime, so output admission runs
production code. A new parity test compares the file session with a
fresh process.

* test(cli): bundle the one-shot entry in the runtime bundle fixture

* perf(tests): run plain CLI commands on the file's shared process

`cli.run` in `cliTest` files started a fresh compiled CLI for every
command, about 0.45s and 260 MB each before any work. The file-scoped
session already existed, but callers had to opt in through
`runFileCli` or `sharedCliRun`, so 1,300 call sites still spawned.

Make the fixture choose: `cli.run` uses the shared process when it
reports the command exactly as a fresh process would, and starts one
otherwise (stdin, explicit deadlines, MCP and MCP doctor routing,
NODE_OPTIONS, or enabled logging). `freshProcess: true` keeps
explicit process-level checks. The session worker now presents the
launcher's entrypoint, so registration identity matches a fresh
process.

`runFileCli` and `sharedCliRun` are superseded and removed; their
call sites use `cli.run`, and paired fresh/shared checks use
`freshProcess`.

* style(tests): format the managed member summary call site

* test(cli): give each shared-session command an empty stdin

The shared CLI process reads session frames from its own stdin. A
command that reads stdin without supplied input, such as
`compare-wasm-interfaces - --json`, read that pipe and hung, where a
fresh process receives EOF. The worker now presents an ended, empty
stdin to each command and restores its own afterwards.

The parity test compared the routed path with itself after cli.run
began choosing the session. It now compares a fresh process with the
session directly, including the `mcp add` refusal and a command
reading absent stdin.

* test(cli): keep default command logging and launcher checks on fresh processes

environment-serve and environment-build log at info when REA_LOG_LEVEL is
unset, through a logger that writes to stderr directly. The shared CLI
process captures only process.stderr writes, so routed runs lost those
lines. Declare the default-logging commands beside the command names,
have infoLogger read that set, and start a fresh process for them.

The log-level precedence checks compared the shared process with itself
after routing; their fresh side now passes freshProcess: true.
2026-11-14 14:28:08 +08:00
6938696256 test: keep child deadlines that rule out fallback exits
These fixtures' descendants exit on their own after 20 or 30 seconds. The
shorter explicit deadline is what proves cleanup stopped them first.

Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 13:21:13 +08:00
ee1450b5d4 test: bound every test process registry by the running test
Registries created directly with createTestProcessRegistry did not get the
processTest default, so a hung child there had no deadline once its explicit
value was removed; Vitest's test timeout does not settle the awaited run, so
shutdown was never reached. Derive the default in the registry from the
running test instead, using the real clock.

Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 13:21:13 +08:00
84990f9777 test: remove fixed child-process deadlines from tests
239 literal timeoutMs values on cli.run and processes.run only restated
a guess at host speed. On hosted runners with four workers, cliOutput's
3-second value failed while the command still produced correct output.
Deadlines that are the behavior under test, derived from an operation
budget, or that bound a regression's wait remain.

Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 13:21:13 +08:00
077bebe49b test: bound fixture child processes by the remaining test deadline
A processTest child run without its own timeoutMs now gets the test's
remaining deadline less a reporting reserve (at least 5 seconds, or a
tenth of the deadline). A hung child still fails with its captured output,
without a fixed per-call value that assumes a host's speed.

Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 13:21:13 +08:00
gensokyo-devandClaude Opus 5.5 5b158b2d1d fix(setup): stop treating Antigravity's .gemini storage as Gemini CLI
Antigravity keeps its MCP configuration and skills under
~/.gemini/config, and Gemini CLI was detected by the bare ~/.gemini
directory. Setting up Antigravity therefore made broad setup select
Gemini CLI and write a registration nobody asked for.

Gemini CLI's applicability now follows its own evidence: settings.json,
its trusted-folder records (honoring GEMINI_CLI_TRUSTED_FOLDERS_PATH) and
its .gemini/tmp session state, through the existing discoveryPaths
owner that detection, status and uninstall share. Selecting
--client gemini_cli explicitly is unchanged.

Fixes #7567

Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 05:36:32 +01:00
gensokyo-devandClaude Opus 5.5 899f77d840 fix(setup): say when an authentic Hopper package mismatches its feed hash
Linux Hopper setup verifies the package signature, then compares the
launcher it contains with the release feed's main_exe_hash. When only
that comparison failed, as with the Fedora 6.6.1 RPM, setup reported the
generic integrity failure and advised retrying or updating REA, which
cannot change a stale vendor feed.

The publisher now reports that case as launcher_digest_mismatch. Setup
keeps the public integrity_mismatch code and the refusal, and its
recovery says the download is authentic, the feed describes another
launcher build, and the mismatch needs a corrected feed. The two digests
stay in the detail. Every other integrity failure keeps its recovery.

Fixes #8138

Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 05:36:32 +01:00
gensokyo-devandClaude Opus 5.5 aa848cf1d2 fix(android): name the JADX JAR download and checksum in recovery
Doctor and configuration failures for a missing or rejected
REA_JADX_MCP_JAR asked for a "caller-supplied" jadx-headless-mcp 0.7.1
JAR without saying where it comes from. The upstream project has since
renamed its packages, so users concluded the JAR could not be obtained.

The shared JADX JAR remediation now names the audited release URL and
SHA-256 that REA already pins. The two capability-availability texts
point to rea doctor --provider jadx for them instead of repeating the
release data outside its owner.

Fixes #7768

Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 05:36:32 +01:00
gensokyo-devandClaude Opus 5.5 82f3bfb6e8 fix(doctor): refuse an empty --target like other target inputs
`rea doctor --target ""` passed an empty string to target readiness,
which checked the working directory instead of reporting that no app
was named. Use the shared local path schema, so an empty target fails
validation before any readiness check, as every other target does.

Fixes #7561

Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 05:36:32 +01:00
gensokyo-devandClaude Opus 5.5 5557d9b3eb fix(doctor): count installations by resolved launcher directory
On Windows `where rea` lists the npm shims rea, rea.cmd and rea.ps1 that
one global install writes side by side, and doctor counted each listed
path as an installation, so a single install reported "multiple".

The system host now pairs each PATH launcher with the installation it
resolves to: its directory after symlink resolution, compared
case-insensitively on Windows. Doctor counts distinct installations and
still lists every launcher path. Two POSIX launchers that resolve to one
package also count once; an unresolvable launcher keeps its own path.

Fixes #8122

Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 05:36:32 +01:00
3a13b088e6 fix(mcp): explain skipped doctor identity probes
Report identity as unobserved when the selected tool families omit
binary_session, preserving the current health decision and exit status.
Cover scoped production sessions and retain validation of successful
and schema-invalid probe responses.

Fixes #7438

[gensokyo-dev: rebased onto main; report "identity not observed" for every
request-flow reply that was not received (skipped scope, transport failure or
rejected output schema), not only skipped scopes; corrected the replayed
inventory-mode expectation, whose identity is observed and matches.]

Fixes #7438

Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 05:36:32 +01:00
gensokyo-devandClaude Opus 5.5 d412569293 fix(mcp-doctor): close only through the owned transport
The owned transport is the doctor's only cleanup owner, and Client.close
only delegates to it. Close it once and report its typed failure instead
of aggregating a duplicate SDK close and clearing that failure after a
retry. Pass the filtered caller environment as the launcher's base only,
and name the doctor operation in transport cleanup errors.

Cover a descendant in its own session, which only the token sweep can
reach, and a late cleanup denial that keeps the startup diagnostic and
reports the retained run. Bound the fixture descendant's lifetime so a
failing run cannot leak it. Document the doctor's process-family
ownership and output bound.

Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 05:36:23 +01:00
2SinceJuly 1b019a73d8 fix(mcp-doctor): keep the diagnostic child target-free and its stderr visible
The owned launcher merges its host base back under the explicit overrides, so
filtering only the override object let an ambient HOPPER_TARGET_* variable
through and the diagnostic child could open the target the doctor promises to
skip. Pass the filtered environment as the host base too, and opt into the
token sweep so a detached descendant that outlives the launcher is still
reached by cleanup.

Also keep the stderr observer attached until bounded cleanup and draining have
settled, report the typed cleanup resources instead of a generic close_binary
message, and drop a first-attempt cleanup failure once the owned retry proves
release.
2026-11-14 05:36:23 +01:00
2SinceJuly d427fc05c3 fix(mcp-doctor): stop the owned process family on every exit path
runProductionMcpDoctor wrapped the SDK StdioClientTransport and only joined its
close calls. That transport clears its direct-child reference, ends stdin and
signals only that child, so a server whose launcher exited after forking an
inherited-stdio descendant left the descendant running while the doctor
reported nothing but the transport deadline.

Run the doctor on OwnedMcpStdioTransport, which spawns the child in a dedicated
POSIX process group or Windows job and verifies group and token-owned
descendant cleanup before close returns. Feed stderr through a sink on
acquisition so diagnostics survive an early child exit and still honor the
64 KiB retained prefix and full byte count.

Covered by a fixture that forks a descendant, exits, and is timed out: the
regression asserts the descendant is gone after the doctor returns.
2026-11-14 05:36:23 +01:00
gensokyo-devandClaude Opus 5.5 3f7d0d2d21 test(process): drive kernel thread exclusion through Linux procfs
Replace the simulated-host sweep test with one that parses PF_KTHREAD
from a controlled /proc/<pid>/stat record through the system ownership
host, with root-matching credentials and an ESRCH environ read. The
user-process control with identical facts stays fail-closed. Name the
task flag constants and correct the comments: the reported kernel
threads were live, not exiting.

Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 05:36:23 +01:00
2SinceJuly 5bb6591d58 fix(process): exonerate kernel threads from ownership token checks
An unrelated kernel thread that appeared during a provider run has no
readable /proc/<pid>/environ, so the ownership sweep recorded it as a live
candidate with an unreadable token and failed cleanup with
cleanup_incomplete. Kernel threads exit quickly, so the read usually
reports ESRCH and is not attributable to environment withholding, which
meant a cleanly finished provider run discarded its result.

Kernel threads are forked by the kernel, never by a provider, so they can
never carry that run's token. Read PF_KTHREAD from the same /proc/<pid>/stat
identity observation and treat a kernel thread with no readable token as
unverified evidence, like an unrelated process whose environment the OS
withholds. The candidate still has to be otherwise unrelated and holds no
signal authority.
2026-11-14 05:36:23 +01:00
gensokyo-devandClaude Opus 5.5 7db1b61790 fix(ghidra): qualify inferred no-return cuts by the excluded fall-through
A terminal call on one branch does not end the whole function: other
branches can still reach the following code, which stays in the body and
pseudocode. The function-level limitation now says Ghidra excluded that
call's fall-through and that code reachable only through it is missing
if the callee returns. It is listed before the call-specific facts so a
bounded composed summary that admits limitations in order keeps it.

The body-coverage tests now check the counted records and their reasons
instead of freezing the explanatory sentence.

Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 05:34:39 +01:00
gensokyo-devandClaude Opus 5.5 ad2111fac6 fix(ghidra): say when an inferred no-return call cuts a function
Ghidra's Non-Returning Functions - Discovered analyzer can mark a
returning callee, such as an imported operator new thunk, as
non-returning. Ghidra then clears the fallthrough at each call site and
refits the callers, so a constructor decompiles to a few plausible
lines. REA reported the terminal call with the FunctionManager flag but
did not say the result omits the code after it or how to compare.

That analyzer bookmarks each entry it marks with the Analysis comment
"Non-Returning Function Found" (Ghidra 11.0 through 12.1.4 source); the
name-list Known analyzer writes "Non-Returning Function Identified".
When a terminal call's callee, or the function a thunk forwards to,
carries the Discovered bookmark, the call's limitation now says the
flag was inferred, and the function adds one address-free limitation
that its body and pseudocode end at that call and omit the following
code if the callee returns, with the REA_GHIDRA_DISABLED_ANALYZERS
comparison. A flag without the bookmark keeps an unknown origin.

The function-boundary observation contract moves to v5 so snapshots
from earlier bridges are not replayed without the qualification.

Refs #10365

Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 05:34:39 +01:00
gensokyo-devandClaude Opus 5.5 9d082b144a fix(decompile): derive the body-coverage caveat from retained records
decompile_all set its top-level "procedure_info is unavailable" caveat
from a per-call flag that only a newly attempted function could raise.
A resume that skipped every verified file, or selected nothing, rewrote
the manifest and decompile-index.json with an empty limitations list
while every retained record still reported an unavailable body.

The export owner now answers from the records it retains: the summary
counts every non-external record whose body is unavailable, including
records an earlier run wrote, and repeats the reason when all share one.
The per-call flag is removed. A fresh export whose procedure_info works
but leaves some bodies unavailable now reports that caveat too; a later
attempt that records a known body clears it.

Fixes #8351

Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 05:34:39 +01:00
gensokyo-devandClaude Opus 5.5 e8c838e8bd test(mcp): keep the surrogate path handler check within its deadline
The handler regression added in #10390 listed tools under the full input
profile and matched every advertised schema before calling each tool. It
took about 14 s locally and passed the 30 s deadline on loaded CI runners.
advertisedPatternsVMode.test.ts already proves that no input or output
profile advertises the surrogate escape, so this case now checks only the
runtime refusal through the default-profile handlers, as the
relative-path case does.

Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 05:06:09 +01:00
gensokyo-devandClaude Opus 5.5 809f0d69db fix(mcp): report HTTP listener recovery from its parsed failure
rea mcp --http printed "Choose another --port or stop the process using
it" for every listener failure except a missing host allowlist, so a host
lookup failure, an unassigned address or a permission denial got port
advice. StreamableHttpListenError already classifies the native failure
and owns a recovery for each kind.

Startup now always prints that owned recovery behind one shared lead-in,
and the fixed message is removed. The native cause text stays out of
stderr as before.

Fixes #7346

Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 04:57:03 +01:00
e1d229cd6b test(process): plan scenario admission cases for a host that reaches it
Planning for win32 refuses PTY capture before root admission runs, so the
cancellation cases now plan for Linux on any host. The ENOTDIR admission
case skips on Windows, which reports ENOENT for a path below a file and
admits it as a root the scenario may create.

Squashed from #9306 onto current main.

Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 04:50:06 +01:00
01fcf8e3d7 test(ghidra): give simulated Linux installs a POSIX path on Windows
The Ghidra profile fixture simulates a Linux host, so posix.isAbsolute
refused the C:\ install directory a Windows test run supplied. The
fixture now owns a POSIX-shaped install directory with shared ownership
and cleanup, used by the DOL, MIPS, PowerPC, RISC-V and language
override suites.

Squashed from #9284 onto current main.

Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 04:50:06 +01:00
RRFZ 0a3368a6a9 test(filesystem): admit the snapshot fixture as written on Windows
The snapshot identity test writes its file and admits it at once with the
default ChangeTime mode. On Windows that ChangeTime is inside the 2 s drift
window, so admission keeps re-reading the descriptor until it settles. The
returned baseline is then a later observation, not the one the test
captured, and the descriptor stat runs more than once.

Admit the fixture as written. That is the documented mode for a file that
was just written, and it reads the descriptor once on every host. Settling
keeps its own coverage in ChangeTimeBaseline.test.ts.
2026-11-14 04:50:06 +01:00
RRFZ 3986bf9f8e test(artifacts): fit the buffered member case to Windows stream buffers
The shared reader lifecycle case waits for a member's writable side to
finish before it reads anything. That only happens while the member fits
below the readable high-water mark. Node's default is 16 KiB on Windows and
64 KiB elsewhere, and the ESP flash fixture's first member is a 32 KiB
bootloader region, so both cases hung until the 30 s timeout on Windows.

Pick the first nonempty member that fits the default buffer and assert
that it fits the opened stream before waiting.
2026-11-14 04:50:06 +01:00
morluto bddbd80afb refactor(cli): run one-shot commands through one shared owner (#10405)
* refactor(cli): run one-shot commands through one shared owner

scripts/rea.mjs and the test CLI session worker each implemented the
one-shot command sequence: argument normalization, output admission,
configuration errors, version documents, the Amp scope refusal, and
result delivery. The worker copy had drifted: it never rendered
formatted version reports or the Amp refusal.

Move the sequence into src/cliOneShot.ts. Both callers supply a host
for their streams, exit and resource ownership. The launcher keeps
closed-pipe status, worker shutdown and process exit; the session
worker captures output per command.

The cliOutput bundle entry is superseded and removed. The dispatcher
test now replaces only the command runtime, so output admission runs
production code. A new parity test compares the file session with a
fresh process.

* test(cli): bundle the one-shot entry in the runtime bundle fixture
2026-11-14 11:48:19 +08:00
morluto f1e250ee76 test(dmg): stop hard-coding host speed in attachment recovery (#10431)
The test bounded each hdiutil and CLI step with its own 10-30 s process
deadline. On hosted macOS runners the test takes 32-45 s (about three
times a local run), and the busy-image CLI call, which verifies the whole
image before its attach is refused, exceeded 30 s and was killed in two
recent main runs. Remove those per-step deadlines; the project deadline
still bounds a hang.
2026-11-14 11:47:59 +08:00
morluto 71712f27f7 test(mcp): open stdio clients through the shared local-tools fixture (#10411)
* test(mcp): open stdio clients through the shared local-tools fixture

Twelve files built their own StdioClientTransport and Client for
`rea mcp`. Those clients never listed tools, so the SDK did not
validate structured results against advertised output schemas, and each
file repeated transport setup, stderr draining and close ordering.

Use connectLocalToolsMcp, which lists tools, validates replies,
silences logging, leaves deep providers unconfigured and owns cleanup.
Per-test clients register test-scoped cleanup; module-level clients
collect cleanup for afterAll.

* test(mcp): keep failed file-scoped MCP cleanup owned

The three module-level clients removed every cleanup callback before
running them, so a failed cleanup lost its only handle. Add
fileLocalToolsMcp, which connects before the file's tests and removes
each cleanup only after it succeeds, and use it in those files.
2026-11-14 11:47:55 +08:00
morluto fcc0a8c454 perf(mcp): build advertised tool schemas once per contract (#10421)
* perf(mcp): build advertised tool schemas once per contract

The MCP SDK reprojects every registered tool schema on each tools/list.
REA memoized that projection, but per wrapper, and each server built new
wrappers for every contract, so each new server reconverted the whole
catalog: about 280 ms per tools/list for 255 tools with the full input
profile. Each wrapper also registered a new schema in zod's global
registry, so heap grew with every server.

Contracts are immutable module values, so build each advertised input
and output wrapper once per contract. tools/list on later servers drops
to about 26 ms (full profile) or 48 ms (compact).

* test(mcp): load only the contract family under test
2026-11-14 11:47:51 +08:00
morluto 243e4015cb docs(ci): remove dated shard measurements from the testing guides (#10414)
* docs(ci): move dated shard measurements into a verification record

The testing guide and testing-lanes guide mixed the October 2026 shard
budget and stale-history measurements into current rules. Move them to
docs/verification/ci-shard-scheduling-2026-10-20.md and link it from
the rules they justify.

* docs(ci): drop dated shard measurements instead of keeping a record
2026-11-14 11:47:46 +08:00
RRFZ 4a4e959513 fix(javascript): retain global escapes across repeated calls 2026-11-14 04:46:27 +01:00
RRFZ 4e1e9b62a7 fix(javascript): preserve global escapes across callback boundaries 2026-11-14 04:46:27 +01:00
RRFZ 54677ec1d6 fix(javascript): preserve timer delays after global escapes 2026-11-14 04:46:27 +01:00
RRFZ 1abd327913 fix(javascript): retain timer delays after opaque global effects 2026-11-14 04:46:27 +01:00
RRFZ 186b2c352c fix(javascript): omit Node timers with rejected delay values 2026-11-14 04:46:27 +01:00
RRFZ 827b31c128 fix(javascript): honor child-process callback overloads 2026-11-14 04:46:27 +01:00
gensokyo-devandClaude Opus 5.5 ee339e5db5 fix(debuggers): keep stopped Rizin and GDB sessions explainable
After REA stopped a Rizin debug session (frame or output limit, deadline,
cancellation, protocol failure) or the debugger exited, later commands
returned a generic invalid_request and status gave no reason. GDB
collapsed the same states the same way.

Both managers now keep a published session addressable until
close_*_session releases it, record the first reason it stopped, report
it as closed_reason in session status, and refuse later commands with
capability_unavailable naming that reason and the close-then-restart
recovery. An ID the server never returned, or that close released, still
fails as invalid_request with its own recovery. Retained stopped
sessions keep their slot, which the capacity recovery now says. A GDB
command deadline now records its reason like cancellation already did.

Fixes #8024

Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 04:42:35 +01:00
gensokyo-devandClaude Opus 5.5 6ce708cfde fix(rizin): report shell refusals instead of complete empty results
Rizin exits 0 when its shell refuses a statement, so execute_rizin_command
reported completion_status complete with exit code 0 and an empty stdout
that read as a genuine empty result.

Rizin 0.6 through 0.9.1 log exactly four refusal lines from
librz/core/cmd/cmd.c: an unknown command, a wrong argument count, an
invalid statement (RZ_CMD_STATUS_INVALID, which also stops the remaining
statements) and a parse error. The Rizin command profile now classifies a
completed process's stderr against those lines; the shared one-shot
service reports completion_status "rejected" and a limitation that names
the refusal and says stdout holds only earlier statements' output. Other
ERROR lines come from commands that ran and stay diagnostics.

Fixes #10364

Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 04:42:35 +01:00
gensokyo-devandClaude Opus 5.5 884b683a94 fix(cli): advertise the decimal token grammar on integer arguments
`cliIntegerArgument` piped a regex-guarded string into a number but never
published Zod's input view, so `--schema` advertised a bare integer for 15
fields while the parser accepted only decimal argv text. `environment-serve
--port` had the same gap through the transforming MCP_PORT owner.

Remove `cliIntegerArgument` and route every call site through
`cliDecimalField`, binding each field to its domain or contract owner where
one exists so bounds, defaults and optionality come from that owner. Export
the input-view publisher as `publishArgvInput` and apply it to `--port`,
which keeps the MCP_PORT grammar shared with `rea mcp --http`.

The decimal catalog test now requires every numeric field's advertisement
to admit its decimal argv token, covers repeated options and
string-advertised token grammars, and checks `--schema` output directly.

The string branch's missing numeric range (#9348) is unchanged.

Fixes #9344

Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 04:27:54 +01:00
5815178a8d ci: give the Apple artifact lane a passing-run budget
Passing runs of the macOS artifact lane took 10.2-14.9 minutes (median
13.6) across recent runs, and 4 of 12 runs that reached their steps were
cancelled at the 15-minute limit without a failing test. Allow 25
minutes so runner speed alone does not fail the lane.

Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 05:54:30 +08:00
87743d67f5 test: check the deadlines Vitest applies to collected tests
Probes in a source and a built project read each collected test's
deadline, including test, suite, and module long-running tags, so a
change in project inheritance or tag resolution fails directly. Both
the policy and the probes read one set of base deadlines.

Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 05:27:07 +08:00
d3efeb0c36 test: assert elapsed time where a deadline guarded complexity
Four wide-input regressions used a short per-test deadline as their only
check against a slow but terminating implementation. Assert the same
budgets explicitly so the project deadline only detects hangs. The
composed-body test keeps its exact read count instead.

Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 05:27:07 +08:00
46728ca41d test: remove per-test deadlines owned by project policy
Explicit deadlines at or below the project deadline only shortened it:
a literal 30-second value also disabled the coverage scaling, which timed
out wide-capacity regressions on main. Workloads above the built
deadline use the long-running tag. Deadlines derived from an operation
budget remain.

Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 05:27:07 +08:00
62798fa8b0 test: share the wide fingerprint analysis across projection modes
Both projection modes read the same 130,000-callable analysis without
changing it, so analyze the source once.

Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 05:27:07 +08:00
5bad48e122 test: let Vitest projects own test deadlines
Source projects allow 30 seconds and built projects 120 seconds, both
doubled under coverage, and hooks share their project's deadline instead
of Vitest's 10-second default. A long-running tag covers bounded
workloads that need more.

Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 05:27:07 +08:00
morluto cc7d73d23a test(ci): double test deadlines on hosted runners (#10417)
* test(javascript): give the wide fingerprint regression a capacity deadline

Each case runs about 22 s of CPU-bound projection on a typical hosted
runner. Its explicit 30 s deadline failed on slower runners at both two
and four Vitest workers, and it also overrode the suite's 60 s
coverage-mode allowance.

* test(ci): double test deadlines on hosted runners

Hosted CI jobs run four Vitest workers on a four-core runner. CPU-bound
capacity cases then share every core with other workers and their
subprocesses; three such cases exceeded the 30 s deadline at four
workers (16.8-22.7 s at two). The deadline only needs to bound a hang,
so hosted CI doubles it: 60 s, or 120 s with coverage. Local runs keep
30 s and 60 s.

* test(ci): check worker and deadline policy for local and hosted runners

The policy test loaded vitest.config.ts in a child that inherited the
parent's GITHUB_ACTIONS, so on CI it observed the hosted deadlines and
failed. Select the runner explicitly and check both: two workers and the
base deadline locally, four workers and twice the deadline on hosted CI.
2026-11-13 15:17:24 -05:00