Keep magic 3627 (CPython 3.14.6) and 3666 (CPython 3.15.0b3), whose code
layout and inline-cache tables match those interpreters' opcode tables and
whose decoded code objects match marshal.loads across a stdlib sample. Leave
the 3.15.0a8 magic 3663 unpinned, since no 3.15.0a8 interpreter was available
to check it, and regenerate the 3.15 slice fixture with 3.15.0b3.
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
The in-process equivalence checks share every module that the complete
CLI already imported, so they cannot detect a registrar that relies on
another module's import-time setup. For each registrar, a fresh rea
process now runs one of its commands with an unknown option, taking the
lazy path. The test compares the rejection document and status with the
complete CLI's.
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Every rea process imported and registered all 52 command registrars
(about 1,900 modules) before running any command. A one-shot command
now loads only the registrar that defines its top-level command.
- src/cli/cliCommandRegistrations.ts holds every registrar in one table,
grouped by tool family, with its module loader and its call. The
complete createCli registers the table with static imports, and the
types check that each entry matches its module.
- src/cli/cliShell.ts owns what does not depend on which commands are
registered: identity, globals, argument policy, completions and the
registration builtins. The full and lazy paths share it.
- scripts/record-cli-commands.mjs records, after tsc, which registrar
defines each top-level command, from the same compiled table. The
bundle keeps the record as an external dist module.
- cli/cliLoader.ts selects the recorded registrar when a known top-level
command runs. It loads the complete CLI for help, --schema, --llms,
completions, builtins, unknown names ("did you mean"), or a missing
record.
- Process-owned CLI resources register their closers when their module
loads (cli/cliResources.ts), so the shell no longer imports
JavaScript-analysis and guidance owners just to close them.
Measured on one pinned core (median of 5 warm runs, base main vs this
change):
- guidance: 1.95 s / 253 MB → 0.42 s / 101 MB
- list-cutter-sessions: 1.97 s → 0.49 s
- inspect-go-binary: 1.95 s → 0.95 s
- setup --dry-run: 2.40 s → 1.88 s
- analyze: 2.39 s → 1.78 s
- --help: 1.99 s → 2.04 s (complete CLI, as before)
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
- doctorCancellation measured from the signal, after the probe had
started, so a probe stopped by its own deadline could still pass. The
fake probe now records its start, and the check runs from there.
- rea/project-wait-deadline missed literal computed `timeout` keys and
spread options. It now reports both, as well as computed keys it
cannot read.
- The testing guide notes that a long-running test's expect.poll keeps
its project budget, while waitFor follows the tag's deadline.
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Stryker's TypeScript checker compiles the test support without
vitest.config.ts, so inject("testDeadlineScale") had type never there.
Outside a test the wait helper now uses the unscaled source deadline,
which no project's hook deadline is shorter than.
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Vitest's expect.poll and vi.waitFor stop after one second by default, a
host-speed guess that the project's deadline policy does not see. Under
hosted-CI load, kunaProjectConcurrency failed that way twice on unrelated
PRs. Another 256 waits relied on the default, and 97 passed literals
picked to fit some host.
Waits now take as long as their test may run, less the reporting reserve
that children already keep. Each Vitest project sets expect.poll's
default, and the new waitFor in tests/support/testWait.ts replaces
vi.waitFor. Fixture readiness waits (awaitAcknowledgement and the provider
process waits) default to the same deadline, and their host-speed literal
arguments are removed. One remainingTestDeadline owns the arithmetic for
both children and waits.
Ten waits whose short timeout was the real check now assert it directly
(Kuna version probe, Cutter discovery, doctor and Inspector cancellation,
apktool fixture teardown, JADX disconnect): settlement before the
production deadline that would otherwise also satisfy the wait, or a
deadline pinned beyond every test deadline.
The rea/project-wait-deadline lint rule rejects vi.waitFor and explicit
expect.poll timeouts. The testing guide and the CI tests audit skill now
document the policy.
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
process.exit() shuts Node's platform down without tearing the V8
isolate down. When a concurrent Maglev or baseline compile job is
waiting for a collection at that moment, the main thread blocks forever
in NodePlatform::Shutdown joining it (captured with gdb on Node
24.22.1). A one-shot command that called Incur's exit then never
terminated: about 1 in 20 such exits after the lazy CLI loading change,
and rarely on main.
The exit callback now sets process.exitCode and lets the event loop
drain, so Node tears the isolate down in order. A handle that outlives a
one-second grace still gets the forced exit with the same status.
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
The MCP universal-slice refusal test also compared whole English
messages; it now checks the architecture input issue and only the
offered selector. The linker-options CLI test drops its per-call child
timeout, which the testing guide reserves for testing the deadline.
Refs #9792
Refs #8935
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
The chained-import CLI test ran xcrun through a bare execFile, outside
the test's process registry, so a stalled compiler or dyld_info could
outlive the test; it now uses the processes fixture. The slice
selection refusal tests compared whole English messages; they now check
the refusal kind, the offered selector, and that the selector works.
Refs #8723
Refs #9792
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
dyld_info prints chained-fixup rows by import ordinal, and a row with two
spaces after the ordinal has two readings. REA settled them against the
nm undefined-symbol list, which omits weak-def coalesced names, so such
imports got null or ambiguous names. inspect-macho now reads the
chained-fixup import table from the binary and matches rows by ordinal,
falling back to the symbol table with a recorded limitation when the
table is unusable.
Fixes#8723
Squashed from #8724 and rebased onto main.
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
inspect-macho marked fully decoded LC_LINKER_OPTION, LC_NOTE and
LC_FILESET_ENTRY commands as undecoded. Each now counts as decoded only
when its payload is consumed exactly (the fileset string must start
right after the 32-byte header and end at cmdsize), and the note keeps
its full owner storage.
Fixes#8935
Squashed from #8937 and rebased onto main.
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Move the transient stat case into HostFileRead.test.ts behind a
pass-through fs mock (only one fixture name fails), instead of a
separate module-mocked file.
Refs #9703
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
readSpan added a member's bytes to memberBytesRead only after the whole
range read succeeded, so a read that consumed some bytes and then
failed (for example EIO) charged nothing against the packaged-probe
allowance. Charge the cumulative bytes from readFileHandleRange's
checkpoint as they arrive.
Also cover the transient stat failure that HostFileRead's test named
but never induced: EIO now has its own module-mocked test, and the
original case is renamed for what it checks.
Refs #10443
Refs #9703
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
`isHostFile` folded every stat failure into "not a file", so a library
candidate under a denied directory became a missing library, and an
unprobeable apt release file or package file read as absent.
`probeHostFile` reports ENOENT/ENOTDIR as absent and every other
failure as unknown. Apt release discovery, the package-file check and
the library walk keep those unknowns: a candidate under a directory the
linker cannot search (EACCES) is kept as a last resort and reported
unreadable rather than missing. Any other failure keeps its search
position, since glibc's open_path continues only past ENOENT and EACCES.
Fixes#9703
Squashed from #9722 and rebased onto main. Adapted on rebase: only
EACCES counts as searched past (checked on glibc 2.36, where a looping
symlink candidate ends the search), the probe reuses the domain
LibraryFileProbe type, and a stray comment is dropped.
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
The native UI verifier now removes its fixture root only after `open -W`
exits on its own (67ce671d66). The lane test's `open` stand-in stayed
alive until the test released it, so every case waited out the grace
period, retained the root and failed on the Apple E2E job. The stand-in
now exits when its fixture exits, as `open -W` does.
The shared-descendant pyc case bounded wall-clock time at 5 s; it runs in
~0.5 s locally but 4-7 s on loaded CI shards and failed scheduled runs.
The retained-heap bound and exact object counts already detect the
per-wrapper copy regression, so the host-speed assertion is removed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Since #8444 the completed observation is projected once at the composed
error's details.partial_observation rather than inside primary_error,
so restore #7319's retained-Evidence assertion there.
Refs #7279
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The testing guide asks for structured facts rather than frozen
sentences or banned phrases. The existing mutatesDevice declarations and
push receipt assertions already cover the behavior; the doc-comment
correction stays.
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main now reports a descriptor close failure as unreadable_output without
the completed partial observation, so the retained-Evidence assertion
from the original branch no longer describes current behavior. Keep the
provider-id regression this fix owns; the dropped partial observation is
tracked separately.
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A launcher whose exec is refused by an operating-system security policy
surfaces EPERM, not EACCES. It was reported as a missing launcher, so
the recovery pointed at installing apktool instead of fixing execute
permission. EPERM now joins EACCES as command_not_executable.
Squashed from #5180 and rebased onto main.
Supersedes #5180 (follow-up to #5177)
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The push_adb_file contract text already describes the tool as
device-mutating after #2990, but the AdbProvider class comment still called
the caller-requested file push the only device mutation.
Correct that comment and guard the invariant with tests: no tool contract
may claim to be the only device-mutating operation, and push_adb_file
reports its device mutation with and without device-side sha256sum
verification.
Refs #2602.
Supersedes #2868 (follow-up to #2602)
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comparing retained scenario captures flattened each side's unique step
map, so a step_id duplicated on one side vanished from that side's map;
the same id arriving uniquely on the other side then landed in
before_only/after_only and produced a missing_before_step or
missing_after_step failure for a step the duplicate side still retains.
The comparison reported both the duplicate and a definite absence for
the same id, a stronger claim than the ambiguity supports.
Alignment now keeps a duplicated id out of the absence lists on both
sides: the id stays unaligned with its duplicate failure, but no capture
is described as missing a step it retains. Genuinely missing ids keep
their missing_* classification and absence lists.
Fixes#7415
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
inspect-byte-entropy passed a hard-coded "rea-byte-entropy" to the shared command finalizer, so a failed descriptor close named a provider that differs from the Evidence provider ("byte-entropy"). Use BYTE_ENTROPY_PROVIDER.id so both come from one owner.
Fixes#7279
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The appended-signature magic `~Module signature appended~\n` is 28
bytes, matching src/domain/native/kernelModule.ts.
Fixes#7324
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Extend readmeConsistency.test.ts with a Malayalam case mirroring the
existing Persian one, addressing the P2 review finding on #6383. The
update heading's U+200C is written as an explicit escape so an editor
cannot strip it invisibly; verified the test fails when the joiner is
removed from README_ml.md.
npm run test:local -- tests/conformance/readmeConsistency.test.ts
passes 10/10.
Supersedes #6383 (follow-up to #6731)
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The guide listed three `.gnu.linkonce.this_module` statuses, but the
parser and the domain schema also return `unsupported` when the section
is stored SHF_COMPRESSED. Add that status with its condition.
The guide also presented `signature_trailer_truncated` as the result for
an appended magic with fewer than 12 preceding bytes. That branch needs
a file shorter than 40 bytes, and ELF admission requires at least 52
(ELF32) or 64 (ELF64) bytes, so the supported inspection never returns
it. State that the reason is reserved and unreachable for admitted files
without changing the parser or the schema enum.
Fixes#7669Fixes#7670
Supersedes #7758
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The registration repair guide named 24 of the 29 client IDs that
`rea setup --client` accepts. Add codebuddy, cline, kimi, workbuddy and
lm_studio, and make the documentation-facts check require every setup
client ID in that list so a new client cannot be omitted again.
Regenerate the tracked Cursor plugin copy of the reference.
Fixes#7640
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
The 6.6.0 "ADB observations and transfers" bullet thanks @Copilot, an
automation account that scripts/lib/release-notes.mjs excludes from
human credit. The current checker rejects the retained section with
"Unverified human credit @copilot". Remove that handle from the thanks
list; the human contributors and the contribution inventory stay as
they are.
Fixes#7674
Supersedes #7755
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The retained-reference example wrote the Evidence id as "ev:<digest>".
Retained ids are "ev_" followed by the digest (prefixedDigestSchema in
src/domain/digests.ts), and inspect_analysis_view rejects the colon form
with invalid_format. Use the same "ev_<digest>" placeholder as the other
guides.
Fixes#7612
Supersedes #7760
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The testing guides stated lane and shard counts in prose. The counts drifted
when the workflow changed: "all eight fast built shards" survived the move to
twelve, "Eight Linux real-system lanes" now covers twelve workflow calls, and
the SQLite guide named a Node 24.15.0 lane that the matrix no longer runs.
Describe each set by its selector and point at the workflow that owns the
exact versions, so later workflow changes cannot make the text wrong.
Fixes#7616Fixes#7617
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* refactor: prune internal seams and preserve configuration ownership
* fix(setup): keep YAML aliases and inherited registration settings on refresh
- Reuse an unchanged YAML collection only while every alias in it still
resolves after the edit; otherwise rebuild it so the alias becomes its
value. A sibling anchor replaced or moved in the same refresh no longer
leaves an unresolved alias in Hermes or Goose output.
- Keep a connection selector whose existing value already chooses stdio
(for example an inherited Hermes transport: stdio) instead of superseding
it; remote selectors are still replaced. Explicit stdio selectors are
therefore no longer rewritten (Kimi expectation updated).
- When the whole Hermes registration is inherited through a merge,
override it with that merge and write only the changed fields.
* fix(setup): edit registration fields whose YAML key is an alias
A key written as an alias to a string scalar (for example *field with
field: &field env) was treated as a source-only key, so any change to
its value was refused in Hermes and Goose. Resolve such keys to their
string, keep the aliased spelling while its anchor survives the edit,
and write the plain key when the same edit rebuilds the anchor.
* test(process): bound cleanup-boundary waits and always release gates
Both cancellation tests awaited a bare started promise and released
their gates only on success, so a missed boundary waited for the outer
deadline and could leave cleanup parked. Use awaitAcknowledgement and
release and join the cleanup in finally.
* fix(setup): repair only aliases an edit leaves unresolved
Replace the pre-edit alias survival guess, which expanded aliases to
sibling anchors that survive unchanged, with an exact repair: record
what each alias in the replaced value resolves to, write the edit, then
replace only aliases left without a preceding anchor by that value.
- Keep an aliased key's source position, so its anchor stays ahead of
later aliases.
- Treat an aliased key as its string only when no other key in the map
resolves to the same string; an ambiguous one stays guarded.
- Override an inherited Hermes registration only when the requested
entry keeps every inherited field, so an explicit replacement can drop
remote selectors.
* fix(setup): repair aliases whose binding an edit changes, keeping comments
An alias whose own anchor was removed could resolve to an earlier anchor
with the same name and silently change value. Record the node each alias
resolved to and repair any alias that no longer resolves to that node.
Carry the alias's comments and spacing onto the repaired value.
* test(setup): split the Hermes anchor and merge refresh cases
* fix(setup): refuse removing an overridden key its merge would restore
The merge-retention check skipped keys the mapping also overrides, so
dropping such a key (for example a remote url during an explicit stdio
replacement) let the retained merge restore it. Check removal before
skipping overridden keys, so the edit is refused with the existing
message instead of producing a registration that cannot be applied.
* fix(verifiers): release fixture roots only after their owners finish
Several real-tool verifiers released a fixture root even when a cleanup
that still used it had failed, so a surviving MCP server, session or
descendant kept running against a deleted directory and the failure
looked like ordinary cleanup.
- scripts/lib/verifier-cleanup.mjs: new releaseAfter(dependents,
release, retained) task. It attempts every dependent cleanup and
releases the resource only if all succeed; otherwise it keeps the
resource and reports it with the dependent failures.
- verify-signal-recording: the root is released after the MCP client
and transport close, and the host-limits read moves before the root
is acquired so its failure cannot leak the root.
- verify-recorded-crash: sessions, the sentinel and the process-lineage
check must all succeed before the root is released. A transport close
failure after a failed connect keeps the connect failure.
- verify-wasm-artifact: both roots are released after the MCP client
and transport close; the residue check and the two directories stay
independent after that.
- verify-native-ui: `open -W` exits only after the app exits, so the
root is removed only once that exit is observed; otherwise it is
retained and reported.
Fixes#8561Fixes#8562Fixes#8564
Refs #8559
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(verifiers): treat a signaled open as unproven fixture exit
A terminated `open` launcher does not prove the LaunchServices app it
started has exited, so only an `open -W` that exits on its own counts.
Also clear the grace timer so a prompt exit does not hold the process
for the rest of the grace period.
Refs #8559
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(verifiers): model open -W exiting after the fixture is signaled
The native UI verifier now removes its root only after `open -W` exits
on its own. The authored recording's `open` never exited when the
fixture was signaled and had no signalCode, so the complete case waited
out the grace period and kept the root. The double now behaves like
`open -W`: it exits once the fixture process is signaled.
Refs #8559
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ghidra): prevent loader relocations from constant folding
Ghidra imports loader relocation destinations with their file bytes. A
destination in a non-writable loaded block can be populated by the
runtime loader instead, for example a copy-relocated musl `stderr` in
RELRO, so the decompiler folded the on-disk zero and showed
`fprintf(NULL, ...)`.
Before initializing the decompiler, mark each loaded, initialized,
non-writable block containing a relocation destination volatile in the
ephemeral database, and add a limitation to procedures that read such a
destination. ELF shared objects and PIEs are included; relocatable
objects and core files are not. Permissions and source FileBytes are
unchanged.
Sessions without database-mutation authority (Windows P0 and existing
caller projects) record the limitation but do not mark blocks volatile,
and the analysis profile versions the two behaviors separately.
A real Linux Ghidra ELF probe runs in the Ghidra bridge CI lane.
Fixes#4177
Squashed from #4198 and rebased onto main. Rebase adaptations: the
read-only gate, the verifier renamed to verify-ghidra-loader-relocation
so it stays out of the manual-verifier glob, docs moved to
docs/testing-lanes.md and docs/providers/ghidra-provider.md.
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ghidra): await installation inspection in the relocation verifier
inspectGhidraInstallation became async on main after #4198's base, so the
verifier asserted on a pending Promise. Also wait for provider output to
close before reading it, like the sibling Ghidra verifiers, and keep the
workflow reference inside the docs site.
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ghidra): address relocation review findings
- Version the existing-project analysis profile with the read-only
relocation semantics, since those sessions now add the limitation.
- Inspect the installation through the verifier helper that owns the
file-reader resources.
- Build the fixture with -fPIC: with -fPIE, GCC 12 emits a copy
relocation of rea_external_value into writable .bss, so the probe's
GOT check could not hold.
- Run probe cleanup through withVerifierCleanup so a cleanup failure
does not hide the probe failure, and keep the workspace when owned
Ghidra cleanup is incomplete.
- Link the workflow with a full GitHub URL, per the docs guide.
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(ghidra): reach the external data through the GOT with a weak extern
Building the whole fixture with -fPIC also turned the reader's direct
load of rea_loader_pointer into a GOT-relaxed lea plus two loads, and
the real-Ghidra lane then reported that the baseline no longer folds
the file constant. Keep -fPIE and declare only rea_external_value weak:
GCC and clang must reach a possibly absent symbol through a GOT entry,
which lands as R_X86_64_GLOB_DAT inside GNU_RELRO (checked with readelf
for GCC 12.2 and clang/lld).
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ghidra): protect only relocations Ghidra could not apply
Running the real-Ghidra lane locally (Ghidra 12.1.4, JDK 21, GCC 12)
showed that marking every non-writable block that holds a relocation
volatile also marks full-RELRO .got. External calls then decompile as
opaque pointer calls (`(*pcVar2)(param_1)` through
`PTR_rea_external_...` instead of `rea_external(param_1)`), which the
probe's GOT-stability check caught.
Ghidra applies GLOB_DAT and RELATIVE relocations, so those bytes already
hold the loader's value and folding them is correct. The #4177 case is
a copy relocation, which Ghidra imports as UNSUPPORTED with the file's
zero in place. Protect only destinations whose relocation status is not
APPLIED or APPLIED_OTHER.
The fixture now reads a provider `const` object that the linker copies
into .data.rel.ro, the #4177 shape. The probe requires that relocation
to be unapplied and requires applied GOT relocations to stay
non-volatile. Ghidra 12.1.4 already shows this x86-64 read by name
without protection, so the probe records whether the baseline folds and
compares before and after only when it does. The profile value becomes
volatile-unapplied-relocation-blocks-v1.
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Arslan Basharat <arslanbasharat414@gmail.com>
Co-authored-by: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Across 29 successful runs, the slowest of eight shards ran 24% above the
mean shard (797 s against 646 s), with no shard index consistently slow:
duration-balanced shards still vary with hosted runner speed. Resampling
the observed per-shard speed factors predicts the slowest of twelve
shards at about 9.2 minutes instead of 13.2, for roughly 5% more runner
time.
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
verify_reconstruction trusted a structural-artifact comparison's
aggregate status without checking its rows, so a caller-imported
comparison that said "unchanged" while retaining a changed row passed
the claim.
- The artifact comparison schema rejects an "unchanged" aggregate that
retains change rows, non-zero change counts or integrity mismatches.
- Comparison Evidence validates integrity-mismatch citations like
row citations.
- Verification replays compareArtifacts over the cited source
inventories for definite outcomes, rejects manifest identities that
disagree with the sources, and withholds a pass when the sources do
not corroborate the claimed status.
Fixes#7304
Squashed from #7308 (including morluto's corroboration commits) and
rebased onto main.
Co-authored-by: ducanhnguyen223 <ducanhnguyen223@github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Co-authored-by: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* 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>
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>
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>
* 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.
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>