mirror of
https://github.com/morluto/rea.git
synced 2026-11-05 22:36:08 +00:00
8a6ddec83ae5a5a538d1ffcff5d00173fa116611
142
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
8a6ddec83a |
fix(mcp): name the close_binary retry for retained cleanup (#8329)
* fix(mcp): name the close_binary retry for retained cleanup A close_binary that retired its target but could not confirm cleanup returned cleanup_incomplete with retryable: false and only the generic "Review the reported local resources" remediation, although the session keeps every failed owner and the next close_binary on the same connection retries them. Agents could abandon the connection that owns the only retry. The MCP close tool now passes its retry operation to the session. The session binds that typed AnalysisCleanupRetry to a failed retirement only while it retains the cleanup for its next close; the close tool binds it to process-capture failures its own scope retains and to compositions whose session part was offered. Projection then reports recovery.kind=retry_cleanup and appends a conditional instruction: keep the connection, let the condition settle or resolve it, call close_binary without snapshot_path and check the result. The hint disappears once that cleanup resolves. retryable keeps describing the failed operation. One-shot CLI closes, open_binary, analysis tools and failed snapshot saves (which keep the target open) offer no retry. Cleanup composition copies the owner's remediation without a retry offer, so the text appears once. Fixes #8211 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: derive close retry guidance from its owning formatters The new close_binary retry assertions froze ProviderCleanupError's explanatory sentence, so a harmless wording edit would break them. The MCP test now compares delivered remediation with analysisErrorRemediationAction applied to the delivered typed error plus cleanupRetryRemediation. The domain tests use the same formatters, check that unbound and released errors carry no retry text, and check that a bound composition adds the offer once. Recovery fields, cleanup state and retry behavior keep separate assertions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
60149282fc |
test: strengthen integration oracles and verification (#8295)
* test: strengthen integration oracles and verification * test: bound lifecycle gates and strengthen workflow checks * test: verify complete paged and extracted results * test: preserve bytecode and cancellation evidence * test: strengthen retained evidence and fixture cleanup * test: require cross-projection bridge identities * test: retain fixture owners through cleanup failures * test: verify graph examples and project selectors * test: tighten provider and lifecycle regressions * test: consolidate hex coverage and bound cutter cleanup * test: bound subprocess output waits and strengthen graph checks * test: check mcp recovery and preserve cleanup owners * test: verify structured mcp argument failures * test: preserve artifact cleanup and gdb limit evidence * test: preserve evidence identities and bound provider gates * test: retain browser and comparison cleanup owners * test: bound startup and strengthen fixture oracles * test: bound lifecycle gates and verify recovered evidence * test: verify public outcomes and lifecycle ownership * test: assert precise evidence and release lifecycle gates * test: verify selected facts and bound cleanup waits * test: check retained evidence and decoded records * test: verify final reports and retain cleanup ownership * test: bound reviewed startup gates and retain cleanup * test: verify PE errors and preserve MCP cleanup * test: preserve MCP fixture cleanup ownership * test: release provider gates before late startup |
||
|
|
b43c329df7 |
feat(artifacts): inventory and extract UF2 and DfuSe firmware containers (#8230)
* feat(artifacts): inventory and extract UF2 and DfuSe regions open_binary refused UF2 and DfuSe firmware containers as an unsupported format, so inspect_artifact and extract_artifact could not show which bytes a drag-and-drop or DFU update writes at which addresses. UF2 is recognized by a complete first block with all three magic numbers. Valid main-flash payloads are joined into address-contiguous regions per familyID, named family-0x<id>/0x<start>-0x<end>.bin, and known IDs are named from a small table copied from Microsoft's uf2families.json at a pinned commit. Numbering is counted per familyID and block count: absent, repeated, out-of-order and out-of-range block numbers are reported, and absent blocks leave coverage unknown. Not-main-flash blocks are excluded and reported; file-container blocks are reported and leave coverage unknown; invalid blocks and a partial final block are excluded with their position. A rewrite of one address with different bytes fails closed, naming both block spans. DfuSe is recognized only by its prefix together with a DFU 1.1a suffix. Each element becomes one region at its file range with its target's alternate setting and name. Structural faults fail closed with a byte offset; overlapping elements stay separate and are reported. A suffix CRC mismatch follows integrity_policy: fail refuses with a dfu-crc32 integrity error, and record-and-continue records a root contradiction that extraction also carries. HEX, UF2 and DfuSe share one retained-region reader and one run merger, so the HEX decoder and reader lose their private copies. * docs(artifacts): document UF2 and DfuSe images and their esptool lane Describe recognition, region names, metadata, numbering, failures, the DfuSe suffix CRC under integrity_policy, and limits, and link the page from the CLI and firmware guides and the agent skill reference. npm run verify:uf2 runs esptool merge-bin --format uf2 on generated inputs at known addresses, with and without MD5, with 256-byte payloads, and on a concatenation of two chips' outputs. Inspection and extraction through the built CLI must return every input at its address under the familyID esptool itself reports. * fix(artifacts): accept both DfuSe image size conventions UM0391 calls DFUImageSize the file length, and dfu-util's dfuse-pack.py writes that value, while ST's DfuFileMgr, MicroPython's dfu.py and pydfu leave the 16-byte suffix out. The decoder accepted only the second form, so it refused dfuse-pack.py output as malformed. Accept either value and keep the declared one in image_size; any other value still fails with the suffix offset and the file length. The tests pin both producers' output for one image, CRC included, from their build() functions transcribed and run under Python 3. * fix(artifacts): keep reused UF2 block numbers from hiding missing blocks esptool numbers every merged input from 0, so two inputs with the same block count share one numbering group. A block lost from one input left its number present in the other, and the file reported complete coverage. Each block number now records the target addresses it was seen at: equal address counts are complete copies, a resend to the same address is one block, and unequal counts make coverage unknown with a limitation and ambiguous_numbering_group_count. sequence_count becomes numbering_group_count, and region block positions become first_file_block and last_file_block. Review follow-ups in the same change: - compare_artifacts compares a DfuSe element's alternate setting and target name, so bytes moved to another device memory are changed; - the shared reader keeps no region bytes outside its map after close; - one domain type replaces four identical decoder failure types; - the UF2 decoder returns a typed limit instead of throwing on bytes beyond its admitted size, and caps retained regions, not runs; - DfuSe caps elements with bytes only, names empty elements and element-less targets, drops the constant bVersion and bcdDFU fields, and says whether the CRC matches when DFUImageSize fits neither convention; - classification evidence carries a suffix only when the probe saw the end, and root classification reads the tail only for a DfuSe prefix; - the UF2 domain region owns family_name, and the root records the family registry revision; the table's MIT notice is preserved; - docs pin the producer revisions (dfu-util ee6b393d and f9a537c9, MicroPython cb99ca98), give the MD5 structure's real meaning, and describe container contradictions in the MCP contract guide; - tests and the esptool lane add the equal-count inputs and a block lost from one of them, accepted boundaries beside each refusal, a DfuSe root larger than the classification prefix, and CLI refusals. * feat(artifacts): name the UF2 families that LibreTiny builds for LibreTiny writes UF2 for Realtek, Beken and Bouffalo Lab modules. The Microsoft registry revision REA already cites (cf3bd7f9) lists eight of those families: RTL8710A, RTL8710B, RTL8720C, RTL8720D, BK7231U, BK7231N, BK7251 and BL602. Their regions now carry those names. LN882H, which that revision omits, keeps its familyID with no name. * fix(artifacts): count DfuSe declarations without bytes instead of listing them Empty DfuSe elements have no entry, so DFUSE_MAX_ELEMENTS does not cap them, and the target walk kept a description string for each one. At 8 bytes per element, a file under the 128 MiB ceiling can declare about 16.7 million of them. The walk now counts every declaration without bytes and builds only the first NAMED_ELEMENTS descriptions, which is all that the limitation shows. The limitation text and empty_element_count do not change. The guide now says that both DfuSe limitations name the first four. On this host, decoding 4,000,000 empty elements (a 32 MB file) ran out of memory under a 128 MB V8 heap before this change, and it peaked at 1.59 GB RSS with the default heap. It now decodes in 114 ms with a 220 MB peak. --------- Co-authored-by: morluto <76467478+morluto@users.noreply.github.com> |
||
|
|
22e5aa97af |
feat(artifacts): inspect classic iNES container regions (#2816)
* feat(artifacts): inspect classic iNES container regions
* fix(artifacts): preserve iNES source disappearance as integrity failure
* fix(artifacts): revalidate iNES source before parsing header
* fix(artifacts): validate admitted roots before classification
* fix(artifacts): normalize source loss during root hashing
* fix(artifacts): bind iNES extraction admission to inventory
* test(artifacts): clarify non-executing inspection wording
* fix: preserve binary plist detection with extended magic probe
* test(browser): wait for popup document loads before capture
* fix(artifacts): honor cancellation across source validation
* fix(artifacts): prefer artifact magic over implicit database suffix
* fix(artifacts): select extraction readers from scanned format
* fix(artifacts): complete prefix reads and share ZIP format admission
* fix(browser): budget scenario cleanup for content drain and shutdown
* test(artifacts): admit valid universal inputs before routing
* test(artifacts): verify iNES workflows on macOS
* test(ci): own iNES macOS coverage and portable fixture paths
* fix: preserve cleanup retries and avoid duplicate inventory parsing
* fix(contracts): share ZIP target formats across MCP lifecycle schemas
* fix(target): preserve typed cancellation during descriptor admission
* refactor(artifacts): use JSON-safe inventory producer output directly
* test(artifacts): share file read setup and satisfy CI checks
* fix(artifacts): classify changed admission as integrity failure
* ci: run Mach-O summary delivery coverage on macOS
* test(javascript): align parameter provenance with main contract
* test(browser): await discoverable fixture pages before runtime verification
* fix(artifacts): pass target metadata to format detection
* fix(artifacts): bind extraction to opened target
* 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>
(cherry picked from commit
|
||
|
|
e6d0618979 |
feat(artifacts): inventory and extract ESP flash layouts (#8228)
* feat(artifacts): inventory and extract ESP32 firmware images ESP32-family app and bootloader images (magic 0xE9) had no reader, so open_binary refused OTA downloads, app partitions and bootloaders. Add the esp-image container format behind inspect_artifact and extract_artifact. A pure decoder reads each byte once and keeps only fixed-size fields. Derived facts cover the chip, from a table cited to ESP-IDF v6.1; segment classification as ESP-IDF's should_map and should_load; checksum and appended SHA-256 results; app and bootloader descriptors; Secure Boot v2 signature blocks, observed and unverified; and undescribed trailing byte ranges. Truncation and undescribed bytes make coverage unknown. ESP8266 images are refused with a specific reason, and ciphertext stays unrecognized. Add the format to every target, Evidence, snapshot, live-summary and artifact vocabulary, document it, and add an optional verify:esp-images lane that compares esptool-built images with esptool image-info and espsecure signature-info-v2. Refs #3615 * test(artifacts): run the ESP image lane on esptool v5.6.0 The lane compared descriptor fields only when esptool image-info printed one, so a descriptor that REA reports and esptool does not print passed without comparison. Compare the descriptor kind in both directions. Record that the lane passed for all 13 images with esptool and espsecure v5.6.0, the version the layout facts cite, as well as with 4.12.0. * refactor(artifacts): define ESP image layout sizes once The decoder and the derived facts each defined the segment-header, appended-digest and flash-sector sizes, the erased-byte scan and the offset formatter. Define them once with the other fixed-layout structures and import them in both places. The signature slot count is the one constant that drives the slot scan. Correct the observedEnd comment: it is the end of the last chunk read. * fix(artifacts): report ESP-IDF's segment length limit by chip ESP-IDF's verify_segment_header rejects a segment of 16 MiB or more unless the chip maps flash through 32-bit cache addresses (SOC_SPI_MEM_SUPPORT_CACHE_32BIT_ADDR_MAP: ESP32-S3, P4, C5, C61, H4 and S31 in v6.1). Record that capability in the chip table and add a limitation for such segments; unknown chips get none. `loaded` repeats should_load. It does not mean the bootloader accepts the segment: verify_load_addresses still rejects one outside the chip's RAM, which REA does not model. Say so in the docs, the skill reference and the inventory limitation. * test(artifacts): check ESP lane tools first and verify extraction The lane started work before checking its tools, so a missing RISC-V target, ld.lld, esptool or espsecure surfaced as a raw spawn or command error. Check each one before building and name the variable to set. Warn when esptool is not v5.6.0, the release the layout facts cite. Assert each segment's class for the ESP32-C3 app, its variants and the bootloader, as the Xtensa image already did. Extract the app and the signed image through the CLI and compare every file with the bytes at esptool's segment offsets or in the appended signature sector; the source's SHA-256 must be unchanged and equal the reported root_sha256. * docs(artifacts): state what the ESP image lane does not establish The Verification section listed the lane's checks but not its gaps: only ESP32-C3 and ESP32 images come from a real producer, no real project build, OTA download or flash dump is inspected, no signature is verified, and the lane does not run in CI. Record the timing of the final lane run on esptool v5.6.0. * fix(artifacts): compare ESP segment declarations Segment entries hash only their data, so compare_artifacts reported a segment that moved to another load address with the same bytes as unchanged; only the image itself changed. Compare each segment's load_addr and data_len as its declaration, as Node SEA and PyInstaller members are compared, and count a changed declaration as a metadata change, also when content is unavailable. Header offsets are layout and the classification is derived, so neither is compared. * test(artifacts): run ESP lane commands as owned process trees The lane ran its tools through execFile. A timeout killed only the direct child, so a linker or assembler that Clang or GCC had started could keep running while the lane removed its workspace. Run every command through createVerifierCommands, check the tools inside withVerifierCleanup, and remove the workspace only after commands.close() has stopped every tree; a failed close keeps the workspace. Only a nonzero exit now counts as a refusal or an expected esptool failure; timeouts and spawn failures propagate. Supervising each command roughly doubles the lane's run time. * test(artifacts): cancel ESP decoding after its first decoded chunk The cancellation test requested cancel or close on setImmediate, which can land while the file is still being opened and checked, so it never showed that decoding had started. It also passed against a reader that ignored both requests while decoding. Acknowledge the decoder's first chunk, then cancel or close, join the operation, and assert that no later chunk reaches the decoder and that the reader ends closed. * docs(artifacts): record which ESP metadata comparison ignores Segments are compared by their declaration. The image's and the signature blocks' format_metadata are not: every field comes from their own bytes, which content comparison already covers, and a block's image_digest_matches follows the image's content. * feat(artifacts): inventory and extract ESP flash layouts A whole-flash dump of an ESP32-family chip was read as its bootloader image, with the partition table, apps and data left as undescribed bytes, or refused when it began with erased flash. Read it as an esp-flash-image container instead. The partition table is decoded as esp_partition_table_verify accepts it and is found at the caller's partition_table_offset, at the default 0x8000, or by scanning 0x1000-aligned sectors for a table whose MD5 verifies, which the inventory reports as derived. The bootloader is located at its chip's ROM bootloader offset. Each partition is an entry with its declaration in flat format_metadata; the bootloader and app partitions carry ESP image facts from the existing streaming decoder; the otadata records are reported with a selection derived without rollback or anti-rollback, and the running partition stays unknown. One unreadable partition does not hide the others, and extraction writes every partition, nvs_keys included, as ordinary data. Flash layouts are detected before single ESP images. The scan runs only when an ESP image sits at a ROM bootloader offset, and is refused when a bootloader at another chip's offset shows that the dump does not start at flash address 0. open_binary gains flash_offset and partition_table_offset, which require format esp-flash-image and are part of the snapshot target identity; the CLI takes them with --target-format esp-flash-image. Comparison treats a partition's label, type, subtype, range and flags as its declaration. * test(artifacts): verify ESP flash layouts with gen_esp32part, merge-bin and otatool Add the optional verify:esp-flash lane. It builds default and relocated partition tables with ESP-IDF's gen_esp32part.py, assembles dumps with esptool merge-bin, including one written from flash 0x1000, and writes OTA records with otatool through flash_file_tool.py, which replaces parttool's esptool calls with reads and writes of the dump file. It compares REA's bootloader and app facts with esptool image-info, every partition with gen_esp32part.py's decoding of the extracted table, and the OTA records and derived slot with otatool read_otadata after each switch. It also checks extracted bytes and source integrity, the scan and caller table offsets, flash_offset on the 0x1000 dump, a corrupted app beside valid partitions and a truncated dump. ESP32 linker scripts place the conformance bootloader and app in ESP32 address ranges. * fix(artifacts): read ESP flash layouts as the bootloader does Read the partition table as bootloader_utility_load_partition_table does: the last factory, otadata and same-subtype OTA declaration wins, and a limitation names repeats. Plan each otadata record within its partition and the dump. An otadata partition smaller than two sectors selects none, the bootloader's INVALID_INDEX; a record the dump lacks leaves the selection unknown while the other record stays reported. The fallbacks follow the bootloader's indexes: ota_0-fallback and factory-fallback name no partition when the table declares none, and the assumptions add GPIO holds and deep-sleep wake. Refuse a dump whose bootloader contradicts its origin before the default table offset is tried, whether flash_offset was omitted or given, and keep the ESP image reader's ESP8266 refusal. A table never lies inside the located bootloader image, so single app images are no longer scanned. An explicit esp-flash-image selection is decided before other container signatures, and the native commands' --target-format no longer takes it. Say when no bootloader confirms the default origin. Exempt the primary bootloader and partition_table entries of ESP-IDF 5.3 from placement limits, report every region inside a longer one, and name partitions by index when labels repeat ignoring case. Keep an undecodable label's bytes in label_hex and compare them. Word undescribed ranges as starting at a byte that is not erased, and treat a short erased region as erased. Add an MCP compare_artifacts test for partition declarations, reader identity and close tests, scan edge cases, the 0x2000 ROM offset and a literal otatool CRC. * test(artifacts): verify ESP primary layout entries and the otadata fallback Build a table with the primary bootloader and partition_table entries that gen_esp32part.py fills from --primary-bootloader-offset, and check that REA reads it with complete coverage, no overlap or misplacement limitation, and a table that agrees with gen_esp32part's decoding. Erase the otadata with otatool after the slot switches and check the records against read_otadata and the factory fallback. * fix(artifacts): keep ESP flash coverage complete for a dump cut short An esptool merge-bin dump ends after the last part it wrote, usually inside its last partition. Such a partition made the layout's coverage unknown, so artifact comparison of two merge-bin dumps reported every unchanged partition as unknown. The partition table names every partition whatever the file's length, so a partition cut short or left out by the end of the file hides no entry. As the ESP image reader does for a cut-short segment, its entry holds the bytes the file has and an entry limitation gives the declared size; a partition with no bytes stays in partitions_outside_dump. Coverage stays complete unless undescribed bytes remain or no bootloader is located. An MCP compare_artifacts test of two dumps that end inside ota_0 now classifies every partition, and fails on the old rule. * fix(artifacts): report written bytes in ESP partitions, erased slots included An app slot is erased for ESP-IDF's bootloader when its image header bytes are erased flash, and REA reported only that status. A slot can still hold data further in: a dump read from a device held a complete older app image 1 MiB into an OTA slot reported as erased, with no limitation. Each partition entry now records where the bytes the dump holds are written, relative to the partition: written_offset, the first byte that is not 0xFF, written_end, just past the last, and written_bytes, how many are not 0xFF. They are null for a partition outside the dump. The status stays erased, which is the bootloader's view, and a limitation names an erased app slot that holds written bytes and says they are not read as an image. The reader reads every partition byte once more to find them. * fix(artifacts): derive the ESP boot selection for every partition table The boot selection lived inside otadata, so a table without an otadata partition, the common factory-only layout, had none. ESP-IDF's bootloader_utility_get_selected_boot_partition returns the factory index when the table declares no otadata partition. Move it to a top-level boot_selection that every layout has. Its basis names the bootloader's branch: otadata, factory-fallback and ota_0-fallback from the records, no-otadata for a table without otadata, none for the bootloader's INVALID_INDEX, and unknown when the dump lacks a record the bootloader reads, which replaces the null selection. running_partition moves with it, and otadata keeps its partition index and records. The assumptions name what each branch leaves out: no records assumption without otadata, and none for none or unknown. The real-tool lane checks no-otadata on a table gen_esp32part built without otadata. * fix(artifacts): say when an ESP image is a flash dump read from 0x1000 An ESP32 dump read from flash 0x1000, as read-flash 0x1000 or merge-bin --target-offset 0x1000 writes it, opened automatically as its bootloader image with a megabyte of undescribed bytes and no next probe. The flash reader refuses that origin, but nothing told an agent which flash_offset to pass. espFlashDumpOrigin owns the inference: an image of a chip whose ROM loads the bootloader from flash R, at file offset F, is the bootloader of a dump read from R - F when a partition table sits where that origin puts 0x8000. The ESP image reader asks it for a non-app image at file offset 0, so the result does not depend on how the reader was created, and records flash_dump {flash_offset, table_file_offset}, null otherwise, with a limitation that says to reopen the file as esp-flash-image with that flash_offset. inspect_artifact proposes the same open_binary call as a next probe, and the flash reader's misplaced-origin refusal names the offset. * perf(artifacts): summarize nested ESP images in the flash layout summary view The summary view returned an ESP flash layout's root facts whole, so each app partition and the bootloader carried every segment and signature block, about half of a dump's summary. The summary view now gives each nested image a summary instead of its facts: status, chip, entry point, segment count, load ranges (each mapped, loaded or unclassified segment's address and declared length), the checksum and appended SHA-256 statuses, coverage and limitations. Complete detail keeps the full facts, every segment included, and the retained Evidence is unchanged. On a 16 MiB device dump the summary's root falls from 5,141 to 2,657 bytes, and the summary Evidence from 10,038 to 7,554. * test(artifacts): expect the misplaced image the ESP bootloader search reports |
||
|
|
54756ff24e |
test: guard target format vocabularies and DOL snapshot saves (#7481)
* test(mcp): save and reopen a GameCube DOL snapshot
#7290 reported that DOL Evidence could not be bundled or saved;
|
||
|
|
845080aef6 |
fix(session): align resource-only status and snapshot recovery (#7896)
* fix(session): align resource-only status and snapshot recovery * fix(session): report independent workflows during resource sessions * test(mcp): honor SQLite runtime availability * test: compare resource snapshot guidance with its formatter Assert projected error codes and the owning remediation action for resource-session snapshot refusals, and type MCP error text as a closed content item. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> |
||
|
|
ec4a0a01c4 |
fix(hopper): reconcile observed caller relationships (#7953)
* fix(hopper): reconcile observed caller relationships * fix(hopper): retain completed caller scans on failure Attach the native reply and collected forward facts when reconciliation fails or is cancelled, and check scan stop codes separately from their wording. Live observations keep REA evidence ids rather than provider supplied ones, and the real Hopper verifier uses advertised MCP schemas. * fix(hopper): answer caller-scan methods in the package fixture The packaged Hopper stand-in echoed unknown bridge methods, so analyze_function rejected rea_caller_scan_target as an invalid scan target and the native package baseline returned unreadable_output. * fix(hopper): share caller identities in failed scan observations Failure partials repeated each caller identity under every destination. The page budget counted compact replies, then schema parsing copied the expanded form. Identities are stored once and destinations cite addresses. * refactor(config): own the Hopper caller-scan budget default The environment schema hard-coded the 2000 ms scan default. The domain limit owner now names that millisecond budget and the schema reuses it. * test(mcp): assert bundle path issues by field compare_bundles reports each relative path as an invalid_format issue instead of one joined diagnostic sentence. * test(flutter): assert ABI selector refusals as structured issues inspect_dart_aot reports the ABI label as an issue on path abi. The message is the selector contract, without an abi: prefix. * fix(session): retain caller observations that cannot be replayed A missing document selector blocks snapshot replay. Backward call-graph and trace reads still keep the native result and forward observations, and the workflow Evidence links those records. * fix(session): keep decompile bodies out of the in-memory ledger Caller and callee walks still stay in Evidence without a document. procedure_pseudo_code does not, so decompile_all leaves each body in the file-backed export instead of retaining the whole export in memory. * fix(hopper): own caller-scan recovery and the page byte allowance Scan facts stay in the domain. Environment recovery, including the time budget bounds and the fixed allowances with no runtime override, is appended from configuration. Setup forwards the budget, and the bridge uses one byte allowance for instructions, native callers, and pages. * fix(hopper): retain compact caller references within the scan budget Recovered call sites stay in the address form the scan already counted. Expanded identity copies are measured before allocation and refused when they exceed the retention budget. Instruction lists are not part of the retained reply. * fix(session): omit instruction payloads from retained caller evidence Documentless caller and callee reads stay in the ledger for the session. Their evidence keeps call sites and drops instruction lists the scan already consumed. * fix(hopper): keep the owning caller address on each compact call site A page reference marked source_procedure "caller" belongs to that page item's caller. Saved sites record that address, and an owner missing from the callee inventory is stored once instead of copied onto every site. * fix(session): leave Hopper reply shaping to the Hopper adapter Documentless caller evidence stores the adapter's raw result unchanged. The session no longer reads native_result.instructions. * test(hopper): throw typed scan failures before reading results Successful caller-scan results now throw the typed error instead of returning after an ok check. Expected failures assert structured tags, stop codes, and reported limits. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> |
||
|
|
3503578f91 |
fix(session): preserve cancellation during mutation retirement (#7959)
* fix(session): preserve cancellation during mutation retirement * fix(session): retain exact cleanup owners through retry --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> |
||
|
|
477f63ae21 |
fix(session)!: classify unavailable snapshot prerequisites (#7837)
fix(session): classify unavailable snapshot prerequisites |
||
|
|
a2e2c29b59 | refactor(analysis): move client cleanup to application | ||
|
|
4e67bc3999 | refactor(analysis): consolidate selection ownership | ||
|
|
5aa23c3d17 | refactor(providers): move inspection scope to application | ||
|
|
8691e48e67 | refactor(evidence): return import counts from ledger owner | ||
|
|
279fc04095 | fix(snapshot): retain publication receipt on cleanup failure | ||
|
|
0e17aab451 | fix(providers): deduplicate nested cleanup notifications | ||
|
|
f878266503 | fix(artifacts): admit selected app bundle traversal | ||
|
|
f347713e24 | refactor(session): share provider replay attribution | ||
|
|
0ddde829b2 | fix(session): preserve failed target restoration | ||
|
|
5b8e415483 | refactor(snapshot): centralize resource cache eligibility | ||
|
|
2ad599dace | fix(snapshot): export only target-bound observations | ||
|
|
eb24da4481 | fix(session): retain unknown cleanup across mixed failures | ||
|
|
11b025ef97 | fix(session): retain cleanup ownership during failed opens | ||
|
|
6a9911ea77 | fix(session): track retained bundle cleanup dependencies | ||
|
|
087acf26e8 | fix(evidence): own cached snapshot data | ||
|
|
2dd2ffcd45 | fix(artifacts): bind operations to admitted sources | ||
|
|
ace4dbf36e |
fix(contracts): align live target classification with admitted facts
Share exact live target variants across open and session responses, preserving historical Evidence and snapshot admission. Consolidate equivalent ELF metadata aliases at their owner. |
||
|
|
b529bd84d7 |
refactor(contracts): preserve named output schema types
Keep exact readonly schema maps and constrain contract factories to their owned keys. Verify named catalog lookups retain each schema type. |
||
|
|
c27560e434 | fix(artifacts): classify selected package names | ||
|
|
779d548c4e | fix(artifacts): preserve selected ASAR companion paths | ||
|
|
5508b2affd |
fix(analysis): retain source evidence through directory exports (#7250)
Retain authenticated provider source records independently of snapshot replay eligibility and return them explicitly to plain application callers, including late cancellation. CLI/MCP commit source records before delivering links; function dossiers share the canonical Evidence constructor. Keep directory replies compact and preserve successful retry verification. Real Ghidra CLI/MCP investigations verify 652-function ls, historical report provenance, cross-session resume, unchanged source/project content and complete offline Evidence. Final full 14,338-function libcrypto comparison matches all metadata/pseudocode facts and independent fresh-import observations: 14,194 written, 143 external, one recorded deadline; 494.03 s, 445.63 CPU s, 1.584 GiB sampled family peak under 2-CPU/8-GiB guards, with no OOM or cleanup failure. 144 focused tests and static/docs/site checks pass; latest-main integration passes 289 cases plus typecheck/lint and actual CLI snapshot source retrieval. Final CI source/static/build/docs/quality/package checks pass. Four ADB shard failures also occur in main CI 40349559391; cancelled coverage remains unverified and author declarations stay unchecked under the user's explicit bypass authorization. No human-review attestation is made. |
||
|
|
4da7e46e9c |
fix(provider-selection): name whether a rejection came from availability or target support (#7220)
Distinguish local provider readiness failures from target-support refusals in shared CLI/MCP diagnostics, preserving original codes and evidence. Avoid claiming configured providers are unconfigured. 120 focused tests, static/docs checks and real ELF CLI/MCP verification pass. Hosted CI has the same four ADB failures as exact main d9908fd7a; three canceled shards remain unverified. Merge uses the user's explicit authorization to bypass proven main failures. Fresh Codex and Greptile reviews are clear. Fixes #7214 Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com> |
||
|
|
0211a07ec5 |
fix(session): report a missing Linux ps as provider unavailability in status (#7180)
Keep binary_session available when Linux owned-child probes lack procps ps. Preserve typed ownership-prerequisite failures in direct execution and report per-provider readiness in status. Independently validated on latest main through real stdio MCP plus focused regression, static and documentation checks. Closes #7164. |
||
|
|
b675073b73 |
feat(mcp): scope advertised tools by family (#7228)
Scope MCP discovery, setup, doctor, status and recovery guidance by selected tool families using one contract inventory and shared catalog identity. Preserve default discovery, canonical validation and complete Evidence. Fixes #3246. Builds on #3026. Real libcrypto workflow verifies all 5,367 exports and identical complete Evidence. Static/source/build/docs/Windows/package/Greptile checks pass; ten assertions reproduced identically on clean main and feature across Node 24/22, with cancelled coverage explicitly unverified. Merge uses the user-authorized bypass for baseline failures and unchecked human-readiness declarations, without attesting human review. Co-authored-by: 0xLLVEL <fakhrezan1@gmail.com> Co-authored-by: Codebuff <noreply@codebuff.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
0c147a4a70 | fix(snapshot): preserve authenticated replay provenance | ||
|
|
5a22ae6bc8 |
fix(mcp)!: return a compact binary_session status by default (#7127)
* fix(mcp)!: return a compact binary_session status by default
binary_session {} with no target open returned about 66 KB, most of it
provider rejection diagnostics and candidate capability sets that the
skill's recovery flow re-reads on every retry. 6.8.0 grew it by 21%
because the shared regex capability limitation began repeating setting
bounds and step-by-step recovery for every search operation of every
provider (#6099, #6267, #6301, #7049) and IDA gained that limitation for
its two search operations (#4862).
The regex limitation now states the effective deadline and heap, their
sources and where to change them; the deadline and heap errors keep the
full recovery. binary_session gains detail: summary (default) or
complete. The summary keeps open state, target identity, the binding,
route capabilities, run, activity and health status, each candidate's
availability and target-support status, code and reason, and every
tool's availability, reason, remediation and modes, and lists the
fields it leaves out in omitted_fields. Complete detail returns the
previous shape. The CLI capabilities and providers commands keep
complete provider facts through the same application projection.
BREAKING CHANGE: binary_session {} no longer returns
analysis_provider_candidates[].availability.diagnostics,
target_support.diagnostics or capabilities, or tool_availability group
surface, effects and annotations. Pass {"detail": "complete"} to get
them.
Fixes #7109
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(mcp): key binary_session output fields by detail
The output schema accepted detail: "complete" with summary candidates or
tool groups, and a summary without omitted_fields, so detail did not
tell callers which fields existed. Each session kind is now crossed
with a detail-specific shape: a summary requires omitted_fields and
summary-only candidates and tool groups; complete requires diagnostics,
candidate capabilities and static tool flags and forbids omitted_fields.
Both the canonical schema and the SDK-validated advertised schema reject
mismatched shapes.
The verifier helper accepts summary candidates only for a validated MCP
summary; CLI provider output still requires candidate capabilities.
Regex limitation tests check values, sources and setting names instead
of whole sentences.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
69a2faa120 |
feat: add FreeBuff agent support for REA setup (#2736)
* feat: add FreeBuff agent support for REA setup Register FreeBuff as a supported setup client using the shared user agents directory (~/.agents/mcp.json with mcpServers, skills in ~/.agents/skills), which matches what FreeBuff Desktop loads. Adds the client definition, boundary tests, supported-agent docs, and the skill reference client list. * fix(freebuff): detect FreeBuff from its profile directory, not shared .agents The ~/.agents marker made FreeBuff appear installed for any home where REA had installed shared skills (the default skill destination, also Gemini CLI's), producing false doctor failures. Detect FreeBuff from its own fixed profile directory ~/.config/freebuff-desktop instead, and add a regression test covering a home with only the shared agents skill directory. * fix(setup): require product evidence for FreeBuff discovery 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(uninstall): retain unverified shared client configuration * fix(clients): preserve scoped removal evidence * fix(doctor): omit undefined selectedClientIds under exactOptionalPropertyTypes Passing selectedClientIds explicitly as undefined fails typecheck on this branch (TS2379), which blocks the focused test workflow before any test can run. Spread the option only when defined. * fix(update): separate ownership evidence from product applicability rea update's maintenance scope inspected only product applicability evidence, so when a FreeBuff profile was absent but REA already owned a version-pinned row in the shared ~/.agents/mcp.json, the plan omitted freebuff and left the integration stale. FreeBuff now declares its registration storage as shared, which proves ownership of an owned row but never product applicability, and maintenance requests ownership evidence through that declaration instead of reinterpreting the shared paths. Doctor and setup keep readiness evidence, foreign rows stay out of maintenance, and the Doctor exactOptionalPropertyTypes fix makes the focused test workflow runnable. * test(dotnet): split oversized operand extent diagnostics describe The describe callback reached 162 lines (max 150), failing max-lines-per-function and blocking the pre-push check for this branch. Move the single-case extent scenarios into their own describe; no test content or order changes. * fix(update): preserve ZCode's disabled shared registration during maintenance The shared user agents file doubles as ZCode's fallback, where `enable: false` disables the registration. Ownership-based maintenance read that row as a FreeBuff registration, whose format does not recognize the flag, so the row was selected and the emitted setup command rewrote it, dropping the flag and silently re-enabling a registration the user had disabled. registrationActivation now honors `enable: false` for any client whose registration storage is shared, because the activation fact binds every reader of that storage. Maintenance leaves such rows out; doctor reports them as stale, matching ZCode's own treatment. * fix(doctor): let explicit client selection authorize the config read When an ACL or an inaccessible shared parent made every access probe fail, a client selected by name was omitted before the configuration read could return its unreadable-config detail, so doctor reported it as not detected with installation remediation: an unresolved selected path collapsed to absence. An explicit selection now authorizes the read outright and the probes serve automatic discovery only. A selected client with an unreadable config reports invalid with the read failure; one with no config reports missing; automatic discovery still probes before inspecting. * fix(uninstall): share shared-storage checks between ZCode and FreeBuff clients() queued ~/.agents/mcp.json twice: once as zcode_fallback and once as freebuff. ZCode has no discoveryPaths, so its strict read still blocked uninstall on malformed shared text, despite FreeBuff's new retain-and-continue behavior. For a valid owned entry, ZCode removed it first, so FreeBuff reported skipped rather than removed. Make the shared file's checks and removal one shared decision: - Add zcodeDiscoveryPaths to ZCode so it has its own applicability evidence. - Gate zcode_fallback push on applicable, not just zcodeFallbackPath presence. - Report shared storage ownership as one decision for both clients: FreeBuff and ZCode now use clientOwnershipEvidencePaths together, so a recognizable REA-owned row proves ownership once for the shared storage, and both clients report the same result consistently. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(uninstall): merge duplicated host and prove shared ownership from owned rows Uninstall.ts declared systemUninstallHost twice, preventing module load, with the exported copy returning only clients and the second copy missing clientWriteBlocker. Merge into one exported host carrying both blockers. hasOwnershipEvidence used access() existence, so an unrelated malformed ~/.agents/mcp.json established ownership and blocked every removal. Ownership now requires a readable, recognizable REA-owned row via the injected filesystem, so unrelated shared data stays retained. Also cover ZCode discoveryPaths in its path test. * fix(uninstall): keep denied product-local configurations fail-closed Unproven product applicability marked every configuration path of that client unverified, so a denied ZCode profile turned an unreadable product-local config into a retained item: uninstall continued and could report complete with REA still registered. The retain-and-continue exception now applies only to storage REA does not own, classified once by clientSharedRegistrationPaths (shared configuration plus another product's same-scope fallback). Covers the Greptile P1 on Uninstall.ts. Validation: the new test fails on the pre-fix Uninstall and passes after it; freebuff/zcode/updateMaintenance/bom/dsh suites green; clientLifecycle, clientRegistrationStatus and claudeDesktop keep the same 8 host failures as the pre-merge baseline (symlink EPERM, stale-vs-aligned on Windows). * fix(update): retain FreeBuff when ZCode reads the shared fallback Maintenance deduplicated clients on the path each inspection read, so ZCode's fallback view of ~/.agents/mcp.json marked that file "covered" and dropped FreeBuff from the scope. ZCode setup writes ~/.zcode/cli/config.json and deliberately leaves the fallback untouched (docs/client-configuration.md), so the emitted command refreshed only ZCode while the shared row both products load stayed pinned to the old package version. Each setup action rewrites only its own configuration path and no other action rewrites the shared row, so every selected client keeps its own maintenance action; the read-path covered/deduped filter is removed. Covers the Codex P2 on UpdateMaintenance.ts:104. Validation: the new regression fails on |
||
|
|
835904e4ee |
refactor(evidence): carry producer-owned source records
Carry the final artifact inspection's exact nested source Evidence through AnalysisExecution. Derive links in the shared Evidence builder instead of reparsing the result in CLI and MCP adapters. Retain validation for unknown and historical Evidence inputs. Move the shared source recorder into application ownership and migrate its consumers. Record sources before parents; keep source recording failures from publishing summaries. Decline snapshot entries whose source closure the current entry format cannot represent, while retaining investigation Evidence. Validation: actual ASAR regression failed before the change with missing links and passes afterward; exact nested identity, source recorder refusal, final-close cancellation and cleanup failure, historical authentication, snapshot controls and public CLI/MCP workflows. Fresh runtime/catalog build, full static/docs, discovery and duplication checks pass. Installed native providers and platform-specific skipped cases remain unverified. |
||
|
|
9b3a633298 |
fix(evidence): retain caller paths across snapshot replay
Preserve the verbatim direct CLI selection in caller_input_path, separate from canonical subject identity and provider/query parameters. Fresh publication uses the existing immutable metadata import path so provider auto-recording cannot discard request provenance. Replay returns the current selection without rewriting stored Evidence or partitioning the cache by alias. Historical records without the optional field still authenticate. Use the domain semantic projection for ledger agreement, remove the duplicate projection and subject-only replacement names, and preserve request metadata at same-invocation summary delivery. Later retained-view questions do not inherit that context. Existing one-shot parameters.input_path remains for compatibility. Validation: 149 focused tests, 28 public CLI/MCP cases, all canonical advertised schemas through the pinned SDK, and nine documentation tests passed across the affected checks. Build, typecheck/lint, and formatting passed. Two Windows-only replay cases were skipped on macOS. Native macOS and managed fixtures were exercised; no Hopper/Ghidra/IDA runtime was started. |
||
|
|
1ca7d38764 | fix(evidence): link composed workflows to consumed observations (#7028) | ||
|
|
cab78de506 |
feat(ghidra): analyze GameCube/Wii DOL executables through Ghidra (#6240)
* feat(domain): parse and validate GameCube/Wii DOL headers Add a pure parser for the 0x100-byte DOL header (7 text and 11 data slots, BSS, entry point). Used slots must lie after the header and inside the file and the 0x80000000..0x81800000 load window; text slots are 4-byte aligned; sections may not overlap in memory or in the file; the entry point must be inside a text section. BSS may overlap data sections, as .sdata/.sdata2 do in shipped DOLs. Refs #1741 * feat(binary): admit caller-selected GameCube/Wii DOL targets * feat(ghidra): import GameCube/Wii DOL targets through a section-map pre-script * test(ghidra): cover DOL launcher arguments, attestation and raw profile digests * test(ghidra): add the real verify:ghidra:dol lane and DOL docs * fix(ghidra): read only the DOL header and section ranges instead of the whole file * test(ghidra): derive DOL lane addresses from readelf and admit Gekko from the install catalog * fix(ghidra): attest DOL block permissions, space, overlay and load state * fix(ghidra): keep load-image permissions optional for older inspections * fix(contracts): accept DOL targets in binary_session output * fix(ghidra): adapt the DOL lane to the current upstream address schema Validate DOL load-image coordinates with the upstream observed-address schema, drop a duplicate import left by the rebase, and re-pin the raw profile digests to the unmodified upstream resolver. * fix(ghidra): preserve bridge inventory symbol provenance * fix(ghidra): align DOL verification with shared workflow contracts * feat(domain): parse and validate GameCube/Wii DOL headers Add a pure parser for the 0x100-byte DOL header (7 text and 11 data slots, BSS, entry point). Used slots must lie after the header and inside the file and the 0x80000000..0x81800000 load window; text slots are 4-byte aligned; sections may not overlap in memory or in the file; the entry point must be inside a text section. BSS may overlap data sections, as .sdata/.sdata2 do in shipped DOLs. Refs #1741 * feat(binary): admit caller-selected GameCube/Wii DOL targets * feat(ghidra): import GameCube/Wii DOL targets through a section-map pre-script * test(ghidra): cover DOL launcher arguments, attestation and raw profile digests * test(ghidra): add the real verify:ghidra:dol lane and DOL docs * fix(ghidra): read only the DOL header and section ranges instead of the whole file * test(ghidra): derive DOL lane addresses from readelf and admit Gekko from the install catalog * fix(ghidra): attest DOL block permissions, space, overlay and load state * fix(ghidra): keep load-image permissions optional for older inspections * fix(contracts): accept DOL targets in binary_session output * fix(ghidra): adapt the DOL lane to the current upstream address schema Validate DOL load-image coordinates with the upstream observed-address schema, drop a duplicate import left by the rebase, and re-pin the raw profile digests to the unmodified upstream resolver. * docs(ghidra): qualify the DOL memory window * refactor(ghidra): own DOL BSS ranges in the parsed header * docs(ghidra): record real DOL workflows and task costs * docs(ghidra): record final DOL integration verification * fix(mcp): share the native procedure search row contract * docs(ghidra): record public procedure search verification --------- Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com> |
||
|
|
9dfa44f776 | fix(cancellation): retain caller reasons at admission checkpoints | ||
|
|
13fcf58276 |
fix(session): own selected snapshot read cleanup
Route MCP snapshot reads through the session's existing file-resource owner so cleanup remains visible, blocks replacement, and can be retried by close_binary. Keep reads inside the serialized open callback and remove superseded adapter resource plumbing. Validate typed errors, exact descriptor recovery, unchanged source bytes, replay provenance, and same-connection lifecycle ordering. Focused snapshot, target cleanup, and MCP lifecycle checks passed with simulated providers; no live provider was exercised. Fixes #6216 |
||
|
|
7356434202 | merge: consolidate upstream ownership and coverage fixes | ||
|
|
a91412aaf9 |
feat(native): export function pseudocode to resumable directories (#6170)
* feat(decompile): write function pseudocode to a directory and return a manifest Add decompile_all and `rea decompile-all` so a caller can write one provider pseudocode file per function, or a filtered set, and receive only a small manifest. The result stays bounded when the program is larger than a local model's tool-result cap. Resume continues an export for the same target digest, provider, analysis profile, and layout. Matching files are skipped, conflicting files stay unchanged, and one function's failure does not stop the rest. Cancellation leaves files already written. Requesting dwarf layout reports that compilation-unit paths are unavailable. Simulated-provider tests cover the manifest, resume, filters, limits, cancellation, and the failure cap. MCP registration, CLI coverage, schema validity, the product catalog, check:fast, and docs:check passed. Real Ghidra was not exercised. Refs #6090 * fix(decompile): keep unknown export identity unresumable and recover torn journals Resume treated two missing target or profile digests as a match, so an export of one binary could continue into another. Resume now requires both digests, and a decompiler observation without the export's profile, or with a different target, is recorded as profile_changed. A crash during a journal append left a torn final line that made the export unresumable. Text after the last newline is now treated as uncommitted and truncated before the next append, and stale temporary files are removed. An inventory row with an empty address aborted the whole export because its failure record failed the journal schema. Such rows are now excluded and counted in the limitations. A limited resume retried the same recorded failures first and never reached new functions. Functions not yet attempted now run before retries. File path reservations come from every journal line, so an output_io record no longer releases a path. The index is rebuilt from the journal in numeric address order, and journal close and cleanup failures return a Result. The cancellation test now cancels after a file is committed and checks that file survives and is skipped on resume. Redundant snapshot-replay checks are removed, the CLI limit uses the contract constant, and --snapshot no longer claims decompile-all updates it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AoJZDPcrgmMsCqLG4LfiFb * fix(decompile): refuse resume of a missing export and repair journals by byte offset A second review round found that resume against a directory that does not exist silently started a full new export and reported it as resumed. Resume now requires an existing export directory. The torn-line repair measured the committed journal from decoded text, so damaged UTF-8 could move the truncation point past the end of the file. The journal is now read as bytes and cut at the last newline byte, and an intact journal is not truncated, so a concurrent append is kept. A per-function observation for a different target is now recorded as target_changed instead of profile_changed. A failure to remove a partly created output directory is reported instead of hidden. The journal handle is closed on every path again, including an unexpected throw. The path allocator no longer gives up after 1,000 collisions and reuses a taken name. Tests now use createTestTempDirectory, assert journal lines against the journal schema, and cover resume of a missing directory, resume with an unknown analysis profile, and a target-mismatched observation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AoJZDPcrgmMsCqLG4LfiFb * fix(decompile): keep a function's first file name across failed retries Reserving every journal path stopped other addresses from taking a path, but an address looked up only its latest record. After its file went missing and a retry failed without a path, the next resume moved the function to a hash-suffixed name and orphaned the original. Each address now keeps the first path the journal gave it. A matched commit still ran the decompiler but did not count toward limit. The limit now counts every function taken on after skipping verified files. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AoJZDPcrgmMsCqLG4LfiFb * fix(decompile): never follow a journal symlink and check procedure_info identity Torn-line repair truncates the journal, and the journal was opened through any symlink in the export directory, so repair could truncate a file outside it. The journal must now be a regular file and is opened without following symlinks where the platform supports it. Body ranges from procedure_info were written without checking that the observation belonged to this export or described the requested function. An observation with a different provider, profile or target, or another entry point, now leaves the body unavailable with that reason. File, journal and index writes now use FileHandle.writeFile, which writes the whole buffer instead of trusting one write call. The stale temporary sweep is removed: a matching file name does not prove this export created the file. The inverted-range test now uses one address space so it reaches the inversion check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AoJZDPcrgmMsCqLG4LfiFb * fix(decompile): bound returned caveats and keep verified checksums Ghidra names each terminal call's address in its per-function caveats, so decompile_all copied one new caveat per function into the returned Evidence and the answer grew with the program. The returned Evidence now keeps the eight most often observed distinct per-function caveats, grouped by provider and text as they are rendered, plus a count of the rest. Inventory caveats are unchanged, and other workflows are not bounded. Each function keeps the caveats of the observations it used: a written file in its header, now including procedure_info caveats, and a failed attempt in its journal and index record. A procedure_info observation for another target or profile is foreign and contributes none. A failure record for a function that was already written replaced the record holding its checksum, so after a transient read error a resume decompiled that function again. The journal now keeps the last successful write separately from the latest attempt. Resume verifies against that write and records it again once the file verifies. A caller abort that arrives while the export finishes now returns cancellation with the caller's reason instead of a success manifest, as #6143 does for other late finalization. A publish, index or close failure stays the primary error. Also make the missing-journal resume error say what to do, and add boundary tests: one runs decompile-all through the real CLI against a fake Kuna to check flag mapping, the relative output directory, filters and limit; one runs decompile_all through production MCP registration to check that the caveat bound is applied. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AoJZDPcrgmMsCqLG4LfiFb * fix(decompile): keep each function's complete caveats in the index The returned Evidence keeps eight distinct per-function caveats and counts the rest, pointing readers at the export. A written function's file header truncates its caveats after 4,000 characters, and its journal record kept none, so a large function with many terminal calls could lose caveats from both the answer and the export. Every journal record, written or failed, now keeps the complete caveats of the observations its attempt used, and decompile-index.json carries them. The header stays a readable summary and, when truncated, says that the index keeps the complete list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AoJZDPcrgmMsCqLG4LfiFb * fix(decompile): report external functions instead of failing them Ghidra classifies imports as external functions with an empty body and returns null pseudocode for them, as its limitations state. decompile_all recorded each one as an invalid_pseudocode failure ("not text"), so a dynamically linked program reported every import as a decompiler failure: 34 of 116 functions in /usr/bin/xxd. procedure_info owns the external classification. When it classifies a function as external, the export now records status "external", counts it in counts.external, writes no file and requests no pseudocode. The record keeps the body fact as observed. The journal header pins the target, provider and profile, so a resume skips a recorded external function without asking the provider again; a limit below the external count still leaves nothing remaining. A null pseudocode result for a function whose classification is not external is reported as no_pseudocode. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AoJZDPcrgmMsCqLG4LfiFb * fix(decompile): report finalization failures after a cancelled export When the caller's abort stopped the publish loop, decompile_all returned that cancellation before checking the index write and the journal close, which had already run. A failure to finalize the export was hidden, so the caller could not tell the saved index or journal was incomplete. Publish failures stay primary, then index and close failures. A cancellation counts as the caller's only when the caller's signal is aborted, and is then reported after a successful finalization with the caller's own reason. A provider's own cancellation, without a caller abort, stays a publish failure like any other. Tests cover an index failure and a close failure after the caller stops the loop, a stopped loop with a successful finalization keeping the caller's reason, and a provider cancellation staying primary over an index failure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AoJZDPcrgmMsCqLG4LfiFb * fix(decompile): remove a created output directory that cannot be secured createPrivateDirectory ran mkdir and chmod as one step. When mkdir succeeded and chmod failed, it returned an error before #create reached its cleanup, leaving an empty directory behind. A fresh export then refused the existing directory, and a resume refused it for having no journal, so the caller had to remove it by hand. mkdir and chmod are now separate. A mkdir failure created nothing, so nothing is removed. A chmod failure after this call created the directory removes it with a non-recursive rmdir: it is still empty, so a path another process filled or replaced meanwhile is refused rather than deleted, and that refusal is reported. A filesystem boundary test fails chmod for the new root and checks the directory is gone and a retry succeeds. A module test confirms that a function written earlier and now classified as external still reports a changed file at its path as output_exists. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AoJZDPcrgmMsCqLG4LfiFb * refactor(process): share the socket lease with owners other than Hopper The socket lease that keeps two REA processes from opening the same Hopper document lived only in HopperLease, with Hopper error messages built in. A decompile export needs the same guarantee for its output directory. OwnedLease now holds the lease mechanism unchanged: a listening local socket that the operating system ends with its process, owner identity answered by the live holder, and recovery of a stale socket serialized through a recovery directory. Callers map a tagged LeaseFailure to their own error. HopperLease keeps its exports and maps each failure to the same HopperStartError message as before. On Windows the lease is a named pipe, which needs no stale recovery. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AoJZDPcrgmMsCqLG4LfiFb * fix(decompile): hold the output directory per run and stop on repeated write failures Two runs could resume the same output directory at once. Each read the journal once, and the index each wrote reflected only its own view, so the last writer could drop the other run's records. A run's torn-line repair could also truncate the other run's append. DecompileExport now holds a lease on the output directory, named by its device and inode, from before the journal is read (or, for a new export, from just after the directory is created and before its journal exists) until the journal is closed. A second run is refused as a retryable capacity constraint that reports the holder's process ID. The lease ends with its process, so a crashed run leaves no lock to clear. The lease is released on every open failure, and a failed release is reported. An export also kept decompiling every remaining function when its files had stopped being writable mid-run, for example on a full disk, failing each one with output_io. After five consecutive functions whose files could not be written or read, the export now stops with an output error that carries the counts and the last failures. A verified file or any other outcome ends a run of failures. Committed files and records stay, the index is still written, and a later resume continues. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AoJZDPcrgmMsCqLG4LfiFb * docs(native): record directory export verification Record matched real Ghidra outputs, bounded caveat and cleanup regressions, actual catalog-inclusive context estimates, runtime measurements and coverage limits for the pinned integration. * fix(native): bound export summaries and reserve portable paths Use one case-folded reservation owner for allocation and resumed journals. Budget inline failures and provider caveats by encoded JSON bytes while retaining complete records in the output index. Align the tool contract with the collector order and verify SDK result-window behavior. * docs(native): refresh final export measurements --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com> |
||
|
|
6f8dc9c139 | fix(session): preserve binding commitments during restoration | ||
|
|
9becdfe8f4 | fix(session): retain cleanup blockers and snapshot request identity | ||
|
|
2732d538e8 | fix(session): own target admission descriptors through finalization | ||
|
|
b3c912ab79 | fix(filesystem): retain read cleanup capabilities across retries | ||
|
|
8aa40e9a61 | fix(cache): scope Evidence display refresh to matching snapshot bindings |