mirror of
https://github.com/morluto/rea.git
synced 2026-11-03 05:16:16 +00:00
cbc69537cdf54dca6cc1cfada4ed8a5f1d9633df
2097
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
cbc69537cd |
fix(discovery): carry provider repair instructions into capability discovery (#8532)
* fix(discovery): carry provider repair instructions into capability discovery Provider readiness reported only a failure description, so capability discovery copied that description into tool_availability remediation and dropped repairs the owners already had: the JEB discovery-deadline setting, the ADB/Apktool execute-permission repair kept in diagnostics, and the IDA and Kuna configuration recovery. Unavailable ProviderAvailability now requires the owner's remediation next to its reason, and readiness-derived unavailable capability descriptors carry it too. Every producer supplies it (ADB, Apktool, JADX, JEB, Ghidra, Hopper, IDA, Kuna, pcap, owned-process prerequisites, profile rejection); the inventory uses it verbatim, falling back to the reason only for static capability facts that declare no repair. ADB/Apktool configuration failures own remediation as a field instead of diagnostics, and execution refusals project it as remediation.action. JADX doctor reads the availability's remediation instead of re-deriving it. binary_session complete candidate availability and unavailable capability groups expose remediation (CLI capabilities/providers too); summary omits it and lists it in omitted_fields. The superseded IDA configuration_remediation and windows_native_failure.remediation diagnostics are removed. Fixes #8506 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(discovery): keep owner repairs through provider selection and capability maps Address review findings on the readiness-remediation contract: - Provider selection rejections carry the availability owner's remediation, CLI/MCP error details project it, and an explicit selection refused by readiness uses it as remediation.action. IDA's unreadable registration and Ghidra's Windows readiness repair no longer degrade to generic selection advice now that the diagnostics copies are gone. - Ghidra's Windows readiness and existing-project capability maps carry the same repair as the availability. - pcap readiness keeps the limiter owner's repair (now a typed remediationAction) and falls back to Wireshark guidance only when the failure has none. - ADB/Apktool repairs are owner constants that are complete sentences. The execution refusal keeps its previous message-plus-repair recovery, which the compiled CLI contract asserts. - Regression tests compare with the owning formatter or constant and add public MCP and CLI coverage for an explicit IDA selection. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
eb39a07966 |
feat(evidence): read selected complete records without the whole bundle (#8528)
* feat(evidence): read selected complete records without the whole bundle get_evidence_bundle could discover a record by exact ID, but reading it required the complete canonical bundle: complete + filters was rejected, and inspect_analysis_view refuses parents without a view, such as annotations, pseudocode sources and native traces. - Add detail: records, a page (offset, limit; default 0, 8) of the complete matching records in canonical bundle order. Records keep their original IDs, subjects, providers and readback; missing_evidence_links names direct links of the returned records that are not retained. - The selection is labelled as historical and not an importable bundle; complete keeps returning the canonical bundle, and offset/limit require detail: records. - Filters keep one owner shared by summary and records delivery, for the MCP session and the CLI's inspect-evidence-bundle. - An oversized record page now advises a smaller limit or one evidence_id; whole-bundle overflow guidance mentions record reads. Fixes #8307 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(evidence): compare record-selection guidance with its owners Assert the record-selection limitations and oversized-page guidance against their owning constants, and check the reported limit facts separately, instead of pinning explanatory phrases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
4b840aa1fb |
fix(setup): report the failed Hopper request URL and HTTP status (#8526)
* fix(setup): report the failed Hopper request URL and HTTP status Hopper download callers collapsed every transport failure into a bare `ok: false`, so HTTP 404 and 503 from the macOS feed and DMG, the Linux publisher feed, the public key and the launch-time package download produced identical generic advice without the failed URL. The shared downloader now returns a typed failure (url plus http_status, timeout, network, response_too_large or url_refused) and keeps caller cancellation as a rejection. Installers attribute it to the request (release_feed, package or public_key); HopperReleaseError carries it, and setup projects it once into `download` and a remediation naming the URL, outcome and next step. Replaces the Linux-only "Package download returned HTTP" special case. Fixes #8503 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(setup): refuse credentialed Hopper URLs and keep known HTTP outcomes Native Fetch rejects a URL with userinfo using a TypeError that echoes the whole URL, so a credentialed redirect reached `download.detail`, setup remediation and publisher messages as a network failure. The downloader now refuses request and redirect URLs carrying credentials as `url_refused: credentials` before requesting them, and reports the caller URL through the shared userinfo-removing `sanitizeBrowserUrl`. Releasing an unadmitted body no longer replaces the outcome it was released for: an errored (truncated) body after HTTP 503, or a failed cancel at the size limit, keeps `http_status` or `response_too_large`. Tests compare delivered remediation with the owning formatters and assert request, URL, status and recovery class independently. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
423059a4de |
feat(javascript): page retained feature traces through analysis views (#8522)
* feat(javascript): page retained feature traces through analysis views A bidirectional trace_application_feature result can exceed one MCP response, and inspect_analysis_view refused trace parents as unsupported, so the only recovery was exporting the whole session. - Add a shared feature-trace view owner: a summary with the trace's identity, producer counts and coverage, and pages of paths, nodes, edges, seed_matches and native_handoffs in retained order with exact filters. Node rows are compact unless observations are requested. Page coverage never upgrades trace coverage. - Accept an optional MCP view on trace_application_feature that retains the complete trace before returning the selected facts; the CLI keeps complete JSON and reads saved traces with inspect-analysis-view. - Offer a ready-to-call first paths page when a retained complete trace exceeds the MCP response budget. - Share the distinct authority/state/confidence basis helper with module references. Fixes #8296 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(javascript): name the retained parent when a selected view overflows Review follow-up for the feature-trace views. - Share one delivery owner between trace_application_feature and compare_source_to_bundle: stage the selected view against the completed parent, keep the established contract that a cancelled request commits no session facts, then commit sources and the parent. - A selected view that exceeds the response budget now references the retained parent and offers the same selection at half its limit, instead of naming the view record, which cannot be a view parent. - Cover two native handoffs paged one at a time, the oversized selected page, and cancellation after the trace completes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(javascript): bind feature-trace pages to their collection rows Advertise each feature-trace page with exactly its own row schema, so a paths page cannot validate with node, edge, seed-match or handoff rows. The native-trace view in #8533 received the same review finding; the two sibling views now share one strict page contract. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(javascript): mix valid rows from another collection into a trace page Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
44b6384009 |
fix(native): find procedures by the secondary names exact lookup accepts (#8520)
* fix(native): find procedures by the secondary names exact lookup accepts search_procedures matched only each procedure's primary name, while exact lookup also accepts Kuna inventory aliases (versioned-symbol and generated sub_ names) and Ghidra symbols at an exact function entry. A search for a name procedure_address resolves returned nothing, and trace_feature silently missed the procedure. Both providers now match the same names their exact lookup accepts. A procedure still appears once under its primary name; the optional matched_aliases field lists the secondary names that matched, so aliases never become procedures of their own and list_procedures is unchanged. The shared domain helper owns that row rule for Kuna and for the Ghidra host-side Unicode folding pass. The Ghidra analysis profile records the new search semantics so older snapshots cannot replay alias-blind results. Fixes #8330 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(ghidra): match leaf spellings of procedure names in search procedure_address accepts each entry symbol's leaf or namespace-qualified spelling, but procedure search tested only qualified names, so a regex such as ^audit_alias$ missed a secondary symbol ns::audit_alias (and ^same$ missed a primary alpha::same) that exact lookup selects. Lookup and search now share one bridge definition of the names that select a procedure, so they cannot drift. Matching secondary symbols are still reported by their qualified names; because a leaf ends its qualified spelling, the host's Unicode literal pass stays exact over those names. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
3f61303939 |
fix(session): clear provider-inferred unavailability after recovery (#8518)
* fix(session): clear provider-inferred unavailability after recovery A provider adapter or process failure marked every routed operation of that provider unavailable, but a later success cleared only the operation that succeeded. Sibling operations, and composed tools built on them, kept advertising the stale failure until each was retried individually. Move runtime availability into one owner that records whether each entry was observed for the operation or inferred from another operation's provider-wide failure. A success clears its own failure and that provider's inferred entries while keeping failures observed on other operations or providers and declared refusals. Outcomes are ordered by dispatch to the provider client, so an older in-flight success no longer erases a newer failure while a request queued behind a failure still clears it. Fixes #8404 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(session): keep newer successes when older failures complete last Runtime availability kept one merged entry per operation and forgot successful dispatches. An older provider-wide failure that completed after a newer success re-inferred unavailability for siblings the newer success had already proved working, and a superseded refusal could survive its own later success. Record only the newest failure and newest success dispatch per operation and per provider, and project unavailability from them: an operation is unavailable while its own newest failure is newer than its own newest success, or, as inferred, while its provider's newest provider-wide failure is newer than any success from that provider. The projection no longer depends on reply completion order. The recovery tests now bound held-reply acknowledgements, release and join every held call in finally, and compare remediation with the owning formatters instead of copying their wording. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
3e6a5cb20a |
fix!: preserve address context input errors (#8419)
* fix: retain address context cleanup failures * fix!: preserve address context input errors BREAKING CHANGE: Strict clients that cached the previous full inspect_address_context output schema must refresh tools/list and accept the typed error field on unavailable facets. * test: use session contract for address context |
||
|
|
1d343a88e5 | feat(kuna): verify release 1.988 (#8509) | ||
|
|
df25bc8068 |
fix(ghidra): retain relocation symbol observations (#8531)
* fix(ghidra): retain relocation symbol observations * test(ghidra): verify named relocation symbols through CLI * fix(ghidra): clarify verification and supervise test commands * test(ghidra): share load verification guidance |
||
|
|
32c253ba31 | fix(electron): preserve application argv during active capture (#8492) | ||
|
|
bafe3784cd |
fix(native): report dispatch target applicability (#8400)
* fix(native): report dispatch target applicability * fix(native): clarify unavailable mode recovery * test(kuna): avoid overlapping verifier imports * docs(native): explain mode-specific discovery * fix(native): preserve unbound provider recovery |
||
|
|
d684125eed | docs(providers): verify prerequisite recovery and sibling failures | ||
|
|
53363166f0 |
fix(evidence)!: validate native view parent predicates (#8451)
Reject native view sources whose predicate disagrees with the selected operation. Use the original predicate for existing Evidence; do not alter a record without recomputing its identity. |
||
|
|
3842809c37 | docs(setup): clarify Hopper failures and installer verification | ||
|
|
e5e0dc5542 | fix(ci): include hidden VitePress configuration in CodeQL (#8486) | ||
|
|
60c0cf977a | docs: clarify recovery for valid lookup failures | ||
|
|
1c1c8f6286 |
fix(snapshot): report binding mismatches (#8432)
* fix(snapshot): report binding mismatches * test(snapshot): assert structured mismatch recovery * docs(snapshot): explain profile comparison recovery * fix(snapshot): include profile in recovery advice * docs(snapshot): explain fresh-session profile discovery * refactor(snapshot): derive admission from binding comparison |
||
|
|
a6caa79bf4 | ci(codeql): separate production scans from test fixtures (#8450) | ||
|
|
e18594b247 |
refactor(composition): unify capability bindings and cleanup ownership (#8441)
Bind typed service creation, observed availability and retryable cleanup in one composition owner. Reuse selected CLI/MCP factories and canonical contract groups without copying provider operation inventories. Closes #8429. Refs #740. Validated paired real application workflows, actual local Codex CLI Terra/high use, complete Evidence and Unknown checkpoint parity, compiler-backed import boundaries, SDK schemas and final real mixed routing. Automated review findings were fixed at their producing owners. Existing exact-base CodeQL alerts are documented on the PR under the owner-authorized unrelated-check exception; no global alerts or security rules were changed. Assisted-by: Suika (gensokyo-skills:suika-scatter-gather-planning) |
||
|
|
6e9ee97a69 |
fix!: preserve feature traces when owner lookup is unavailable (#8368)
* fix!: preserve feature traces when owner lookup is unavailable * test: strengthen feature trace cancellation assertions * fix: preserve feature trace provider readiness errors * test: verify all feature trace reference sources * test: verify IDA guidance at its owning boundary * style: format feature trace regression |
||
|
|
f72638f6b1 |
feat(investigation)!: retain records across engine cleanup (#8361)
Separate engine cleanup, investigation reset and terminal disposal in the shared application owner. Keep stable Evidence IDs and full Unknown revision history through engine close and target changes; serialize reset with all record writers and cleanup owners, optionally acknowledging a complete checkpoint before clearing. Bound retained representation without eviction. Validation: 43 focused files / 533 distinct tests, source/type/lint/schema/documentation checks, nine genuine source cases across eight families, real Ghidra session identity and cleanup, and nine actual local Codex CLI terra/high runs with independent full-result and checkpoint audits. See docs/verification/investigation-lifecycle.md for measurements, partial attempts and verification limits. Fixes #8347. BREAKING CHANGE: close_binary retains investigation records. Use reset_investigation to clear them. Cross-process recovery requires an explicitly acknowledged Evidence bundle checkpoint. Assisted-by: Suika (gensokyo-skills:suika-scatter-gather-planning) |
||
|
|
a36c9dd9c8 |
fix(kuna): omit Mach-O data symbols from the procedure inventory (#8335)
* fix(kuna): omit Mach-O data symbols from the procedure inventory Kuna's `functions --json` registers every Mach-O export as a function entry, so globals in `__DATA,__data`, constants in `__TEXT,__const` and `__mh_execute_header` were listed, counted and decompiled as procedures. The Kuna session now classifies each inventory entry with the target's own section table, read by the shared `inspect_macho` load-command reader from the header bytes kept while its private copy is hashed. Entries in sections that declare no instructions, or in the header and load commands, are data: listings and searches omit them and report per-region counts, and procedure operations refuse them by name or address while `address_name` and `xrefs` still accept them. Instruction sections, symbol stubs and symbol-pointer import slots are kept; addresses outside every section stay with an explicit limitation, an unreadable section table keeps the whole inventory unclassified, and ELF inventories are unchanged. Composed workflows such as `decompile_all` and `binary_overview` follow the listing. Fixes #8168 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(kuna): keep an entry's classification caveat on direct answers Resolution now returns the selected entry's Mach-O placement and the caveat it leaves open, built by the same constructor as the listings: the one-entry unplaced wording, or the unreadable section table's reason. Pseudocode, assembly, analyze_function (including the dossier's own limitations), procedure_address, call queries by name and address_name carry it; code and import-slot entries carry none. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
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> |
||
|
|
c534e249d1 |
perf(process): reuse a verified Darwin ownership helper across processes (#8318)
* perf(process): reuse a verified Darwin ownership helper across processes Every REA process on macOS compiled the Swift ownership helper into a fresh temporary root and then paid macOS's first-launch assessment of that new executable: 408 ms + 325 ms of a 1.4 s `rea inspect-macho /bin/ls`. With the default xcrun compiler and module cache, the reader now keeps one content-addressed copy under ~/Library/Caches/rea/process-helper/<key>/. The key covers the helper sources, toolchain selection, architecture and Darwin release. A copy is executed only after the cache root, entry and files are verified as current-user owned, not group- or world-writable, not links, and digest-matched to the entry manifest. Malformed entries owned by the user are removed and rebuilt; linked or foreign entries are left untouched and the per-process compile runs as before. Any cache failure falls back to that compile, so the cache never fails an ownership operation. A miss compiles exactly as before, then publishes a copy through an atomic rename, keeping the first concurrent publisher, and runs the shared copy. That way its first-launch assessment is paid once. Per-run roots keep their existing cleanup; published entries are never removed by close or exit. An explicit REA_DARWIN_SWIFTC_PATH or REA_DARWIN_MODULE_CACHE_PATH keeps the per-process compile and writes nothing to the cache. `rea uninstall --purge-data` removes the namespace. Fixes #2483 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(process): harden the shared Darwin helper cache Address review findings on the shared ownership-helper cache: - Verify every real parent of the cache root: each must belong to the user or root and not be writable by others (sticky root-owned directories excepted), so no other user can rename a verified entry. Execute through the real path. - Open manifest and helper through the owned non-blocking regular-file reader, so a FIFO cannot block preparation, and retain handles whose close fails. - Key entries on the swiftc and SDK that xcrun itself resolves, including their real paths, sizes and modification times. DEVELOPER_DIR, TOOLCHAINS, xcode-select and in-place updates therefore select new entries. - Never remove or replace an invalid or published entry. Removal could race another process that has verified or is running that path, so such an entry falls back to the per-process compile. - Give the cache a close() that retries retained staging removals and handle closes and reports ProviderCleanupError while any remain. The reader closes it with its per-run root. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(process): keep cache lookups owned and fall back from unlaunchable helpers Address the second round of review on the shared ownership-helper cache: - Pass the preparation signal to both xcrun toolchain lookups, and wait for every started lookup before reporting the first failure. Cancellation and close then stop a stalled lookup instead of waiting out its deadline. A failed or cancelled key computation is retried by the next lookup. - When the verified shared copy cannot launch (EACCES, EPERM, ENOEXEC, ENOENT or an unrequested SIGKILL, for example from a noexec home volume), the reader stops using the cache. It reuses its own compiled helper or compiles one, and retries the read once. - Anchor the cache's returned cleanup errors as cleanupRoot does, so every error returned while cleanup was pending resolves after a retry succeeds. - Build the cache path with appendCallerPath, so a home with symlinks and `..` keeps the caller's meaning instead of being normalized lexically. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(process): keep concurrent fallbacks and dual cleanup failures Each helper read now records before awaiting whether it launched the shared copy, so a concurrent read's fallback cannot hide its own. When the per-run root and the cache's retained resources both fail one close, the returned error composes both. It stays incomplete until both owners recover. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(process): refuse shared helpers that an ACL lets others write macOS ACLs can grant writes that the POSIX mode bits do not show. On Darwin, lookup and publication list the real ancestors, the entry and its files with `ls -lde`, and refuse sharing when any ACL entry allows a write-class right. The default `group:everyone deny delete` entries on macOS home folders are unaffected. The unlaunchable-helper test now removes the execute bit from a verified copy, which refuses launch on both Linux and macOS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
41e7333cb5 |
feat(guidance): distinguish focused matches from broad parent sections (#8305)
* feat(guidance): distinguish focused matches from broad parent sections Guidance search treated a parent section, including every descendant, as one match. Terms scattered across unrelated subsections made a 49K-character root the only result for "switch provider annotations", and every ancestor of a focused hit was listed alongside it. The section parser now records each section's own text (heading and body before its first subsection) and its parent. Search keeps the same admission rule but classifies each match by match_scope: "section" when every term is in the section's own text, "subsections" when the terms are only spread across subsections. Ancestors whose terms all sit inside one subsection are no longer listed, section matches rank first, and subsections matches carry own_text_terms plus bounded greedy pointers to the subsections holding the remaining terms. Every match reports content_length so callers can judge a read before making it. Read still returns the complete section. Own text is tokenized once per request instead of each expanded subtree. Fixes #8290 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(guidance): require the scattered-match checks to run Count the subsections matches the real-bundle test inspects and fail when none were checked, and document that a parent whose own text holds every term stays listed beside its matching subsection. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
da0e9669a8 |
fix(decompile): keep provider no-pseudocode facts on batch items (#8323)
* fix(decompile): keep provider no-pseudocode facts on batch items A batch_decompile item whose provider answered without pseudocode was reported as unreadable output with doctor guidance, and the provider's reason, such as a Kuna export failure for that entry, survived only in the batch-wide limitations. The workflow read only the observation's result. Read each item's complete observation. A null answer is now a capability_unavailable item naming the provider, and every item answered without usable text keeps that observation's own limitations, so a batch-only Evidence export retains the association. Empty or non-text pseudocode stays unreadable output; typed provider failures and successful items are unchanged, and the batch Evidence still aggregates every caveat. The batch workflow revision changes so earlier snapshots are not replayed with the previous item semantics. Fixes #8226 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(decompile): match null-pseudocode guidance to reported caveats A null answer without caveats told the caller to read item limitations that the batch omits when the list is empty. The guidance now depends on whether that observation reported caveats, and says the provider gave no further explanation when it did not. The batch tests now select their contracts by name from the enhanced and session families instead of the full catalog. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
73ff6ca0c8 |
fix(native): separate value-trace page omission from traversal truncation (#8309)
trace_native_values set one truncated flag for two different facts: the returned page omits retained nodes, and a budget stopped or narrowed the traversal. A last page of a complete trace and a node- or edge-capped trace both reported truncated: true with next_offset null and no unknown naming the cap, so a caller could not tell whether to follow pages, raise a budget, or treat the examined graph as exhausted. Results now carry page_truncated for page omission and a traversal object that is complete, or truncated with the observed reasons in schema order: max_depth, max_functions, max_call_sites, max_nodes, max_edges, node_payload_bytes, provider_pcode_truncated and ambiguous_call_candidates. truncated keeps its previous meaning as the union of both. A new budget owner admits nodes and edges and records every cause together with a located unknown, only after a budget rejects work; an exactly filled budget is no longer truncation. Depth and ambiguous-candidate limits are resolved after traversal, so a destination analyzed or queued through a shallower path is no longer reported as depth-limited. Once an edge is rejected, remaining call sites in that procedure are not resolved. Fixes #8283 Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
c287a73276 |
fix(ghidra): report unbacked file-offset addresses without schema repair (#8308)
* fix(ghidra): report unbacked file-offset addresses without schema repair address_to_file_offset projected a well-formed address in uninitialized or unmapped Ghidra memory as generic invalid input: the headline said the arguments were invalid and recovery pointed at the input schema, while the real reason survived only in a nested issue. The bridge now gives each outcome its own code (address_unmapped, address_uninitialized, file_mapping_absent, file_mapping_ambiguous, file_offset_unrepresentable) instead of folding them into invalid_request. The Ghidra projection keeps the bridge reason as the headline, points to inspect_native_load_image, records the caller's exact address and the file_mapping outcome, and scopes diagnostics to the request. AnalysisInputError gains conformsToInputContract so a conforming request omits recovery.kind=inspect_input_contract. Malformed addresses and other bridge refusals keep their existing projection. Fixes #8244 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(ghidra): match fixture block ends to bridge conventions The fake bridge treated .text's exclusive list_segments end (0x1100) as an inclusive bound, so address_to_file_offset mapped an address outside the block. Give the fixture's blocks one owner (start and size) and derive each reply from the production bridge convention: exclusive list_segments ends, inclusive byte-search coverage, half-open containment for file offsets. Add an MCP boundary test that reads the block edges from list_segments and search_bytes, maps the last file-backed byte and refuses the first address past each block with its outcome code. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
7c9ed94259 |
fix(ghidra): decide batch names independently of request order (#8306)
* fix(ghidra): decide batch names independently of request order The Ghidra bridge applied set_addresses_names in JSON member order, each address in its own transaction, so a reordered but equivalent map could give a shared name, or a name released by another selected address, to a different address. The bridge now resolves every destination (namespace and leaf name) against the names held before the batch. Addresses that request the same destination, or a name that another selected address holds, are rejected without applying; the remaining edits are independent and apply as before. Both naming operations report each failure's canonical address, reason and related addresses. The adapter projects the bridge reply to the unchanged boolean results and keeps the reply as raw_result only when an address failed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(ghidra): report each contested batch name once A batch conflict listed every other requester on each failure, so k addresses competing for one name produced k(k-1) related addresses, and the adapter retained the whole reply, booleans included, as raw_result. The bridge now reports each contested destination once in a conflicts table with its namespace, name, requesting and holding addresses, and each conflict failure refers to it by index. Conflicts are ordered by their first requester, so indexes do not depend on member order. Single and batch naming share one planner and reply layout. The adapter validates the table in linear time and keeps only failures and conflicts in raw_result. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
a989c0e458 |
refactor(evidence): unify retained inputs across domains (#8299)
Declare logical Evidence sources once and resolve exact retained inputs through shared application workflows across 20 composition tools. Preserve domain-owned authentication, source closure, caller choices, coverage and resource admission. Validation includes public CLI/MCP regressions, local Codex terra/high trials and fresh-import real-artifact workflows. Measurements, failed attempts and coverage limits are recorded in docs/verification/evidence-input-composition-2026-10-31.md. Fixes #8293. Fixes #8281. Assisted-by: Suika (gensokyo-skills:suika-scatter-gather-planning) |
||
|
|
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
|
||
|
|
e669365c3b |
feat(ghidra): admit RISC-V ilp32 ELF with a derived calling convention (#8229)
* feat(ghidra): record the RISC-V float-ABI calling-convention decision Decision D3 (#7477), provisional: admit ELF32 soft-float (ilp32) RISC-V images through a lane that keeps the pinned RISCV:LE:32:default language and corrects the calling convention in the bridge. This commit is the contract only; admission is unchanged. - The domain owns the e_flags float-ABI vocabulary and parses .riscv.attributes and Tag_RISCV_arch into a declared, absent or unavailable ISA declaration. - The Ghidra profile owns the lane table (class and float ABI), lane ids built from fields, the ilp32-prototype-v1 policy and its __rea_ilp32 prototype, and the extensions Ghidra 12.1.4 decodes with p-code. - The session handshake accepts the bridge's calling-convention report. - docs/ghidra-riscv.md keeps the decision record and per-ABI policies for ilp32 and ilp32f; a test keeps it in step with the tables. - tests/conformance/c/riscv-float-abi.c is the source the policies were measured on. * feat(ghidra): admit RISC-V ilp32 ELF with a derived calling convention ESP32-C2, C3, C5, C6, C61, H2 and H21 builds are ELF32 soft-float (ilp32) images, which the RISC-V lane refused at its double-float check. Ghidra 12.1.4's generic RV32 compiler specification models ilp32d, so its stock prototype would read float and double arguments from fa0-fa7. - Target resolution reads the one SHT_RISCV_ATTRIBUTES section through the same bounded ELF declaration reader as range validation, and records Tag_RISCV_arch as declared, absent or unavailable. - Admission selects a lane from the class and float-ABI table. The soft-float lane also requires an RV32I Tag_RISCV_arch that declares only extensions Ghidra decodes with p-code; the refusal names any others (Zcb, Zcmp, Zcmt, Zb*, xesp*). - Soft-float profiles commit float_abi, arch, riscv_calling_convention ilp32-prototype-v1 and the lane elf32-exec-le-soft-float-generic-v1. Double-float profiles are unchanged. - ReaGhidraRiscvCallingConvention.java runs after analysis. It derives __rea_ilp32 from the default prototype without floating-point entries and rules, with fs0-fs11 killed by calls, self-checks its storage and assigns it to every non-thunk function, external function and function definition. Its report is written last. - The provider client requires that report exactly when the profile commits the policy, before any operation, and keeps it as session limitations and caller-project history. ELF32 single-float (ilp32f), quad-float and ELF64 soft- or single-float images stay refused, now with a reason built from the lane table. * test(ghidra): verify RISC-V ilp32 against real Ghidra verify:ghidra:riscv now also builds tests/conformance/c/riscv-float-abi.c with ESP32-C3's -march=rv32imc_zicsr_zifencei -mabi=ilp32, typed with DWARF and linked again with --strip-all. Every allocated section of the stripped image must keep its address and bytes. - riscv-checks.mjs holds the ilp32 storage of each fixture function together with the words the compiler's call site writes there. An LLVM objdump reading of the caller must find every word at its stated location: an unaligned named double, the a7/stack split, two floats in an integer pair, a large structure by reference, aligned variadic pairs and an indirect call. - Through CLI and stdio MCP, the soft-float builds must report the soft-float lane and ilp32-prototype-v1, __rea_ilp32 with exactly that storage (one integer word per location when stripped), caller pseudocode that passes the source constants and names no floating-point register, the prototype outcome in retained Evidence, and decoded fence.i and csrr. - The RV32 double-float image relabelled as soft-float, refused before, is admitted through the new lane. RV64 soft-float, single-float and unsupported bits are refused with their reasons. - riscv-checks.test.ts runs the checks offline against recorded LLVM and Ghidra output, including Ghidra's stock ilp32d prototypes as a negative control. * fix(ghidra): pass RISC-V ilp32 values over 8 bytes by reference The psABI passes any value wider than 2 x XLEN by reference, scalars included. __rea_ilp32 converted only structures and unions over 8 bytes to pointers, so a long double (16 bytes) was joined into a1-a4. Measured on Ghidra 12.1.4, rea_riscv_abi_quad(long double value, int sel) read value from a4:4,a3:4,a2:4,a1:4 and sel from a5, where clang passes a pointer in a1 and sel in a2. - ReaGhidraRiscvCallingConvention.java now has one derivation driven by a per-policy row (floating-point entry size, preserved floating-point registers). Every policy inserts a rule before the input list's final join that converts any value of 9 bytes or more to a pointer; a return that size already becomes a caller buffer. The self-check requires a 16-byte value to pass by reference. - The fixture gains rea_riscv_abi_quad. The call-site oracle now checks the words the by-reference pointers point at, for the large structure and the long double, and the recorded data comes from an LLVM 19 build. - docs/ghidra-riscv.md: the decision record and the ilp32 policy row. ilp32-prototype-v1 keeps its id: no release carries it yet. * test(ghidra): check RISC-V lane limitations by their facts The limitation tests froze a full explanatory sentence, the note count and array positions, so a harmless rewording failed them: the pattern Greptile flagged on #7486. Assert the facts the notes must carry instead: the pinned language, the static-linkage boundary, one note naming the declared ABI, the ABI the pinned language models and the prototype REA applies, and the declared ISA. * test(ghidra): check return storage in stripped RISC-V ilp32 builds The stripped branch of assertRiscvIlp32Storage compared parameter storage only, so an inferred return that lost the high word of a register pair, such as rea_riscv_abi_wide at a0:4 instead of a1:4,a0:4, still passed. Stripped returns must now use the typed build's storage, or none when the result goes through caller memory. Recovered type names are still not compared: a test accepts other type names and refuses the dropped high word. * docs(ghidra): record decision D3 as decided in #7477 |
||
|
|
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 |
||
|
|
091892dfed |
test(ghidra): expect carved MIPS copies to be refused at target opening (#8227)
Since |
||
|
|
245a581818 |
feat(kuna): verify release 1.986 and guide version selection (#8187)
* feat(kuna): verify release 1.986 and guide version selection * test(kuna): cover verified release doctor guidance |
||
|
|
ec107022fa | docs: guide audits of existing investigation tools (#8272) | ||
|
|
b349e3c708 |
fix(evidence): give missing retained closures actionable recovery (#8270)
* fix(evidence): give missing retained closures actionable recovery * refactor(evidence): assign retained lookup context at resolution |
||
|
|
d9e01e5af2 | feat(evidence): aggregate exact retained comparison references (#8267) | ||
|
|
6e2404b869 |
fix(comparison)!: preserve same-entry correspondence across renames (#8263)
* fix(comparison): preserve same-entry correspondence across renames * docs(comparison): align rename guidance and focused contract checks |
||
|
|
356cc50475 |
docs: guide design and verification of provider workflows (#8261)
* docs: guide provider workflow design and annotation comparisons * docs: connect provider tool design to workflow verification |
||
|
|
d48e472fa6 | fix(mcp): preserve repeated HTTP host allowlists (#8164) | ||
|
|
ca7d1c3750 |
fix(ghidra): match startup-timeout guidance to the project mode (#8114)
In fresh-import mode, the startup-timeout remediation now points to REA_GHIDRA_PROJECT_PATH for reusing a completed analysis, next to the existing REA_GHIDRA_STARTUP_TIMEOUT_MS and REA_GHIDRA_DISABLED_ANALYZERS advice. In existing-project mode, the message no longer says Ghidra was importing and analyzing the target, and the remediation no longer suggests REA_GHIDRA_DISABLED_ANALYZERS, which configuration validation rejects together with REA_GHIDRA_PROJECT_PATH. Refs #3751 |
||
|
|
0ffed7a48c |
feat(android): trace callers of external DEX methods (#8154)
Resolve exact external method targets from directly encoded DEX invokes. Preserve complete caller identity, bounded position evidence and follow-up selectors. Report aggregate position coverage independently of the caller inventory, and reuse bounded prototype facts within the exact session. Absorbs #8096. Fixes #7811. Co-authored-by: hhang <169027046+xu91102@users.noreply.github.com> |
||
|
+1 |
1ddee1089b |
feat(dotnet): expose field constant defaults (#8015)
* feat(dotnet): expose field constant defaults * test(dotnet): guard field default comparison warning Compare actual ordinary and constant-bearing observations independently of the limitation producer. Preserve warning delivery and unchanged matching assertions while allowing harmless wording changes. Refs #5150 * test(mcp): retain structured bundle path diagnostics Keep absolute-path refusal and all rejected parameter facts independent of legacy flat or current structured SDK diagnostic rendering. Retain relative CLI, absolute MCP and no-Evidence controls. Refs #5150 * Revert "fix(ci): integrate main and repair inherited static checks" This reverts commit |
||
|
|
250dc81cd6 |
fix: correct stale provider refusal and diagnostic text (#7484)
* fix(ghidra): name every admitted family in the architecture refusal The refusal listed x86, x86_64, arm, arm64, MIPS, RISC-V, raw 6502 and raw m68k, but the admission set also holds powerpc and hexagon. Build the text from SUPPORTED_ARCHITECTURES, marking raw-only families, so a newly admitted family cannot be left out again, and name the refused family. * fix(hopper): stop calling the Ghidra Hexagon lane verified Hopper declined Hexagon targets with "Select a verified Ghidra Hexagon profile instead", but REA has no verified Hexagon lane. Record whether each declined family's Ghidra lane is verified, and say that Ghidra admits Hexagon through an unverified lane. Name declined families by architecture id, as the Ghidra and IDA refusals do. * fix(ghidra): name the pinned language in profile readback refusals The session readback said "MIPS" whenever a provider-pinned profile conflicted with the target or with REA_GHIDRA_LANGUAGE_ID, although the RISC-V, PowerPC and DOL lanes are pinned too. The readback helper was MIPS-named and re-parsed the language slot that ghidraProfileLanguageOverride already owns. Move it beside that owner as a family-neutral readback and name the pinned language id instead. * fix(ghidra): list DOL among independently verified load images GameCube DOL load images are independently verified, but the declined format reason, the inspect_native_load_image capability note and the Windows P0 guide listed only DOS MZ, DOS COM and raw-binary. * fix(ghidra): count RV32E's sixteen integer registers The EF_RISCV_RVE refusal described a 15-register ABI. RV32E has 16 integer registers, x0-x15, as docs/ghidra-riscv.md already says. * fix(elf): name the refused e_machine "unsupported ELF architecture" did not say which machine was refused. Include the numeric e_machine, for example EM_XTENSA 94. * test(hopper): assert declined-lane facts and owned refusal reasons The MIPS case banned the phrase "not verified" instead of checking facts, so wrong advice would still pass. Expose each declined family's Ghidra lane status, assert those statuses, check that the advice depends on the status, and compare Hopper's refusals with hopperDeclinedArchitectureReason. The RISC-V refusal table now compares the provider's reason with ghidraRiscvUnsupportedReason and expects the EF_RISCV_RVE declaration name rather than fixed wording. * test(ghidra): assert verified load-image formats as owned facts The declined-format test required display phrases such as "DOS MZ" and "GameCube DOL", so harmless rewording failed it while wrong guidance containing those names passed. The format list was also spelled three times: in the attestation's membership check, its reason and the inspect_native_load_image capability note. Give the verified formats one owner with the formatters for both texts, assert the list as a fact, and compare the delivered reason and capability note with those formatters. * fix(hopper): stop restating which Ghidra lanes REA has verified Hopper's refusal for families it declines carried its own table of which Ghidra lanes REA has verified (mips, riscv and powerpc verified, hexagon not). That restated the Ghidra provider's facts in Hopper and goes stale whenever they change, the drift that made the Hexagon refusal wrong in the first place. Reading Ghidra's facts from Hopper would couple the providers instead; no module in src/hopper imports from src/ghidra. The table and hopperDeclinedGhidraLane are removed. hopperDeclinedArchitectureReason now states only what Hopper owns: it does not admit the family, and the Ghidra provider's lane reports whether REA has verified it. The arm64_32 sentence is unchanged. The test checks every declined family against the formatter: each reason names the family and Ghidra, and apart from the name all reasons are the same text, so none states a per-family Ghidra status. * fix(hopper): route declined families to Ghidra without promising its lane facts The refusal said the Ghidra lane reports whether REA has verified it, but Ghidra admits Hexagon with no such note, so a caller could not find the promised status. Hopper now only states that it does not admit the family and routes the caller to the Ghidra provider. |
||
|
|
19ab239278 |
ci(ghidra): probe M-profile ARM and Xtensa decoding (#7482)
* ci(ghidra): probe M-profile ARM and Xtensa decoding The embedded plan relies on ARM:LE:32:Cortex, ARM:LE:32:v8-m and Xtensa:LE:32:default, but CI only exercised ARM:LE:32:v7. Import source-owned bytes for each language at 0x1000 with -noanalysis and check how they decode from the language's default context: Cortex and v8-m must start in Thumb state, v8-m must decode the ARMv8-M MSPLIM register, and Xtensa must decode entry and retw.n. Add the probe scripts the job runs, including the existing ARM context probe, to the ghidra_bridge change scope. * ci(ghidra): match decode-probe operands as complete operands The operand expectation searched the instruction text for a substring, so mrs/4/msp also accepted mrs r0,msplim. Compare it with each operand Ghidra reports for the instruction, so only a complete operand matches. The Cortex (msp, lr), v8-M (msplim, lr) and Xtensa (a1) expectations are unchanged. |
||
|
|
1926fc2dac |
fix(ida): admit architecture families by allowlist (#7485)
IDA refused MIPS, RISC-V, PowerPC, Hexagon and arm64_32 by denylist, so any family nobody excluded was reported supported, and the label ternary printed "Hexagon" for any other metadata family. Admit exactly the families IDA admits today (x86, x86_64, arm, arm64) and name every other family from its own architecture id. Families that Ghidra admits keep the pointer to a Ghidra profile. Refusal text now uses architecture ids, for example "no verified mips lane" instead of "no verified MIPS lane". |
||
|
|
b33f4a5a1b |
docs: correct the raw ARM example and document a Cortex-M language override (#7483)
* docs(raw-binary): replace the STM32-style ARM example The headline raw example opened ecu.bin at 0x8000000, an STM32 flash address, while the arm lane decodes in ARM state. Map a 32-bit ARM-state image at 0x8000 instead, and state beside the example that Thumb-only images, including Cortex-M firmware, are not supported. * docs(ghidra): document an interim Cortex-M language override Ghidra imports little-endian ARM ELF files as ARM:LE:32:v8, which defaults to ARM state and marks Thumb code only from $t mapping symbols and odd function-symbol addresses. Unpinned arm ELF already admits REA_GHIDRA_LANGUAGE_ID, so document ARM:LE:32:Cortex (ARMv6-M, ARMv7-M, ARMv7E-M) and ARM:LE:32:v8-m (ARMv8-M) as an unverified interim. State the override's full effect while it is set: raw-binary, DOS, DOL, PSP and language-pinned lanes such as RISC-V refuse it, and REA asks Ghidra to import every other target in the ARM language, because it does not check the override's processor against the target. |
||
|
|
cd878ad57d |
refactor(ci): unify lane ownership and guard Python tests (#8150)
* refactor(ci): unify lane ownership and guard Python tests * fix(ci): reject entirely skipped bridge subtests |