Commit Graph
445 Commits
Author SHA1 Message Date
morluto bd46f3c1ee test(mcp): compile advertised patterns with the regex engines clients run (#10982)
* test(mcp): compile advertised patterns with the regex engines clients run

List the built package's tools over stdio in every input, output and
catalog profile and compile each distinct advertised regular expression
with V8 (plain, u, v), Go regexp (RE2), C++ RE2, Python re, and Rust regex
and fancy-regex through the Rust jsonschema crate. A refusal names the
engine, its error, and each tool, schema path and profile.

The Python engines are pinned, hash-checked wheels; Go is the host
toolchain with GOTOOLCHAIN=local. A missing engine is reported as not
verified, and REA_REQUIRE_SCHEMA_ENGINES=1 makes it a failure.

The pattern owner now also reports patternProperties keys, which clients
compile as well.

Refs #10830

* test(mcp): run schema engine helpers and listings under the process owner

* test(mcp): load advertised schemas in the validators clients build (#10983)

* test(mcp): load advertised schemas in the validators clients build

Build a validator for every distinct advertised input and output schema
with the Rust jsonschema crate's defaults, which check the declared draft's
meta-schema and formats and compile every subschema. --complete adds Python
jsonschema's check_schema, which jsonschema.validate runs in Python clients;
it takes several seconds, so it is opt-in.

Refusals are grouped by reason, so one shared pattern that breaks many
schemas is reported once with its sites.

Ajv strict mode and OpenAI strict mode are documented as not covered, with
the reasons.

Refs #10830

* ci(mcp): require the client schema engines on every code change (#10984)

* ci(mcp): require the client schema engines on every code change

Run scripts/verify-advertised-schemas.mjs at the end of the build job, after
its artifacts upload, with REA_REQUIRE_SCHEMA_ENGINES=1 so a missing engine
fails rather than passes. Go is the runner's toolchain; the Python engines
install into a virtual environment cached by the requirements file's digest
and interpreter version. Full qualification adds --complete.

Refs #10830

* test(ci): require the client schema engine step in code builds

* test(mcp): record a reviewable summary of the advertised catalog (#10985)

* test(mcp): record a reviewable summary of the advertised catalog

Commit scripts/verify/advertised-schemas/summary.json: each advertised
pattern with the tool schemas that carry it, and a digest of every tool's
schema per input or output profile. The advertised schema check compares it
with the packaged listings it already makes and fails on any difference,
printing lines such as '119 tool schemas gained pattern /.../', so a change
that reaches many tools at once is visible in review.
--update-summary regenerates it.

Refs #10830

* docs(release): check the packed catalog with client engines before publishing (#10986)

* docs(release): check the packed catalog with client engines before publishing

Add a pre-publish step to the release guide: install the packed candidate
into an empty prefix and run verify-advertised-schemas.mjs against it with
--package-root, requiring the RE2 (Go regexp and C++ RE2) and Rust (regex,
fancy-regex and jsonschema) engines. CI checks each commit's build; this
covers the archive that will be published.

Refs #10830

* docs(release): check the exact qualified archive and clean up afterwards

* test(mcp): regenerate the advertised catalog summary from current main
2026-11-15 21:38:23 +08:00
morluto f89f82be02 refactor(verify): give the real-Hopper verifiers' roots to VerifierFixture (#11165) 2026-11-15 21:37:40 +08:00
morluto fe05a4c56d refactor(verify): release five verifier roots through VerifierFixture after their clients confirm (#11118)
* refactor(verify): release five verifier roots through VerifierFixture after their clients confirm

* fix(verify): keep the binary-layout and EVM roots until their auxiliary MCP clients confirm

* fix(verify): carry the retained root on each migrated verifier's final failure
2026-11-15 21:07:13 +08:00
morluto 5b5ca68bb3 refactor(verify): release the agent-experience run root through VerifierFixture (#11103) 2026-11-15 20:32:38 +08:00
morluto 3f88f69746 feat(verify): allocate kept verifier artifact directories through VerifierFixture (#11091)
The agent-client verifiers keep their lab directory as the run's artifact record (receipt, transcripts, profiles, Evidence) and name it as artifacts in the receipt, so it is not a fixture root that release should remove. VerifierFixture.keepArtifacts allocates such a directory canonically, never removes it, and names it on stderr at allocation so a run that fails before its receipt still reports where its artifacts are. The 11 client verifiers use it, and the verifier-fixture-root baseline shrinks by 11 sites.
2026-11-15 20:19:27 +08:00
morluto abd36dd250 refactor(browser): parse Runtime and Debugger events once by registered schemas (#10742)
* refactor(browser): parse frame lifecycle events once by a registered event schema

CdpConnection admits each event through protocol/CdpEvents.ts, which parses
the five Page frame lifecycle events once into identity facts plus a frame
URL observation, like a frame-tree node. Screenshot, page capture, the
observation timeline, WebMCP, Electron inspection and the execution window
read those facts instead of re-parsing the raw payload; CdpFrameFacts no
longer carries the raw source record. Playwright CDP session subscriptions
name an event from Playwright's protocol table, and an architecture guard
counts the remaining raw event payload reads so they can only shrink.

* refactor(browser): parse Runtime and Debugger events once by registered schemas

Register Debugger.scriptParsed, Debugger.scriptFailedToParse,
Runtime.executionContextCreated, Runtime.executionContextDestroyed and
Runtime.consoleAPICalled. Script and context payloads carry both the
tolerant facts passive capture uses and the active runtime's strict
declaration, derived from one parse, plus the declaration's byte size for
the runtime retention budget. Page capture, Electron script capture, the
V8 Inspector provider and the runtime source inventory now read the
registered payload. The cdp-raw-event-params baseline drops from 20 to 7.

* refactor(browser): admit transport events through the registered-event owner

Remove the unused cdpFrameUrl wrapper; its fragment cases now exercise
observeCdpFrameUrl. Add a connection-level test that two subscribers share
one parsed payload and the raw params.

* fix(browser): report an unserializable event declaration's size instead of throwing

JSON.stringify can throw on a declaration JSON.parse accepted (nesting
deeper than the serializer's stack). The registry sized script and context
declarations inside the connection's WebSocket callback, so such an event
escaped as an uncaught exception. The size is now a Result; the runtime
source inventory raises the failure inside its own catch, as before.

* refactor(browser): parse Network events once by registered schemas (#10743)

* refactor(browser): parse Network events once by registered schemas

Register Network.requestWillBeSent, responseReceived, loadingFinished,
loadingFailed, webSocketCreated and webSocketFrameSent/Received. The
request payload carries the tolerant facts page capture and the timeline
read plus the active runtime's strict declaration. Page capture's network
and WebSocket handlers, the timeline's request tracking and the runtime
request inventory now read the registered payload. The
cdp-raw-event-params baseline drops from 7 to 5.

* refactor(browser): drop payload helpers the capture handlers no longer use

* refactor(browser): read every CDP event payload through the registry (#10745)

* refactor(browser): read every CDP event payload through the registry

Register Target.attachedToTarget, Target.detachedFromTarget,
Page.lifecycleEvent and WebMCP.toolsAdded/toolsRemoved, and carry a
requested navigation's reason and a commit's transition type in the
frame-event payload. The timeline no longer threads raw params into its
entries: each entry receives its timestamp, frame and loader identity
explicitly. WebMCP discovery, the service-worker policy blocker and the
target-event matcher read the registered payload. With no raw reads left,
the cdp-raw-event-params guard is enforced at zero instead of counted.

* refactor(browser): drop raw payload helpers the timeline and worker blocker no longer use

* refactor(browser): type Playwright CDP session events by the registry (#10751)

PlaywrightCdpSession.on subscribes only to registered events and hands
the listener the payload parsed by its registered schema, returning the
unsubscribe function. Private storage seeding reads registered payloads,
including the events of non-flat child sessions, and applies its strict
seeding policy to the parsed facts. Its local attach, detach, nested
message and pause schemas and the storage-only script/context schemas are
removed; Debugger.paused, Runtime.executionContextsCleared and
Target.receivedMessageFromTarget join the registry.

* test(browser): admit fake policy events through the event registry

The service-worker policy now reads event.registered, but the PlaywrightScenarioSession fake connection delivered raw events, so three detached-target tests never reached the policy. The fake now admits each event with receiveCdpEvent as CdpConnection does.

* fix(browser): fail the CDP session closed when an event listener throws (#10758)

* fix(browser): fail the CDP session closed when an event listener throws

An exception from a CDP event subscriber escaped CdpTransportCore's socket message callback uncaught (for example the service-worker blocker's protocol_error on a Target event without a sessionId). The transport now stops delivery, fails the connection as a protocol error whose cause is the listener's exception, rejects pending and later commands with it, and notifies protocol-failure subscribers. The Playwright CDP session relay applies the same rule to its event listeners.

* fix(browser): report a failed service-worker policy connection at the next policy check

The policy's event listener rejects a malformed Target event, which now fails its connection. With no policy command pending, nothing reported it and later iframe targets went unprotected. The policy records its connection's protocol failure and assertBlocked, run before each scenario step, rethrows it.

* fix(browser): keep cleanup commands available after a listener failure

A listener failure no longer marks the wire as broken. The transport still rejects pending commands, notifies protocol-failure subscribers, stops delivering events and refuses reuse, but it keeps reading replies and admits commands sent in cleanup grace. The service-worker policy can then remove its init scripts, restore the main realm, detach and release its socket. Wire-level protocol errors still refuse every later command. The PlaywrightScenarioSession policy fake gains onProtocolFailure, which the policy now subscribes to.

* refactor(browser): keep raw CDP event payloads out of the received event (#10764)

* refactor(browser): keep raw CDP event payloads out of the received event

CdpReceivedEvent and CdpTransportEvent no longer carry params: receiveCdpEvent hands the raw payload only to the registered schema, so a subscriber cannot read it by property access, destructuring or computed keys. This supersedes the event.params text guard in architecture-guards, which is removed.

* refactor(browser): read registered event payloads in the JavaScript verifiers

The runtime, storage and URL-userinfo verifiers subscribe to CdpConnection, which no longer hands subscribers raw params. They now read event.registered. A test scans every scripts/ onEvent callback for raw payload reads, since the TypeScript check does not cover them. The storage verifier's pause trace records a malformed pause instead of the unregistered reason member.

* refactor(browser): track the timeline's main frame with the document tracker (#10779)

TimelineCapture kept its own mutable main frame id and replaced it on a root replacement. It now holds the CdpDocumentTracker that CdpTargetSession owns and observes the replacement document through it; every main-frame check (lifecycle, navigation, document request, redirect) reads the tracker's current frame. A characterization test pins that the replaced root's lifecycle events are no longer recorded.

* refactor(browser): select CDP events only by their registered name (#10829)

CdpReceivedEvent carried the wire method as a plain string, so a subscriber
could compare it with a misspelt or unregistered name and the check compiled
but never matched. Three owners selected Inspector.targetCrashed, an
unregistered event, that way.

Register Inspector.targetCrashed and drop the wire method from the received
event. Subscribers select events by registered.method, whose type is the
registered event names. The capture coverage start keeps reading the
wire domain, now the event's domain field.

* fix(browser): retire a policy child session that CDP reports gone

After a listener failure the connection stops delivering events, so an
iframe's Target.detachedFromTarget never retires its policy target. Cleanup
then sent Page.removeScriptToEvaluateOnNewDocument to the dead session,
kept the stale child, and every retry failed before detaching the root.

The service-worker policy owner now treats CDP's session-not-found
rejection as proof that the child is gone and retires it. The classifier
moves from CdpTargetSession to CdpCommandRejection, its owner, and the
target-session detach path uses the same one.

* refactor(browser): route target events through one session owner (#10835)

* refactor(browser): route target events through one session owner

Page capture, WebMCP discovery, screenshot capture and the runtime sources
each compared the envelope session ID themselves, while the observation
window and execution collection used cdpTargetEventMatches, which also
routes the root Target.detachedFromTarget that names the target's session.

onCdpTargetEvent in CdpTargetEvents.ts now subscribes every target consumer
with that one rule; the matcher is private and the per-subscriber
comparisons are removed. Electron inspection keeps its own filter while
its capture isolation awaits a maintainer decision.

* fix(browser): report WebMCP subframe tools whose document is unverified (#10839)

* fix(browser): report WebMCP subframe tools whose document is unverified

A committed subframe navigation kept the frame's tools silently when CDP
reported no loader at the same URL, and removed them on any URL change even
when the loader proved the same document.

Each frame now carries a CdpDocumentTracker, the session's document
identity owner. Only a proven change removes the frame's tools. An unknown
comparison keeps them visible, marks webmcp_tools attach-limited and names
the frames whose document identity could not be established.

* test(browser): prove an unverified live subframe limits WebMCP coverage

* fix(browser): key a WebMCP registration by its frame and tool name

A subframe tool kept across a committed navigation that changed the URL
but not the loader was stored under a key built from the old URL, so a
later toolsAdded for the same frame and name added a second entry.
Registrations are now keyed by frame and name; tool_key still records the
registering frame URL.

* test(browser): deliver fake CDP events through the transport's admission (#10840)

Event fakes each rebuilt the received event: CdpAgentHints typed its
listeners as raw wire events behind an unknown cast, and the Electron,
scenario-session and routing tests each wrapped receiveCdpEvent by hand.

fakeCdpEvents (tests/fixtures) is a CdpConnection.onEvent fake whose emit
admits each raw event with receiveCdpEvent and the wire byte count, so a
change to the received event shape fails at the fake instead of silently
not exercising subscribers.

* refactor(browser): own the selected page generation in one target document tracker (#10860)

* refactor(browser): own the selected page generation in one target document tracker

Page capture, screenshot, the observation window, the runtime session and
the execution window each built a document tracker or rule of their own
from root-frame navigation events. CdpTargetDocument now follows the target
session's root-frame events and the frame-tree replies its consumers read,
classifies root identity once, and reports each navigation to consumers
that decide only what it means for their evidence.

* fix(browser): report a lost scenario policy connection before the next step (#10864)

* fix(browser): report a lost scenario policy connection before the next step

The service-worker policy recorded only protocol failures. When its CDP
socket closed or its page session detached, later documents lost the
blocking script, but the scenario learned of it only when a frame check
found an unprotected realm. The owner now records the disconnect or
detach when CDP reports it; the next policy check and the next step's
action report it first.

* fix(browser): refuse an unregistered CDP command before it reaches the browser (#10868)

JavaScript verifiers can name any command, and the send owners refused an
unregistered one only when its reply arrived, after the browser had acted
on it. CdpConnection and the Playwright session now refuse the name before
sending, and the Playwright session refuses an unregistered event name
instead of subscribing to events no listener receives. The verifier text
scan stays as an early warning and documents what it cannot see.

* fix(browser): keep a proven root change and the loaderless selection's uncertainty

Two review findings on the target document owner. A root event naming
another frame with a malformed loader set `changed` but was announced as
unidentified, so the execution window failed with protocol_error and
dropped what it had collected; the owner now announces it as the proven
change it is. The runtime session compared each frame-tree reply with the
tracker's current document, which can learn a loader from an event, so a
loaderless selection followed by an event and a reply with that loader
compared as same; it now compares the reply with the selected document
through the owner, and reports target_changed as before.

* test(browser): refuse the next scenario step after the policy session detaches

* refactor(browser): read WebMCP document identity from the target document owner (#10884)

* refactor(browser): read WebMCP document identity from the target document owner

WebMCP discovery compared the first and last frame-tree roots itself and
kept a document tracker per subframe. CdpTargetDocument now follows the
selected root and each committed subframe for it: the final frame tree
feeds the owner, a root change proven by a navigation event during
discovery is target_changed as in page capture, and a subframe whose
committed document changed loses its tools. A subframe navigation without
a loader still keeps the tools and reports them as unverified.

* fix(browser): start a subframe first seen within its document with an unknown loader

A subframe absent from the initial frame tree and first seen through Page.navigatedWithinDocument had no document tracker, so a later commit started a fresh one and the tools it registered meanwhile lost the unverified-document limitation. The owner now starts such a subframe with an unknown loader.

* fix(browser): refuse a verifier's unregistered CDP event name at subscription (#10885)

JavaScript verifiers subscribed to every event with CdpConnection.onEvent
and compared registered.method with a string literal. A misspelt or
unregistered name never matched and the verifier waited until its timeout.
CdpConnection.onRegisteredEvent now takes one event name, refuses an
unregistered one before subscribing (the same registry check the Playwright
session applies), and hands the listener only that event's registered
parse. The verifiers subscribe only through it, and the evaluation test
rejects a raw onEvent subscription in scripts.

* fix(browser): keep subframe documents by frame and loader without their URLs
2026-11-15 19:54:17 +08:00
morluto 47d14d0fb8 refactor(verify): give the javascript verifiers' roots to VerifierFixture (#11068)
* refactor(verify): give the javascript verifiers' roots to VerifierFixture

VerifierFixture.retain(reason) keeps a root that an owned command whose
cleanup is incomplete may still use, replacing each verifier's local
retain flag and cleanup closure.

* refactor(verify): give the Ghidra COM, DOS, 6502, NativeAOT and raw verifiers' workspaces to VerifierFixture (#11070)

* refactor(verify): give the Ghidra COM, DOS, 6502, NativeAOT and raw verifiers' workspaces to VerifierFixture

* refactor(verify): keep the Ghidra decompiler-failure, decompile-timeout and no-return workspaces through VerifierFixture until owned cleanup is verified (#11077)
2026-11-15 19:52:38 +08:00
morluto 4126698407 feat(mcp): project compact input schemas into the portable advertised dialect (#10632)
* test(mcp): check advertised schemas against a portable dialect in every profile

* fix(mcp): re-emit advertised patterns in a portable regex grammar

* fix(mcp): present discover_tools input through the selected profile

The hot-cold catalog registered discover_tools directly with the SDK, so
the default compact input profile still advertised its canonical schema,
including page-size defaults clients apply on their own (#5322). Route
every listed input schema, transport discovery included, through one
server-owned presentation, and pass the selected presentation to the
deferred server, which serves recorded tool schemas but not discovery.

* fix(mcp): keep the Evidence union on described borrowed inputs

borrowEvidenceInput installed its advertised projection on one schema
instance. A call site's .describe() rebuilds the schema from its
definition, so match_native_functions advertised left and right as
unconstrained values in every input profile. Install the projection in
the borrowed parser's constructor so derived schemas keep it, for both
borrowed inputs and borrowed arrays.

* fix(mcp): validate advertised dialect by selected profile

* fix(mcp): preserve schema widening through references

* feat(mcp): project compact input schemas into the portable advertised dialect

One projection (advertisedDialectProjection.ts) owns the compact input
advertisement: one type per node, items on every array, string literals
as enums, oneOf widened to anyOf, allOf merged, tuples as element unions,
exclusive bounds made inclusive, and every keyword outside the dialect
dropped. Each rewrite is exact or widening; server validation is
unchanged. The root description and sentences for dropped cross-field
constraints move to the tool description, which Codex and Zed keep.

The compact baseline falls to nullable values only (29), which the
dialect cannot express without narrowing an input. The gateway shape
repairs (typeArrayItemUnions, hasGatewayIncompatibleShape), the second
dependentRequired-to-prose copy and the strict-gateway test denylist are
removed; the dialect checker gates the inline presentation instead.

* fix(mcp): refuse zero-padded repeat bounds and record host-specific path patterns

* fix(mcp): keep projected schemas permissive

* fix(mcp): keep references valid when presentation widens their targets

* fix(mcp): keep a single union branch's closure scoped to its properties

* fix(mcp): keep an allOf member's tuple tail with its own positions

* fix(mcp): relax references into negations and conditionals presentation may remove

* test(mcp): select the borrowed Evidence contract from its family

* fix(mcp): keep astral literals and dynamic references widening in every mode

* fix(mcp): omit astral literals and relax untracked references when presentation widens

* fix(mcp): read reference pointers by schema position, not segment spelling

* fix(mcp): protect references into collapsing boolean unions and keep referencing branches out of the collapse

* fix(mcp): keep reduced schemas open when their root admits names by pattern

* test(mcp): keep the reduced-schema pattern case outside the size-limited block

* fix(mcp): omit patterns whose classes name astral characters

* fix(mcp): decide union collapse and pointer protection from canonical branches

* docs(mcp): document non-u astral matching and pin BMP agreement across V8 modes

* fix(mcp): keep prototype-named properties as own properties in the dialect projection

* test(mcp): expect the advertised base64 schema to omit the unbounded pad-bit probe

* fix(mcp): protect references into unevaluated keywords lost evaluation removes

* fix(mcp): emit stack-safe classes with non-ASCII members and protect draft-07 reference siblings

* fix(mcp): protect references into literal siblings of relaxed draft-07 references

* feat(mcp): omit output schemas from tools/list by default (#10646)

* feat(mcp): omit output schemas from tools/list by default

No surveyed model API reads an output schema, MCP client validators
repeat REA's own result validation, and complete output schemas were
about 92% of the default tools/list. REA_MCP_OUTPUT_SCHEMA_PROFILE now
resolves to off through one owner (resolveMcpOutputSchemaProfile);
compact and full remain selectable. structuredContent is still
delivered, and the deferred server serves both off and full from the
recorded catalog with the matching recorded identity.

Tests and artifact verifiers that validate results against complete
advertised output contracts select full explicitly.

* fix(mcp): select schemas in verification workflows

* fix(mcp): select complete output schemas in the Electron verifier

* fix(mcp): select complete output schemas in standalone verifier probes

* fix(mcp): select complete output schemas in every verifier transport

* test(mcp): select full output schemas in packet and signal schema checks

* fix(mcp): validate the doctor probe reply against the canonical output contract (#10655)

* fix(mcp): validate the doctor probe reply against the canonical output contract

* test(mcp): replay doctor probe validation under every output profile

* test(mcp): accept typed-branch nullable unions in the advertised dialect (#10649)

* test(mcp): select full output schemas in HTTP session workflows

* fix(mcp): keep the Evidence union on described borrowed inputs (#10597)

* fix(mcp): keep the Evidence union on described borrowed inputs

borrowEvidenceInput installed its advertised projection on one schema
instance. A call site's .describe() rebuilds the schema from its
definition, so match_native_functions advertised left and right as
unconstrained values in every input profile. Install the projection in
the borrowed parser's constructor so derived schemas keep it, for both
borrowed inputs and borrowed arrays.

* test(mcp): select the borrowed Evidence contract from its family

* docs(mcp): admit baseline growth only for restored contract declarations

* fix(mcp): state reduced multi-type properties as typed branches, not type lists

The reduced fallback derived a property's types and emitted them as a type
list, which Gemini, Moonshot and Ark reject. A property whose canonical
schema is anyOf string and number therefore traded a typed union for a
rejected construct when the inline projection fell back. Emit one type, or
anyOf typed branches, so [T, null] becomes the dialect's nullable union.
2026-11-15 18:26:13 +08:00
morluto add15d65b3 refactor(verify): give verifier fixture roots one lease on src/process (#10988)
* refactor(verify): give verifier fixture roots one lease on src/process

* fix(verify): keep fixture registration closed, carry the lease on the caught failure, share cleanups once
2026-11-15 18:02:28 +08:00
morluto 2caedcfb57 refactor(platform): give the host platform one owner and ratchet ambient process.platform reads (#10911)
* refactor(platform): give the host platform one owner and ratchet ambient process.platform reads

* refactor(process): pass the host platform to process sampling instead of reading it ambiently

#10755 added two process.platform reads (ps selection in process sampling and the
desktop build doctor's ps fact) after the host-platform ratchet was measured.
The desktop fact already receives the host platform from doctor; process sampling
now receives it from the capture harness, removing all five ambient reads there.
2026-11-15 17:42:23 +08:00
morluto d0fee4e58e fix(mcp): re-emit advertised patterns in a portable regex grammar (#10582)
* test(mcp): check advertised schemas against a portable dialect in every profile

* fix(mcp): re-emit advertised patterns in a portable regex grammar

* fix(mcp): validate advertised dialect by selected profile

* fix(mcp): preserve schema widening through references

* fix(mcp): refuse zero-padded repeat bounds and record host-specific path patterns

* fix(mcp): keep references valid when presentation widens their targets

* fix(mcp): relax references into negations and conditionals presentation may remove

* fix(mcp): keep astral literals and dynamic references widening in every mode

* fix(mcp): omit astral literals and relax untracked references when presentation widens

* fix(mcp): read reference pointers by schema position, not segment spelling

* fix(mcp): protect references into collapsing boolean unions and keep referencing branches out of the collapse

* fix(mcp): omit patterns whose classes name astral characters

* fix(mcp): decide union collapse and pointer protection from canonical branches

* docs(mcp): document non-u astral matching and pin BMP agreement across V8 modes

* test(mcp): expect the advertised base64 schema to omit the unbounded pad-bit probe

* fix(mcp): protect references into unevaluated keywords lost evaluation removes

* fix(mcp): emit stack-safe classes with non-ASCII members and protect draft-07 reference siblings

* fix(mcp): protect references into literal siblings of relaxed draft-07 references
2026-11-15 17:06:43 +08:00
morluto 45881575a6 ci(windows): validate advertised MCP schemas in the Windows lane (#10785)
* ci(windows): validate host-absolute path schemas in the Windows lane

Windows hosts advertise their own absolute-path pattern (#7151). The lane
compiled it through advertisedDialect.test.ts but never validated a Windows
path against it. Run absoluteLocalPathSchema.test.ts there, select the lane
when the pattern's owner changes, and guard both schema checks in the lane.

Refs #10517

* ci(windows): run live MCP schema validity in the Windows lane

toolSchemaValidity.test.ts compared the live advertisement with the
POSIX-generated .cache/mcp-tool-catalog.json, so it could not run where
the Windows lane skips artifact generation. Move the generated-catalog
cases into generatedToolCatalog.test.ts, share the reference walkers
through the advertised-schema fixture, and add the live-server file to
the curated Windows lane and its scope.
2026-11-15 17:02:56 +08:00
morluto 254bb21857 refactor(browser): send only CDP commands with registered result schemas (#10666)
* refactor(browser): send only CDP commands with registered result schemas

* refactor(browser): open Playwright CDP sessions only through the registered-command owner

* fix(browser): keep the restore obligation for an applied override with a malformed reply

A schema-rejected success reply means the browser applied the Emulation
override, so the attached environment owner records the reset obligation
before reporting the protocol error. Only a rejected or unanswered command
leaves no obligation.

* refactor(browser): open verifier-script CDP sessions through the registered-command owner (#10710)

* fix(browser): register the CDP commands JavaScript verifiers send

The verifier scripts send Browser.close, Page.createIsolatedWorld, Page.navigate, Page.reload, Target.activateTarget, Target.closeTarget and Target.createTarget through CdpConnection, which now admits every reply through its command's result schema. Register those schemas, refuse an unregistered run-time name as a typed malformed reply instead of a TypeError, and check script send literals against the registry.

* fix(browser): keep Target.closeTarget's success member for the verifiers
2026-11-15 14:49:33 +08:00
morluto 8c052bdec5 test(architecture): ratchet top-level layer direction and mutual imports (#10584)
* test(architecture): ratchet top-level layer direction and mutual imports

Declare a layer for every top-level src/ directory and root source file
(domain, contracts, foundation, providers, application, composition,
adapters) in scripts/lib/module-layers.mjs. verify:module-boundaries now also
builds the production import graph between those units and compares it with
a counted baseline: 45 unit pairs import a higher layer (248 imports) and 23
unit pairs import each other. A new upward pair, more imports on a recorded
pair, a new mutual import, or an undeclared unit fails; shrinkage is
reported so the baseline can be lowered.

* fix(architecture): enforce layers for isolated units
2026-11-15 08:37:04 +08:00
morluto 959af004df docs: refuse literal tool counts in living prose (#10585)
* docs: refuse literal tool counts in living prose

docs:check now refuses a count of ten or more tools in README, AGENTS,
CONTRIBUTING, docs/ (except dated releases, specs, verification and ADR
records), the authored skill and the public website. The catalog owns that
number and every hand-written copy goes stale when a tool is added. The three
current statements (240, 172 and 254 tools, all measured on earlier builds)
now refer to the catalog of the measured build instead.

* fix(docs): exclude generated pages from prose checks

* fix(docs): rerun the tool-count check when any scanned prose changes

The docs:check:built cache inputs and the CI docs lane did not cover AGENTS.md, CONTRIBUTING.md, every .agents/skills tree or website/public, so an edit there could reuse a cached pass or skip the docs job. The scanner now owns one isLivingProsePath predicate; the CI plan selects the docs lane with it, and a test binds the turbo inputs to the scanned roots.
2026-11-14 18:58:24 -05:00
morluto 3e0dc29041 fix(browser): type CDP command replies and parse frame trees once (#10604)
* fix(browser): type CDP command replies and parse frame trees once

CdpConnection.send is typed by method name. A command registered in
src/browser/protocol/CdpCommands.ts has its parameters typed from the
protocol table Playwright ships and its reply parsed once by its own result
schema; a mismatch rejects that command with CdpMalformedReply
(protocol_error, command, JSON pointer) without poisoning the connection.
Playwright storage sessions admit replies through the same table.

Page.getFrameTree and Page.getResourceTree are the first registered
commands. Their one parser keeps per-frame facts tolerant (malformed child
entries remain explicit omissions) and replaces the per-site readers:
observeMainFrameUrl, mainFrameUrl, walkFrameTrees, frameTreeResources,
runtimeFrameTreeSchema and the scenario storage frame schema.

A reply without a frame tree used to be retried for two seconds and
reported as target_not_allowed; it is now one protocol_error.

A guard test counts literal CDP command names without a result schema per
source file; the baseline can only shrink.

* fix(browser): consume parsed CDP facts across boundaries
2026-11-14 15:21:00 -05:00
morluto ef1b92bf1e test(mcp): check advertised schemas against a portable dialect in every profile (#10567)
* test(mcp): check advertised schemas against a portable dialect in every profile

* fix(mcp): validate advertised dialect by selected profile

* fix(mcp): refuse zero-padded repeat bounds and record host-specific path patterns
2026-11-14 15:20:31 -05:00
morluto e53212655b refactor(contracts): derive the public tool catalog from one contract-group list (#10564)
* refactor(contracts): derive the public tool catalog from one contract-group list

toolContracts.ts and toolFamilies.ts each imported and listed the same
contract groups. toolContracts.ts now owns one ordered group object;
TOOL_CONTRACTS is its flattened values in the same catalog order, and
toolFamilies.ts reads TOOL_CONTRACT_GROUPS from it instead of re-importing
every group. The static catalog-source lint rule learns the
Object.values(groups).flat() composition so positional-contract enforcement
still discovers every group without executing modules.

* fix(lint): reject computed tool catalog groups
2026-11-15 04:07:17 +08:00
2SinceJulyandgensokyo-dev 30d23ccd92 fix(verifiers): accept Hopper's declared unknown relationship coverage
verify-real-hopper asserted complete relationship coverage for
analyze_function, but HopperProvider always declares unknown caller and
callee coverage with a reason, and compare_functions then reports the
calls dimension as unknown. The fixture oracle now checks the declared
unknown and its reason instead of demanding coverage Hopper never
claims.

Fixes #8067

Only the verifier hunk of #9496 is taken; the rest of that PR reverted
unrelated main code.

Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
2026-11-14 14:16:39 +01:00
0b21b6ce03 fix(skill): keep recovery client IDs aligned with the setup registry
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>
2026-11-14 10:21:04 +01:00
morluto b138f52e12 refactor: prune internal seams and preserve configuration ownership (#10430)
* 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.
2026-11-14 04:08:37 -05:00
67ce671d66 fix(verifiers): release fixture roots only after their owners finish (#10491)
* 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 #8561
Fixes #8562
Fixes #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>
2026-11-14 09:56:18 +01:00
Kaoru0822 5cddc69c51 fix(verify): keep adopted resources live until command owner closes (#10314) 2026-11-12 23:58:18 -08:00
Kaoru0822 7c9d65fe97 fix(test): resolve filesystem aliases before planning prerequisites (#10213) 2026-11-12 20:29:42 -08:00
morluto 02ebd3e02d refactor: prune test-only seams and obsolete helpers (#10275) 2026-11-12 19:24:54 -05:00
morluto 653c49419e fix(release): validate notes with the publication parser 2026-11-12 05:17:10 -05:00
morluto 5eef239dfd fix(ci): defer proposals for merged release commits 2026-11-12 05:08:27 -05:00
morluto ab84ba6839 fix(process)!: retain inspection cancellation and cleanup ownership (#10113)
* fix(process): preserve producer-owned inspection cancellation

Prototype the explicit inspection origin and retained file/batch owner protocol. Downstream adapter migration and lease binding remain required before integration.

* fix(process): type inspection ownership handoffs precisely

* fix(process): retain plain inspection preparation cancellation

* fix(process): retain explicit inspection cleanup and cancellation facts

* fix(process): require explicit inspection facts and cleanup scope

* refactor(process): remove redundant cleanup forwarding wrapper

* fix(firmware): retain inspection cancellation and cleanup ownership

* fix(wakaru): retain typed inspection outcomes and caller scope

* fix(ghidra): preserve inspection facts and launch cleanup scope

* fix(providers): preserve typed process inspection outcomes

* refactor(process): remove obsolete inspection cancellation re-export

* fix(native): preserve inspection preparation cleanup and cancellation

* fix(registration): retain typed inspection cleanup during Git discovery

* fix(process): preserve inspection deadline origin in adapter handoff

* fix(process): consume the canonical inspection selector in binding

* fix(native): preserve inspection deadlines and cleanup retry completion

* test(process): narrow the retained Darwin preparation owner

* fix(providers): preserve preparation ownership and timeout policy

Narrow preparation facts through their canonical owner, preserve actual cleanup capabilities and recorded cancellation, and keep enclosing command deadlines authoritative. Retain raw inspection records through Java refusal and configuration projections without changing availability fallback policy.

* refactor(process): use one inspection failure type owner

* fix(providers): retain recorded secondary failures when rebinding

* fix(ghidra): preserve normalized inspection facts through public projection

* fix(process): normalize native process listing cancellation

* docs(development): clarify failure provenance and cleanup verification

* fix(process): preserve direct inspection cancellation facts

* fix(process): retain inspection owners through termination

* fix(process): preserve command inspection cleanup provenance

* fix(desktop): preserve inspection facts after cleanup retry

* refactor(process)!: migrate desktop capture with inspection producers

* fix(desktop)!: preserve capture failure origins and cleanup owners (#10115)

* fix(desktop): preserve capture failure origins and cleanup

* fix(desktop): type keyring cleanup cancellation

* fix(kuna)!: retain copy cleanup before retiring workspaces (#10114)

* fix(kuna): own copy cancellation and descriptor cleanup

* fix(kuna): close copy descriptors before workspace removal

* test(kuna): type copy lifecycle gates for project library

* docs(kuna): explain retained copy-file cleanup and staging ownership

* docs(kuna): separate cache publication, integrity and cleanup guidance

* fix(desktop): retain sampling inspection owners before release

* fix(process): preserve capture file read cancellation origin

* fix(process): retain capture inspection cancellation and cleanup owners

* fix(process): retain sampling inspection failures in capture scope

* fix(process): retain inspection failures through mandatory cleanup

* fix(process): distinguish sampler shutdown from capture cancellation

* fix(browser): retain startup EOF before later cancellation

* fix(process): bind capture inspection cleanup to the owning run

* test(process): migrate cancellation fixtures to typed owners

Record explicit preparation and command cancellation facts, retain exact opaque reasons and physical causes, and guard the mocked version probe from native preparation. Keep the live Wakaru command control while adding a recording equivalent for bounded source verification.

* fix(process): own sampling reads and settle inspection peers

* fix(errors): retain authored recovery through cleanup composition

* fix(process): retain all sampling inspection leaves for final cleanup

* test(browser): report recording cleanup signal outcome

* fix(process): keep inspection error context out of implicit JSON

* fix(desktop): retain normalized sampling cleanup ownership

* test(process): assert tagged startup cancellation
2026-11-11 16:37:48 -05:00
morlutoand吴佳浩 1b36fc2d50 fix(scripts): validate package-map ownership and preserve HTML fallback (#10097)
* fix(website): keep the HTML validator when the Markdown route is absent

A caller that prefers Markdown gets the HTML probe with its conditional headers
deleted, so the Markdown route can be evaluated on its own. When the Markdown
sidecar is missing the worker answers with that probe, which never saw the
caller's `If-None-Match`, so a matching HTML ETag returned 200 instead of 304.

Ask the asset service again with the caller's own request before answering with
HTML. The decision moves into `htmlFallback` so the request handler keeps its
complexity below the repository bound.

Verified by executing `node --test website/worker.test.mjs`: without the change
the new case fails with 200 instead of 304, and all four cases pass with it.
`oxlint` reports no findings and `oxfmt --check` passes. The website worker test
is not part of a CI workflow, so this suite runs locally only.

* fix(scripts): resolve package-map imports in the module-boundary guard

The guard resolved only relative, absolute and `file:` specifiers, so every
`#`-prefixed package-map import returned no target and was skipped. A pure-layer
file importing `#javascript-analysis-worker` passed, while the same import
written relatively failed with a `pure-layer` diagnostic: the gate failed open
on the spelling the package map exists to encourage.

Resolve a package-map specifier to the source file that produces its built
output, then apply the same ownership rules. The package map is read once per
repository root.

Verified with the new `scripts/lib/module-boundaries.test.mjs` (2 pass; the
package-map case failed before the change) and by running the complete guard on
this checkout, which still reports 4138 files with no findings, so the new rule
adds no false positive. `oxfmt --check` passes; `oxlint` reports the same single
pre-existing `failedBoundary` complexity warning it reported before this change.
The script tests are not part of a CI workflow, so this suite runs locally only.

* fix(scripts): normalize package targets as file URLs

---------

Co-authored-by: 吴佳浩 <wujiahao@supremind.com>
2026-11-11 08:27:39 -05:00
morluto 3ad2e214be fix(verifier): retain UF2 workspace until resource cleanup completes (#10096)
* fix(verifier): retain UF2 workspace until resource cleanup completes

* fix(verifiers): retain firmware workspace cleanup ownership
2026-11-11 18:53:02 +08:00
morlutoandCursor Agent b00138be64 fix(verification): retain failed cleanup owners and primary errors (#9993)
* fix(verifiers): retain native cleanup ownership on failure

* fix(verification): load cleanup fixtures through the module resolver

CodeQL's local threat model treats file contents passed to
vm.SourceTextModule as user-controlled code execution. Import the real
verifier modules and redirect their dependencies to static mocks instead
of compiling script text read from disk.

* fix(verifiers): own CLI and MCP process families

* fix(verifiers): retire workspaces after cleanup retry

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-11-11 17:39:19 +08:00
morlutoandCursor Agent 83f0a4d238 fix(ci)!: verify exact conformance fixture records (#9977)
* fix(ci)!: verify exact conformance fixture records

BREAKING CHANGE: Regenerate unversioned conformance manifests with npm run build:fixtures. Schema version 2 separates exact string markers from intentional fragments and rejects the ambiguous strings field.

* test(conformance): wait out a cold verifier instead of treating SIGTERM as rejection

The compiler-produced complete/REA_C_ENTRY run was killed by its 10s
execFile timeout on the loaded source-test runner, with empty stderr and
SIGTERM. The stricter record checks already passed locally and for the
other compiler-produced cases. Assert the process status and give that
cold run room inside the test budget.

* fix(ci): preserve carriage returns in nm symbol records

nm -j terminates each name with LF. A carriage return before that LF is
part of the symbol. Splitting on CR LF dropped it, so a renamed symbol
ending in CR matched the name without it.

* test(ci): supervise conformance verifier subprocesses

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-11-11 17:28:10 +08:00
morluto 4d0f6d9b42 fix(ci): retain Hopper fixture receipt counts (#9976) 2026-11-11 17:22:14 +08:00
morluto ea00ca2d46 fix(verify): preserve Ghidra oracle state and coverage (#9994)
* fix(verify): check checkpoint state before restoring fixtures

* fix(verify): require applicable Ghidra decoder controls

* refactor(verify): require explicit instruction fixture facts
2026-11-11 17:21:11 +08:00
a54e848302 feat(cursor): ship a Marketplace plugin with the skill and pinned MCP server (#9878)
Cursor Marketplace installs are Git checkouts, so the plugin manifest
points at a synced copy of the authored skill and starts
npx -y rea-agents@<release> mcp. Release Please and the release
checkpoint keep that pin aligned with the package version.

The manifest, skill, and icon checks follow the local plugin bundle
contract from #7619, adapted for a checkout that has no dist/.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: GamerDubz <105694977+GamerDubz@users.noreply.github.com>
2026-11-11 00:16:44 -05:00
morluto 4082375e73 fix(verifiers): preserve results and own cleanup through completion
Attempt independent resource cleanup without losing primary failures, retain unresolved owners, and publish completion after release. Bound existing producer commands, preserve helper return values, and settle startup and fixture children on failure.

Validation: 29 focused boundary tests passed; actual helper-value and import-bound filesystem cleanup controls passed. The real inert-child termination control and targeted JavaScript binding checks passed, alongside typecheck, lint and formatting. Live Ghidra, Cutter, Electron GUI and Windows addon qualification was not run.
2026-11-10 17:03:59 -05:00
morluto dcee59f273 test: strengthen independent oracles and consolidate boundary coverage
Require delivered facts, exact cancellation and malformed-input boundaries, and independent metadata expectations. Transfer unique assertions into stronger keepers before removing duplicate cases and overwritten fixture writes; preserve all consumed core fixture bytes.

Validation: 1,190 focused tests passed with 39 platform-dependent skips; 134 composition and conformance tests passed. Typecheck, lint, formatting, discovery and Knip passed. Independent preservation reviews and targeted regression controls passed.
2026-11-10 17:03:59 -05:00
morluto 0c37c22d51 test: remove copied authentication after command cleanup failure 2026-11-10 16:43:39 -05:00
morluto a9882a58b2 test: use a portable producer for HTTP/3 cleanup 2026-11-10 16:02:00 -05:00
dbfab4a65d fix(cli): refuse an unsupported Node.js release before linking (#9297)
* fix(cli): refuse an unsupported Node.js release before linking

The dispatcher imported the compiled runtime before checking the runtime
range, so a release outside `engines.node` failed while linking a module
that imports `createZstdDecompress`. Callers saw a module-linking stack
trace from every command, including `--version` and `doctor`, instead of
the refusal the installer and `engines` already promise.

Check `engines.node` from the package read the dispatcher already performs,
before the first compiled import. The helper has no imports of its own: the
dispatcher must admit the runtime before any dependency can be resolved.

Fixes #9296

* fix(cli): ship and align runtime admission

* fix(ci): cover packaged runtime admission helper

* test(cli): assert Node admission with structured range results

Export satisfiesNodeRange and cover caret, minimum, union, and
non-release versions. The dispatcher proves the compiled runtime never
loads by the absence of its marker file, and compares stderr to the
helper's own message.

---------

Co-authored-by: 2SinceJuly <202121119+2SinceJuly@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-11-10 13:53:58 -05:00
吴佳浩Albenandmorluto 25885b05c0 feat(v8): inspect V8 code cache containers and retained byte patterns (#8993)
* feat(v8): inspect V8 code cache containers and their retained byte patterns

Bytenode-compiled `.jsc` files — the V8 code cache container that `vm.Script`,
`vm.compileFunction` and bytenode 2.x write, and that Node single-executable applications
and Electron apps ship — had no format-native reader. `inspect_binary_layout` shows the
surrounding ELF/PE and `inspect_artifact` inventories the file, but neither decodes the V8
structures, so an agent could not tell which V8 line produced the file, could not learn the
container is metadata rather than source, and had nothing to point at a version-pinned
decompiler. Issue #8543.

`inspect_v8_code_cache` joins the format-native family with `inspect_python_pyc`,
`inspect_erlang_beam` and `inspect_kernel_module`: one explicit local file, bounded parsing,
no execution, no installation, no child process.

**The container is version-dependent, so the reader reports roles with confidence instead
of assuming an ABI.** All eight header words are reported with byte offset, observed value,
the role this reader believes the word has, and whether that role is `confirmed`,
`inferred`, or `unconfirmed`. Only three facts gate admission: the header size this reader
pins, the V8 code cache magic high half `0xc0de` (the low half is
`ExternalReferenceTable::kSize` and varies per build, so it is a build fingerprint rather
than a constant), and a declared payload length that reaches exactly the end of the file.

I derived the field semantics from the producer rather than assuming them, and two findings
changed the design:

- **The word V8 calls the source hash holds the source length on the measured producers.**
  A 54-code-unit source stored `54`, and sources with the same code-unit length but
  different content stored the same value, including a source whose UTF-8 length was 154.
  The reader reports it as `source_length` and the docs say that this name is what the
  measurement supports, not a claim about what another build stores there.
- **`vm.compileFunction` sets a high bit in that word.** The reader masks it out and reports
  the producer family as `script` or `compile_function`, so the source length stays correct
  for both producers.

Embedded strings are reported as **byte-pattern observations with absolute byte ranges**,
labelled as such in the field name and in the limitations. A reported sequence is not proof
V8 retained it as a string, and a missing literal is not proof it is absent.

**Fail-closed boundaries, all covered by tests:** an unknown magic is a typed
`unsupported_target` failure because the file is not a V8 code cache; a short header or a
payload-length disagreement is a typed `invalid_request` failure. Neither yields a partial
parse and neither records Evidence.

Non-goals are explicit in the tool description and the docs: the payload is serialized V8
heap data, not source; recovering logic needs a version-pinned View8-style decompiler that
this tool neither provides nor depends on.

Fixtures are generated from the running V8 instead of committing a version-pinned binary, so
the tests exercise the real producer and stay valid across Node upgrades.

- Semantic owner and earliest changed stage: format-native V8 code cache container decoding.
- CLI and MCP/tool-catalog contract: one new `artifact-provider` tool and one new
  `inspect-v8-code-cache` CLI command, registered in `TOOL_CONTRACTS`, the `artifact`
  language family, `TOOL_EFFECTS`, the capability declarations and services, and the
  capability inventory. `docs:check` passes, so the generated catalog agrees.
- Provider, bridge, target-format, or platform compatibility: no provider runs and no
  external tool is required, so the tool is available on every supported Node host.
- Evidence, artifact, provenance, or reconstruction contract: complete Evidence with the
  payload byte range as its location; no artifact format, reader, or reconstruction change.
- Generated metadata, package, or installation impact: catalog and document facts
  regenerated by the existing checks; no new dependency.

Expected effects:

- [x] Target content is returned as bounded structured facts.

- `src/v8/V8CodeCacheParser.test.ts` (13 cases): real-producer header facts, per-field role
  and confidence, source length for both producers, an observation's absolute offset
  verified against the file bytes, the limitation text, foreign magic, payload-length
  mismatch, short header, missing payload bytes, a different build constant still admitted,
  and the observation budget.
- `tests/boundary/mcp/v8CodeCacheMcp.test.ts` (4 cases): advertisement and annotations,
  header facts over MCP, relative-path rejection, unsupported magic, malformed container.
- `tests/acceptance/v8CodeCacheCli.test.ts` (4 cases): the public CLI, relative-path
  resolution, byte-range observations, and the typed failure.

- `npx vitest run src/contracts src/v8 src/application/v8CodeCache src/domain/v8` — 242 passed
- `npx vitest run tests/boundary/mcp/v8CodeCacheMcp.test.ts tests/acceptance/v8CodeCacheCli.test.ts tests/boundary/filesystem/productCatalog.test.ts tests/acceptance/tools/localToolContracts.test.ts` — 20 passed, 4 skipped
- `npx tsc --noEmit -p .` — exit 0
- `npm run build` — exit 0
- `npm run lint` — 0 errors
- `npm run knip` — exit 0
- `npm run docs:check` — exit 0
- `npx oxfmt --check src tests docs` — exit 0

Gap: the header table is measured on node v24.22.1 / V8 13.6.233.17-node.58 only. No other
V8 build is available here, so a different build's field order is untested; that is exactly
why only three facts gate admission and the remaining roles carry a confidence level rather
than being asserted.

Additive. No existing tool, schema, or behaviour changes. The reader never executes the
selected file, never launches a process, and never accesses the network; its audited effects
are `mutatesSession: true` only, matching the other static format readers.

Human owner: @XiaoBinGan

- [x] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
- [x] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
- [x] I declare this PR ready for initial maintainer review.

- [x] This PR addresses a concrete problem or an agreed enhancement.
- [x] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
- [x] The PR has one focused outcome and the title follows `type(scope): outcome`.
- [x] Related issue: #8543.
- [x] Tests cover changed observable behavior and meaningful failure paths.
- [x] Owning docs, contracts, and generated metadata are updated where needed.
- [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

* chore: retrigger title and readiness checks after the title was corrected

* fix(v8): bound the payload scan and use the repository path conventions

Review feedback from @greptile-apps on four points.

**Bound the synchronous payload scan.** The scan is one synchronous pass over the
payload, so the 512 MiB ceiling allowed a single request to hold the process for
several seconds. The ceiling is now 64 MiB, matching the pinned CPython pyc reader,
and the default is 32 MiB. The scan stays synchronous, like the BEAM and ELF note
readers in this family, but the budget that bounds it is no longer large enough to
matter. The new `max_file_bytes` ceiling and default are documented.

**Use the absolute-path schema.** `path` now uses `absoluteLocalPathStringSchema`
instead of `localPathStringSchema`, matching `inspect_erlang_beam`. A relative name
previously passed validation and was resolved against the server's working
directory, so `module.jsc` could select a different file than the caller meant. The
rejection is now at the schema boundary.

**State the extraction step.** The handoff in `docs/v8-code-cache.md` now says a
cache embedded in a single-executable application or an Electron app must be
extracted first, because this reader requires the magic at byte zero and returns
`unsupported_target` for the surrounding ELF/PE executable.

**Load only the owning contract group in tests.** Both tests now import
`V8_CODE_CACHE_TOOL_CONTRACTS` directly instead of resolving the tool through the
full catalog, so a focused test no longer constructs every other tool's schema.

21 cases pass across the parser, MCP boundary and CLI acceptance files; `tsc` 0;
`build` 0; `knip` 0; `docs:check` 0; `oxfmt --check` 0.

* fix(v8): select the tool contract by name in the focused tests

Reverts the catalog-position selection I added for a review suggestion. This
repository has a lint rule (`rea(no-positional-tool-contract)`) that forbids
selecting a tool contract by catalog order, and `toolContract("inspect_v8_code_cache")`
is how every neighbouring focused test selects one. The positional form I tried
introduced two lint errors, so the named form stays.

The review concern was that resolving through the full catalog constructs every
other tool's schema. That cost is real but it is the repository's chosen trade:
catalog ordering must never select an operation or schema, and `toolContract` is
the named accessor that enforces it.

* test(v8): cover the new tool in the absolute-path boundary test

Main added `tests/boundary/mcp/absoluteLocalPathTools.test.ts` after this branch
was opened. It enumerates every tool whose MCP `tools/list` schema must reject a
relative path, and `inspect_v8_code_cache` uses `absoluteLocalPathStringSchema`,
so the tool belongs in that list. Adding it keeps the enumerated field set complete
instead of leaving one absolute-path tool untested.

`tests/boundary/mcp` + v8 + contracts: 256 passing. `tsc` 0; `build` 0; `knip` 0;
`docs:check` 0; `npm run lint` 0 errors.

* perf(v8): read the payload by index instead of allocating per byte

`for (const [index, byte] of payload.entries())` allocates a two-element array for
every byte of the cache payload. On a 1 MiB payload that allocation dominated the
scan.

Measured with a real cache built from this parser, alternated so the two forms run
against the same input:

| payload | entries() | indexed reads |
| --- | --- | --- |
| 1 MiB | 15.5ms | 4.4ms |

That is 3.49x on the scan, and the gap widens on smaller payloads where the
allocation cost is a larger share (7.3x at 64 KiB in a synthetic run of the same
shape). The scan is the whole cost of `inspect_v8_code_cache` once the file is read,
so this is the tool's own hot loop.

Output is unchanged: the parser returns one retained string for the 64 KiB fixture,
and `src/v8` plus the CLI and MCP boundary files stay at 21 passing. `tsc` 0;
`build` 0; `npm run lint` 0 errors.

* fix(v8): admit only decimal tokens on the numeric CLI options

Main added `tests/boundary/cli/cliDecimalArguments.test.ts` after this branch was
opened. It enumerates every numeric CLI option and requires `0x10` and `1e3` to be
rejected, because plain `Number` coercion would read them as 16 and 1000. This
command's three options forwarded the domain fields unchanged, so the test failed on
them:

    inspect-v8-code-cache options.maxFileBytes: Parser.parse accepts 1e3
    inspect-v8-code-cache options.maxStrings: Parser.parse accepts 0x10
    inspect-v8-code-cache options.maxStrings: Parser.parse accepts 1e3
    inspect-v8-code-cache options.minStringBytes: Parser.parse accepts 0x10

`cliDecimalField` publishes the input view that parses the decimal token first and
then lets the domain field own bounds, defaults and help, which is what the other
numeric commands use.

`tests/boundary/cli/cliDecimalArguments.test.ts` now passes. `tsc` 0; `build` 0;
`npm run lint` 0 errors; `knip` 0; `docs:check` 0.

* fix(v8): recognize module caches, and advise from remaining headroom

Two review findings, each measured on Node 24.22.1 before changing anything.

**A module cache was reported as a script.** `vm.SourceTextModule.createCachedData()`
sets bit 30 of the source-length word, which the source-length mask `0x1fffffff` leaves
out, and the producer check only tested the function bit at bit 29:

| producer | source word |
| --- | --- |
| `vm.Script` | `0x00000013` for a 19-unit source |
| `vm.compileFunction` | `0x20000009` for a 9-unit source |
| `vm.SourceTextModule` | `0x40000013` for a 19-unit source |

So a real module cache was labelled `script`, and `vm.Script` rejects that container. The
producer enum gains `module` and the module bit is tested first; the source length is
unchanged because both flags sit outside the mask.

**The budget advice recommended a retry that could not work.** Both limits have
ceilings — `max_strings` at 65536 and `min_string_bytes` at 256 — so an admitted file
with more than 65536 runs of 256 bytes reached the branch while every suggested retry
was a rejected input. `observationBudgetRemediation` now reads the remaining headroom
and only recommends a change that is still admissible, falling back to selecting a
smaller artifact when neither can move. The parser message states the fact and leaves
recovery to the provider, which is the only place that can see both budgets.

`MAX_INSPECT_V8_CODE_CACHE_MIN_STRING_BYTES` names the `min_string_bytes` ceiling that
the schema previously spelled inline, so the advice and the schema cannot drift.

`docs/v8-code-cache.md` describes both flag bits. `src/v8` plus the CLI and MCP boundary
files: 28 passing; 7 new cases fail on the base commit. `tsc` 0; `build` 0;
`npm run lint` 0 errors; `knip` 0; `docs:check` 0.

* refactor(v8): decide the budget recovery as data, and test the decision

The remediation tests matched fragments of the advice sentence and banned old phrases.
`docs/testing.md` asks for error codes, recorded limits and recovery behaviour instead of
frozen prose, so a harmless reword could fail those tests while wrong advice passed them.

`observationBudgetRecovery` now returns the decision — which retries remain within the
schema's admitted range, and whether a smaller artifact is the only option — and
`observationBudgetRemediation` renders one sentence from it. The tests assert the
decision, so the wording is free to change and an incorrect choice cannot pass.

This also fixes a bug in the previous shape: it took the `min_string_bytes` branch to mean
"lower it", but that branch is reachable with the value already at the schema minimum,
where lowering is not a legal retry. The decision now carries `canLowerMinStringBytes`
and a `requiresSmallerArtifact` flag for that case.

5 cases, all failing on the base commit, covering both headroom states, either ceiling
alone, and the run-length floor. `src/v8` plus the CLI and MCP boundary files: 28
passing. `tsc` 0; `build` 0; `npm run lint` 0 errors; `knip` 0; `docs:check` 0.

* ci: rerun after the wakaru release download recovered

The only failing job on this branch was `javascript_recovery / real-javascript-recovery`,
which failed on `curl: (22) The requested URL returned error: 504` while downloading
`wakaru-linux-x64.tar.gz`. The release is reachable again (HTTP 200), so this empty
commit re-triggers the lane.

* docs(v8): place the guide in the tree and record the feature

The guide sat at `docs/v8-code-cache.md`, outside the `docs/guides/` tree every other
guide uses, and neither index linked it, so it could not be reached from
`docs/README.md` or the VitePress sidebar.

Moved to `docs/guides/javascript/`, linked from both indexes, and recorded the feature
under `docs/specs/v8-code-cache-inspection/` with `spec.md`, `plan.md` and `tasks.md`.
The spec keeps only the premises that were measured on Node 24.22.1 — the three producer
words and the retained-string layout — rather than restating the implementation.

`npm run docs:check` 0; `npm run format:check` 0; `tsc` 0; `build` 0; `lint` 0 errors;
`knip` 0. V8 reader, CLI and MCP files: 28 passing.

* docs(v8): use the documented spec path and test the advice against its struct

Two review findings.

**The records were at `docs/specs/v8-code-cache-inspection/`.** `AGENTS.md:73` asks for
`docs/specs/<domain>/<feature-slug>/`, so they move to
`docs/specs/v8/code-cache-inspection/`.

**The verification section claimed more than the tests do.** It said the producer cases
were built from real `vm.Script`, `vm.compileFunction` and `vm.SourceTextModule` output,
and that the budget advice was compared with its owning formatter. In fact only
`vm.Script` and `vm.compileFunction` are real producers — the module case sets the
measured bit on a `vm.Script` cache — and only `observationBudgetRecovery` was asserted.

Corrected the claim, and closed the second gap rather than only describing it:
`observationBudgetRemediation` now has four cases holding the sentence to the struct it
renders from. The sentence must not advise a knob the struct closed, and must mention a
smaller artifact exactly when the struct requires one. Verified by making the sentence
advise `max_strings` after the ceiling was reached — the test fails. Wording stays free;
wrong advice does not.

`npm run docs:check` 0; `npm run format:check` 0; `tsc` 0; `build` 0; `lint` 0 errors;
`knip` 0. V8 reader, CLI, MCP, absolute-path and decimal-argument files: 34 passing.

* fix(v8): restore the absolute-path contract entry after the rebase

The rebase onto `main` conflicted in `tests/boundary/mcp/absoluteLocalPathTools.test.ts`:
`main` gained `inspect_api_contract`, `inspect_devicetree`, `inspect_playwright_trace` and
`inspect_python_pyc` in both the contract list and the path-field map while this branch
added `inspect_v8_code_cache`. Both sides are additive, so both are kept.

Without the resolution the branch carried conflict markers, which made `mergeable_state`
`dirty` and every check on it meaningless. Re-verified after the rebase: `tsc` 0, `build` 0,
`format:check` 0, `lint` 0 errors, `knip` 0, `docs:check` 0, and the V8 reader plus its CLI,
MCP, absolute-path and decimal-argument boundary files at 34 passing.

* test(v8): pin the producer from the runtime's own header word

An independent reviewer ran these files on Node 22.23.4, 24.22.1 and 26.12.1. Only 22.23.4
failed, on `separates the compileFunction producer bit from the source length`, expecting
`compile_function` and reading `script`.

The cause is the fixture, not the parser: `vm.compileFunction(...).cachedData` carries
`0x20000009` in the source-length word on Node 24.22.1, with bit 29 set, while Node 22.23.4
does not set that bit at all. Whether a given V8 build marks the word is a build detail, so
asserting one build's spelling made the check version-dependent.

The case now reads the word the runtime produced and asserts the parser maps it correctly,
and keeps the part that must hold everywhere: the source length is the low bits, so it
equals both `word & 0x1fffffff` and the source's length. The flag meanings themselves stay
pinned by the synthetic `withHeaderWord` cases above, which do not depend on any build.

Reverting the parser's `compile_function` arm fails this case and
`keeps the function and module flags distinct`. `src/v8` plus the CLI, MCP and absolute-path
boundary files: 24 and 34 passing. `tsc` 0; `build` 0; `npm run format:check` 0;
`npm run lint` 0 errors; `knip` 0.

* fix(v8): report an unflagged producer word as unknown, not as a script

`vm.compileFunction` marks bit 29 of the source-length word on Node 24.22.1 (`0x20000004`
for a 4-unit source) and does not mark it on Node 22.23.4 (`0x00000004` for the same call).
Whether a V8 build marks a function cache is therefore a build detail, and an unflagged
word is either a `vm.Script` cache or an unmarked function cache. The container carries
nothing that separates the two.

The reader reported `script` for that case, which is a confident claim the bytes do not
support. My previous commit made the test accept whichever value the runtime produced,
which recorded the ambiguity instead of resolving it in the contract. `unknown` is now a
producer value, the unflagged word maps to it, and the observed word stays in
`header.fields` for a caller that trusts a specific build fingerprint. A limitation line
says the same in the report itself.

`header.producer` widens to `["script", "compile_function", "module", "unknown"]`; `script`
is no longer produced, because no unflagged word can be shown to be one.

The spec's producer rule and its verification notes are updated to match. Reverting the
mapping to `script` fails 2 of the 24 `src/v8` cases. `src/v8` with the CLI, MCP and
absolute-path boundary files: 33 passing. `tsc` 0; `build` 0; `docs:check` 0;
`npm run format:check` 0; `npm run lint` 0 errors. `knip` reports one unused export
(`builtinDataEffectMethod`) on `main` as well, so it is not from this change.

* fix(artifacts): retain completed identity across native parser failures

* docs(v8): preserve unknown unflagged cache provenance

---------

Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-11-09 20:17:25 +08:00
morluto c5ed046d6e fix(ghidra)!: qualify memory effect coverage (#8651)
* fix(ghidra): qualify memory effect coverage

* fix(native): retain value trace source limitations

* fix(native): distinguish value trace policy commitments

* fix(ghidra): bind value-flow scope to snapshot profile

* test(ghidra): verify legacy value-flow snapshot recovery
2026-11-08 15:05:51 +00:00
morluto 1a0e2c77f2 fix(ghidra): qualify selected project call coverage (#8391)
* fix(ghidra): qualify selected project call coverage

* test(ghidra): retain verifier MCP cleanup ownership

* test(ghidra): document trusted verifier compiler selection

* test(ghidra): document owned verifier exit marker

* test(ghidra): remove ineffective scan directives

* fix(ghidra): supervise project coverage verification

* fix(ghidra): supervise verifier compiler process
2026-11-08 08:57:05 +08:00
morlutoandCursor Agent f912a68417 fix(ghidra): respect Java Unix socket path limits (#8382)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-11-08 02:15:05 +08:00
morluto c06b53644b fix(ghidra)!: preserve facts in inventory searches (#8376)
* fix(ghidra)!: preserve facts in inventory searches

BREAKING CHANGE: Ghidra snapshots made before the search projection profile revision no longer match. Run fresh analysis and save a new snapshot.

* test(ghidra): update raw profile digest goldens
2026-11-08 02:04:30 +08:00
a67525cdf1 docs: organize canonical documentation layout and verify new pages (#2791)
* docs: organize canonical documentation layout (URGENTE)

Group all existing authored guides by domain and ownership, expose complete navigation, and preserve their public routes. Update physical path consumers and release configuration while retaining historical records. Document domain-based specs and ADR slugs without global numbering.

Co-Authored-By: Codex <noreply@openai.com>

* fix(docs): honor home layout in all-page route verification

* style: format reviewed source changes

* fix(docs): preserve routes and navigation cache inputs

* fix: repair the static-check failures on the default branch (#2895)

* fix: repair the static-check failures on the default branch

The default branch fails its own required `Static checks` job three ways, so
every pull request reports that job as failed regardless of its own change.

- `npm run format:check` reports `src/domain/functionComparison.test.ts` and
  `src/ida/IdaOperationRunner.ts`.
- `npm run lint` reports a duplicate `import { join } from "node:path"` in
  `tests/boundary/mcp/ghidraInventoryMcp.test.ts` (lines 4 and 17).
- `npm run typecheck` reports `format: "devin"` missing from the client format
  union in `src/application/SupportedClients.ts`, and an unchecked index in
  `tests/boundary/cli/clientProfileLifecycle.test.ts`, whose pair array is
  inferred as `string[][]`.

Apply the pinned formatter, drop the duplicate import, list the `"devin"` format
that its own definition already uses, and mark the pair array `as const`.

Validation: `npm run check:fast` and `npm run format:check` pass.

* fix(setup): keep Devin on the JSON configuration dialect

---------

Co-authored-by: 吴佳浩 <wujiahao@supremind.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>

* fix(docs): update links after guide relocation

* docs: correct verified documentation route counts

* fix(docs): update browser capture guide link after move (#2820)

Refresh gettext protected-link comments alongside the authored href.

Co-authored-by: Codex <noreply@openai.com>

* fix(docs): include http3 lab in stable routes

* fix(docs): preserve historical release evidence and links

* fix(ghidra): restore Windows verifier identity import

* docs(wakaru): preserve pinned upstream policy link

* docs(index): retain recently added guide links

* docs(mcp): preserve parent retention clarification

* fix(cli): preserve standalone import guidance

* fix(test): preserve translated guide link drift coverage

---------

Co-authored-by: Matheus Breguêz <matbrgz@gmail.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: morluto <17176810+morluto@users.noreply.github.com>
Co-authored-by: 吴佳浩Alben <35291372+XiaoBinGan@users.noreply.github.com>
Co-authored-by: 吴佳浩 <wujiahao@supremind.com>
2026-11-08 01:42:28 +08:00
morlutoandCursor Agent 4bb53000a3 fix(ghidra): clarify function annotation selectors (#8584)
* fix(ghidra): clarify function annotation selectors

* test(ghidra): compare catalog guidance with its contract

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-11-08 01:10:17 +08:00
3e8a5f76d0 feat(native): retain LLDB source coordinates and verify Pascal calls (#2800)
* feat(native): retain LLDB source coordinates and verify Pascal call entries

Preserve partial line-table attribution for native locations and historical
evidence compatibility. Verify owned Free Pascal call entries through CLI/MCP.

Refs #2382, #2372, #2397

Co-Authored-By: Codex <noreply@openai.com>

* docs: namespace native specifications by domain and feature

Use stable descriptive paths instead of numeric prefixes to avoid parallel contribution collisions.

Co-Authored-By: Codex <noreply@openai.com>

* fix(native): bound Pascal verification and compare caller coordinates

Address review findings at their producing boundaries and preserve directly affected consumers. Source inspection and git diff --check completed. Tests and automated checks were not run at the user’s explicit request.

* fix(native): bound compiler shutdown and source-coordinate fixtures

* docs: clarify historical native source verification

* fix(native): preserve source attribution and compiler ownership

* docs(native): qualify retained source attribution

* fix(ci): clean up native Pascal verifier processes

* test(native): type the Pascal verifier helper import after merging main

Main now typechecks this boundary test, which imports the untyped
canonical-temporary-directory helper and reads an unknown catch value.
Add the helper's declaration file and narrow the caught error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(native): verify partial source attribution caveat

* fix(native): retain verifier compiler cleanup ownership

* fix(native): forward verifier cancellation and measure path bytes

CLI and MCP artifact runs observe the verifier abort signal, and a
failed Pascal verifier test stops the compiler group before deleting
its directory. Repeated source locations grow by measured UTF-8 JSON
bytes; workflow tokens, CPU and peak memory stay unmeasured.

---------

Co-authored-by: Matheus Breguêz <matbrgz@gmail.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-11-07 23:25:20 +08:00
Hasan ZayniandClaude Sonnet 5.5 1cc979c104 feat(ghidra): admit DOS MZ targets on Windows P0 (#7144)
* feat(ghidra): admit DOS MZ targets on Windows P0

Windows Ghidra P0 refused dos-mz although the MzLoader import, 16-bit
real-mode language attestation and load-image evidence are host-neutral.
Admit dos-mz in inspectWindowsP0TargetSupport and run verify:ghidra:dos on
Windows: inherit the system environment there, expect annotation and naming
edits to be refused (P0 has no mutation authority), and skip verifier
lineage like the 6502 lane. Explicit COM stays refused on Windows; its
verifier is built around annotation edits.

Refs #7121

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(ghidra): check naming refusal in the read-only DOS lane

With mutable: false the address-boundary helper skipped every naming
request, so the Windows report overstated its coverage. Assert that
set_address_name and set_addresses_names are refused with
capability_unavailable and leave the entry name unchanged, and declare
the optional mutable argument in the .d.mts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(ghidra): unwrap failed profile Result before asserting

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(ghidra): expect an unchanged DOS entry on Windows P0 verification

Windows P0 refuses edits, so verifyGhidraAddressBoundaries skips the
rename-and-restore and the entry keeps its imported symbol source. The
post-check still expected user_defined, which only follows a rename.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 15:39:03 +08:00
gensokyo-dev 0beedcd712 perf(mcp): add opt-in hot/cold tool discovery (#9046)
Add per-connection discovery that loads canonical named tools on demand while preserving the default full catalog. Bound discovery replies before changing visibility, preserve family exclusions and Evidence workflows, and reset visibility on HTTP reconnect.

Verified with focused protocol tests and real Codex CLI artifact investigations; token costs remain task-dependent, so the profile is opt-in.
2026-11-05 20:27:31 +00:00