mirror of
https://github.com/morluto/rea.git
synced 2026-11-05 06:45:22 +00:00
Open
opened 2026-10-31 01:09:35 +00:00 by bsakaguchi
·
0 comments
No Branch/Tag specified
main
codex/procedure-reference-stacked
release-please--branches--main--components--rea-agents
release-please--branches--main--components--rea-agents--release-notes
codex/kuna-independent-retry
codex/byte-search-overlay-coverage
codex/open-failure-target-receipt
codex/kuna-xref-evidence
codex/ghidra-ambiguous-procedure-recovery
codex/function-source-bundle
codex/trace-function-integration-prototype
codex/snapshot-source-closure
codex/recorded-evidence-array-pages
codex/evidence-recovery-redesign
codex/trace-feature-address-scope
codex/call-discovery-scope
codex/ghidra-literal-candidate-evidence
codex/decompile-directory-independent-retry
codex/retry-provenance-base
codex/value-flow-capability-experiment
codex/ghidra-containing-instruction
cursor/readme-discord-button-ef9f
dependabot/github_actions/actions/setup-node-7.1.0
dependabot/github_actions/actions/upload-artifact-7.0.2
dependabot/npm_and_yarn/npm-minor-and-patch-d8d97ce6df
codex/kuna-1989
fix/8559-native-ui-fixture-ownership
fix/8555-go-verifier-mcp-ownership
codex/provider-capability-recovery
fix/8642-rizin-target-stdin
codex/ghidra-memory-effect-scope
codex/ghidra-annotation-entry-selector
codex/ghidra-readonly-recovery
codex/ghidra-regex-verifier-recovery
codex/evidence-discovery-view-guidance
fix/8545-bulk-append-overflow
fix/8428-navigation-refusal-alternatives
codex/address-context-recovery
codex/matching-member-limitations
codex/unknown-scope-contract
codex/evidence-view-guidance
feat/8373-native-trace-views
codex/ghidra-snapshot-verifier-binding
codex/elf-export-visibility
codex/evidence-view-recovery
codex/native-reference-cli-help
codex/provider-candidate-observation-scope
codex/kuna-session-verification
codex/ghidra-switch-lifetime-guidance
codex/pseudocode-paging-discovery
codex/clarify-evidence-view-support
codex/kuna-xrefs-selector-recovery
codex/context-capacity-recovery
codex/evidence-closure-large-links
codex/same-function-evidence-identity
codex/ghidra-verifier-inspected-jdk
codex/audit-guided-workflows
codex/crash-prompt-retained-dossiers
codex/analysis-view-error-recovery
codex/kuna-verifier-target-selection
codex/ghidra-selected-project-call-coverage
codex/docs-native-analysis-scope
codex/ghidra-java-socket-boundary
codex/ghidra-retained-snapshot-verifier
codex/ghidra-search-inventory-facts
fix/8284-zero-argument-parameter-bindings
fix/8198-ui-action-handler-offset
fix/8257-elf-entry-label-identity
fix/8304-deferred-output-schema-projection
fix/8277-call-path-computed-target-uncertainty
fix/pr-8089-conflicts
fix/ci-static-duplicate-export
dependabot/npm_and_yarn/lint-staged-17.6.0
dependabot/github_actions/actions/download-artifact-8.0.2
dependabot/npm_and_yarn/write-file-atomic-8.0.0
dependabot/npm_and_yarn/canonicalize-5.1.0
dependabot/github_actions/actions/cache/restore-6.1.0
dependabot/npm_and_yarn/toon-format/toon-4.4.0
dependabot/github_actions/actions/deploy-pages-5.0.1
codex/review-fixes-pr-2403
codex/review-fixes-pr-2400
codex/process-terminal-width
codex/test-brittleness-cleanup
verify/7167-browser-connect-macos
fix/7167-browser-connect
feat/native-matching-allowance-setting
feat/browser-scenario-dry-run
test/managed-caller-parameters-20261024
codex/parser-fortythird-boundaries
fix/6926-pinvoke-platform-decorations-20261023
fix/6889-har-body-encoding-20261023
fix/6888-sqlite-schema-budget-20261023
fix/dependency-security-gates-6708
cursor/evidence-overwrite-rebase-b4ac
feat/4057-verify-native-exports
fix/windows-acl-observer-overhead-20261022
cursor/erlang-beam-restack-4476
cursor/pe-certificate-review-bf32
fix/6116-javascript-application-fs-errors
fix/6061-unmapped-runtime-script-unknown
feat/browser-scenario-summary
fix/pe-certificates
codex/verify-3407
cursor/rebase-5699
cursor/rebase-5352
cursor/rebase-5600
cursor/fix-cli-schema-omission-10a8
codex/audit-hopper-shutdown-reasons-20261021
fix/demangle-swift-omitted-record
fix/nib-boolean-value-types
cursor/cancellation-partial-observation-a5ac
fix/ib-object-limit-reasons
fix/electron-fuse-limit-advice
fix/kuna-doctor-dangling-cache
fix/fixed-budget-refusal-advice
fix/js-ipc-listener-dedup
fix/js-return-member-provenance
fix/dmg-integrity-retry-advice
fix/ida-doctor-readiness
fix/kuna-version-probe-output-drain
fix/legacy-swift-runtime-name-matching
fix/dylib-lazy-load-commands
fix/browser-scenario-startup-cancel
fix/swift-nested-punycode-classification
fix/compare-unselected-scopes
fix/objc-method-budget-coverage
fix/dmg-mounted-root-observations
audit/ci-tests-20261019-round2
release/6.7.0
fix/wabt-cleanup-retry-resolution
fix/electron-fuse-elf-pe-architecture
fix/native-plist-descriptor-ownership
fix/kuna-caller-cleanup-ownership
experiment/atomic-codemode-20261016
review/first-contributor-3776
fix/call-resolution-full-read-cycles
fix/member-mutation-selection-repeat
experiment/atomic-re-tools-20261015
perf/member-mutation-lazy-origins
perf/static-network-mutation-index
fix/hopper-startup-lifecycle
audit/3050-windows-proof-20261015
feat/windows-window-capture-2183
audit/3049-windows-proof-20261015
audit/3735-macos-fixtures-20261015
fix/batch-decompile-null-pseudocode
fix/kuna-inventory-honors-jobs
experiment/browser-codemode-tool-design-20261015
fix/hopper-clean-runtime-argv
codex/review-2049-27f1b367
review-fixes/pr-2787-routing
fix/3360-scoped-this-emitters
fix/3367-replaced-global-effects
fix/3838-compact-any-value-items
test/hopper-download-probe-20261015
codex/windows-runtime-creation-red-green-20261015
codex/windows-readonly-root-red-green-20261015
codex/windows-root-share-red-green-20261015
codex/exp-1685-win-mcp-startup
codex/bug-sweep-20261015
investigate/2190-windows-package-phases
investigate/3543-macos-cli-deadline
perf/3281-reverse-tools-feedback-quality
fix/3406-hopper-doctor-fixture
fix/3341-wrapper-require-test-context
fix/3301-owned-uninstall-fixtures
fix/3164-compiler-input-ownership
fix/pcap-cleanup-stdout-newline-20261014
perf/interface-builder-summary
codex/review-fixes-pr-1977
fix/ghidra-effective-jvm-platform
fix/docs-turkish-rust-link-20261013
fix/main-maintenance-ci-20261010
fix/recover-binary-session-process-effects
codex/review-fixes-pr-2457
codex/ci-required-cancellation-gate
fix/main-format-baseline-20261013
fix/setup-preserve-entry-fields
cursor/restore-main-checks-1ffc
fix/ghidra-bridge-hashmap-import
codex/shared-ci-jadx-json-default-20261013
codex/shared-ci-ghidra-test-groups-20261013
codex/shared-ci-java-fixture-format-20261013
codex/fix-intrinsic-invocation-boundaries
test/release-preflight-reusable-jobs
test/js-parameter-provenance-expectation
fix/linux-hopper-verification-current
test/2419-ghidra-elf-probe-size
followup/pr-1544-native-ida
codex/fold-pr-2230-contribution
docs/readme-responsible-use
fix/issue-2064
fix/issue-2050
fix/issue-2053
fix/issue-1968
fix/issue-1945
experiment/codemode-bridge-20261011
fix/tool-effects-negative-wording-1904-20261012
fix/1842-electron-interop-provenance
feat/recover-javascript-multi-input
refactor/website-i18n-prep
fix/nativeaot-pe-virtual-extent
fix/browser-verifier-ci-hang
fix/pe-resources-input-selection
docs/beginner-friendly-guides
docs/beginner-setup-guide
fix/javascript-analysis-worker-1563
fix/1649-ghidra-duplicate-names
fix/javascript-export-keys-integration-1369
test/maintenance-boundary-contracts-20261011
review/javascript-export-keys-1369
review/process-live-progress-1483
test/javascript-1495-growth-ratio
fix/ci-escape-timing
docs/normalized-terminal-geometry-1450
release/6.3.0
archive/release-6.3.0-pr1381
release/6.2.0
fix/electron-preload-dynamic-override
fix/javascript-self-referential-bundler-edges
release/6.1.0
cursor/grok-client-cherry-pick-0b56
feat/signature-posture
feat/dyld-shared-cache
feat/artifact-integrity-policy
feat/pkg-inventory
release/6.0.0
chore/sync-release-5.0.0
release/5.0.0
cursor/cloud-agent-node-787e
fix/javascript-xhr-open-endpoints
review/pr-711-realpath-fallback-wording
cleanup/replay-confinement
codex/test-suite-performance
codex/issue-foundations
codex/address-open-issues-2026-07-20
agent/javascript-vite-rollup-esbuild-adapters
agent/process-cleanup
agent/triage-integration
agent/unknown-commands-registry
feat/mcp-identity-metadata
morlvps/issue_cleanup
codex/installer-redesign
morl/roadmap-investigation-core
morl/roadmap-investigation-docs
release-please--branches--main--components--rea
rea-agents-6.8.0
rea-agents-6.7.0
rea-agents-6.6.0
experiment/atomic-codemode-wait-runtime-20261016
rea-agents-6.5.0
rea-agents-6.4.0
rea-agents-6.3.0
rea-agents-6.2.0
rea-agents-6.1.0
rea-agents-6.0.0
rea-agents-5.0.0
rea-agents-4.1.0
rea-agents-4.0.1
rea-agents-4.0.0
rea-agents-3.2.1
rea-agents-3.2.0
rea-agents-3.1.0
rea-agents-3.0.0
rea-agents-2.7.0
rea-agents-2.6.0
rea-agents-2.5.1
rea-agents-2.5.0
rea-agents-2.4.0
rea-agents-2.3.0
rea-agents-2.2.0
rea-agents-2.1.0
rea-agents-2.0.0
rea-agents-1.7.0
rea-agents-1.6.0
rea-agents-1.5.0
rea-agents-1.4.0
rea-agents-1.3.0
rea-agents-1.2.0
rea-agents-1.1.0
rea-agents-1.0.0
rea-agents-0.5.0
rea-agents-0.4.0
rea-agents-0.3.0
rea-0.2.1
rea-0.2.0
Labels
Clear labels
area: bridge
area: bridge
area: build
area: build
area: build
area: cli
area: domain
area: evidence
area: mcp
area: native
area: providers
area: runtime
area: server
area: setup
area: tests
bug
design
documentation
enhancement
enhancement
enhancement
experiment
help wanted
i18n
invalid
P0: critical
P1: high
P2: medium
P2: medium
P2: medium
P3: low
performance
provider-request
pull-request
Mirrored from GitHub Pull Request
question
roadmap
triage
No labels
area: bridge
area: bridge
area: build
area: build
area: build
area: cli
area: domain
area: evidence
area: mcp
area: native
area: providers
area: runtime
area: server
area: setup
area: tests
bug
design
documentation
enhancement
enhancement
enhancement
experiment
help wanted
i18n
invalid
P0: critical
P1: high
P2: medium
P2: medium
P2: medium
P3: low
performance
provider-request
pull-request
question
roadmap
triage
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set.
Reference
morluto/rea#5807
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/morluto/rea/pull/3531
Author: @goncalompontes
Created: 10/14/2026
Status: 🔄 Open
Base:
main← Head:feat/ghidra-project-cache📝 Commits (10+)
adeb127feat(ghidra): open a pre-imported project with -process instead of re-importingc3c3f0bfix(ghidra): reject existing projects without the fixed rea-project name000f379feat(ghidra): select a pre-imported project with -process1394412fix(ghidra): bound existing project copies to owned cancellable inputs676326efix(ghidra): preserve missing project admission diagnosticsdd53a55fix(ghidra): reconcile project copies with runtime configurationbe9c21ffix(ghidra): isolate saved-project snapshot identitiesbd8633cfix(config): clarify paired Ghidra project settings4b7f7d8Merge captured main into PR #235863c4779fix(ghidra): preserve existing project import mode📊 Changes
130 files changed (+18302 additions, -764 deletions)
View changed files
📝
.agents/skills/reverse-engineer-anything/SKILL.md(+48 -0)📝
docs/.vitepress/config.ts(+1 -0)📝
docs/error-contract.schema.json(+126 -0)➕
docs/ghidra-project-cache.md(+176 -0)📝
docs/installation.md(+68 -0)📝
docs/mcp-contracts.md(+68 -4)➕
docs/specs/1048-ghidra-project-cache/spec.md(+322 -0)➕
docs/specs/1048-ghidra-project-cache/tasks.md(+72 -0)➕
docs/specs/analysis-jobs/spec.md(+232 -0)➕
docs/specs/analysis-jobs/tasks.md(+55 -0)➕
docs/specs/multi-target-sessions/spec.md(+155 -0)➕
docs/specs/multi-target-sessions/tasks.md(+61 -0)📝
docs/tool-design.md(+12 -0)📝
docs/user-visible-errors.csv(+4 -1)📝
src/application/AnalysisProvider.ts(+76 -0)📝
src/application/DirectAnalysis.ts(+8 -6)📝
src/application/DirectAnalysisCleanup.ts(+2 -2)📝
src/application/DirectAnalysisDependencies.ts(+9 -9)➕
src/application/binary/AdmittedEvidenceScope.test.ts(+126 -0)➕
src/application/binary/BackgroundAnalysisJobs.test.ts(+255 -0)...and 80 more files
📄 Description
Adds a managed, persistent Ghidra project cache plus an open-mode-independent analysis identity so prior analysis snapshots replay across sessions.
Related issue: #1048. The pre-imported project selection that issue describes is implemented by #2358; this PR adds the persistent cache layer on top.
NOTE: this branch is stacked on #2358 (
feat/1048-existing-project-wiring), so until #2358 merges this PR's diff also contains its commits (existing-project selection, launcher wiring, and the related profile/config changes). A fork-only stacked copy exists at goncalompontes/rea#1.Problem
Large Ghidra imports re-pay import and auto-analysis on every
open_binary. A saved project was not reusable across sessions, and a cache miss and a later cache hit committed different analysis profiles, so retained analysis snapshots could not replay.What
REA_GHIDRA_PROJECT_CACHE=off|read|on(default off),_DIR,_MAX_BYTES,_MAX_AGE_DAYS.-process -noanalysis -readOnly.project_cachecommitment, so miss and hit share a profile digest.rea cache-list|cache-verify|cache-prune|cache-remove.0700and tightens an existing widened root; Windows creates the root through the native protected-DACL boundary, and an existing root that does not pass that verification is rebuilt as a private directory that keeps the stored projects.Measured (Windows Ghidra P0)
engine2.dll: first open 256.8 s to cache hit 13.1 s.Verification
Local Windows checkout at
d4b8afbba:npx tsc --noEmit┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó pass.npm run format:check┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó pass.npm run lint┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó 0 errors (repository-wide warnings only).npm run metadata:check,npm run jscpd,npm run scan:todos,npm run verify:architecture-guards┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó pass.npm run test:localfor the cache store, cache-root, key, manifest, provider behavior, config, and CLI logging suites ┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó pass.npm run test:focused -- tests/boundary/cli/jsonOutput.test.ts tests/acceptance/cacheVerifyCli.test.ts┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó 44 passed.npm run test:fast┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó 10,530 passed; the 63 failures are pre-existing POSIX/macOS-only suites on this Windows host (ADB paths, Hopper, WABT, Mach-O/Electron). No Ghidra or cache suite failed.The Linux-only
ghidraClientboundary file could not run on this Windows host because its fixture rename hitsEBUSY; Linux CI covers it.npm run knipreports the pre-existing unresolved#web-bundle-analysis-workerimport.Merge refresh (
bf31ce2f9)Merged
upstream/main(fa3665725) into the branch. The only conflict wassrc/ghidra/GhidraSnapshotCache.test.ts: the branch's Windowsdescribe.skipIfwrapper and main's new degraded-Evidence replay test were combined, so the existing relationship-coverage replay case and main's new case run in the same suite.Validation on Linux, merged head:
npx tsc --noEmit┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó pass.npx vitest run src/ghidra┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó 820 passed, 1 skipped; oneGhidraProjectCacheRootlane failed on the first run and passed on rerun (the flake already documented below).npx vitest run src/ghidra/projectCache src/ghidra/GhidraProjectCache.behavior.test.ts src/ghidra/GhidraProvider.behavior.test.ts┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó 210 passed.npx vitest run src/ghidra/GhidraSnapshotCache.test.ts┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó 17 passed.npx oxfmt --check src/ghidra/GhidraSnapshotCache.test.ts┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó pass;npx oxlinton the file ┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó no findings.npm run build:cached┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó pass.User-visible CLI output
Linux, merged head, empty cache directory:
Security, privacy, process, containment
The store remains local and owner-only. Entries are derived data and are never executed. Publishing is gated on a confirmed shutdown, a natural process exit, completed non-timed-out analysis, and no client mutation. Interrupted or forced stops never publish. Admission rejects links/reparse points and malformed expanded projects.
A rebuilt Windows root copies the stored projects into the private replacement instead of moving them, so the preserved projects carry the replacement's owner-only DACL rather than the permissions the shared root gave them. The rebuild sets the previous root aside first and removes it only after every project is copied, so a rebuild that cannot complete leaves the stored projects where they were.
Author readiness
Human owner: @goncalompontes
Review follow-up
37efe1c2danswers the review finding that the Linux run had no passing test for "a changed session does not publish".method_unavailable. The publication test covers every mutating operation and asserts the bridge answered it.npx tsc --noEmit;npx vitest run src/ghidra/projectCache src/ghidra/GhidraProjectCache.behavior.test.ts src/ghidra/GhidraProvider.behavior.test.ts(186 passed); the fake bridge mutation surface probed over a loopback transport (applied on a writable transport, refused on a read-only one); the client boundary exercised end to end against the same fixture.Not re-run here: the Linux-only
ghidraClientsocket tests still cannot run on this host: the fixture cannot publish a Windows endpoint without the native runtime, and AF_UNIX listen is denied here.Windows cache root follow-up
d4b8afbbafixes two defects that kept the cache unusable on a real Windows host, both found by running the feature end to end there.BUILTIN\Administratorsand always fails the owner-only check; the store then re-imported the target every session. Such a root is now rebuilt as a private directory: the previous root is set aside first, the stored children move into the replacement, and the replacement is verified before the previous root is removed. A rebuild that cannot complete restores the previous root and leaves the stored projects where they were.The rebuild is reported through the store, the provider log, and the session Evidence, so a rebuilt root is stated rather than applied silently.
Validation on this Windows host (Ghidra 12.1.4, JDK 21):
npx tsc --noEmit;npx oxfmt --check;npx oxlint(0 errors, the repository-wide warnings only);npm run verify:module-boundaries.npx vitest run src/ghidra┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó 769 passed, 28 skipped.npx vitest run src/ghidra/projectCache┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó 51 passed, 3 skipped.npm run test:fast┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó 10,530 passed; the same 63 pre-existing POSIX/macOS-only failures (ADB paths, Hopper, WABT, Mach-O/Electron) and no Ghidra or cache failure.Not re-run here: the native artifact build lane. It requires Linux and MinGW-w64, so the native sources are unchanged by this commit; the change uses only operations the shipped artifact already provides (
runtime_create,runtime_mkdir,runtime_close,cutter_bridge_verify_directory), each exercised against the real artifact on this host.Windows cache root repair follow-up
26d6b1c54answers the two review findings on the Windows root rebuild.SeChangeNotifyPrivilege, which bypasses the traverse check on the private parent, and a movedstagingdirectory gave every project written into it the same shared permissions. The rebuild now copies the stored projects into the private replacement, so each copy is created inside it and inherits its owner-only DACL. A link is refused instead of carried into the private root, where it would keep naming the shared directory it points at.Validation on this Windows host:
npx tsc --noEmit;npx oxfmt --check;npx oxlint(0 errors, the repository-wide warnings only);node scripts/check-doc-facts.mjs;npm run verify:module-boundaries.npx vitest run src/ghidra┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó 772 passed, 30 skipped.npx vitest run tests/acceptance/cacheVerifyCli.test.ts tests/acceptance/cachePruneCli.test.ts┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó 4 passed.Windows cache root repair failureslanes cover a preserved project that cannot be copied, a replacement that cannot be removed, and a set-aside root that cannot be removed.Not re-run here: the two POSIX-only cleanup lanes (a set-aside root that cannot be removed, and a replacement that cannot be removed) did not run on this Windows host; their expected outcomes were confirmed by forcing the removal to fail. The native artifact build lane was not re-run either: it requires Linux and MinGW-w64, and the native sources are unchanged by this commit.
Windows cache root publication follow-up
6b9c2e5b7answers the review finding that a rebuilt root could publish unfinished projects.The new regression test fails against the previous implementation: it observed a published project holding 199 of its 200 files.
Validation on this Windows host:
npx tsc --noEmit;npx oxfmt --check;npx oxlint(0 errors, the repository-wide warnings only);node scripts/check-doc-facts.mjs;npm run verify:module-boundaries.npx vitest run src/ghidra/projectCache src/ghidra/GhidraProjectCache.behavior.test.ts src/ghidra/GhidraProvider.behavior.test.ts┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó 197 passed, 5 skipped.npx vitest run src/ghidra┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó 776 passed, 30 skipped.npx vitest run tests/acceptance/cacheVerifyCli.test.ts tests/acceptance/cachePruneCli.test.ts┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó 4 passed.Windows cache root repair coordinationandWindows cache root repair lockinglanes cover a project that is published only once it is copied, a project a concurrent publisher already stored, a root another session is rebuilding, a lock a dead session left behind, and the lock released when a rebuild cannot complete.Not re-run here: the two POSIX-only cleanup lanes (a set-aside root that cannot be removed, and a replacement that cannot be removed) did not run on this Windows host; their expected outcomes were confirmed by forcing the removal to fail. The native artifact build lane was not re-run either: it requires Linux and MinGW-w64, and the native sources are unchanged by this commit.
Windows cache root repair reclamation follow-up
7f0c75843answers the review findings on the reclamation of the copies an interrupted rebuild leaves behind.<root>.repair-stagingbeside the cache root, even when REA never created it. The cache root is a path the caller chose, so a sibling of it can hold anything, and an ordinary open orcache-prunedeleted its contents. The copies now live in a staging directory inside the cache root, which is the one directory REA owns, so the reclamation only removes state REA created. A stored entry is named by its digest, so the store never counts the copies, and a rebuild does not carry over the copies a previous interrupted rebuild left behind, which were never published either.The new regression tests fail against the previous implementation: the unrelated sibling directory was deleted, and the reclamation held no lock while it removed the copies.
Validation on this Windows host:
npx tsc --noEmit;npx oxfmt --checkandnpx oxlinton the changed files;node scripts/check-doc-facts.mjs;npm run verify:module-boundaries;npm run verify:architecture-guards;npm run scan:todos;npm run knip.npx vitest run src/ghidra/projectCache┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó 65 passed, 5 skipped.npx vitest run src/ghidra┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó 784 passed, 30 skipped.npx vitest run tests/acceptance/cacheVerifyCli.test.ts tests/acceptance/cachePruneCli.test.ts┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó+┬┤ÔöÉ┬ó 4 passed.Not re-run here: the two POSIX-only cleanup lanes (a set-aside root that cannot be removed, and a replacement that cannot be removed) did not run on this Windows host; their expected outcomes were confirmed by forcing the removal to fail. The native artifact build lane was not re-run either: it requires Linux and MinGW-w64, and the native sources are unchanged by this commit.
Pre-existing on this host, not from this commit: the
publishes a preserved project only after it is copiedlane is flaky at roughly one run in thirty. A background scanner can hold the temporary cache root open, so the rename that sets the root aside fails withEPERM, and the lane then reports either a rejected rebuild or an empty publication. The same failure reproduces on the previous commit.Before merge
type(scope): outcome.docs/ghidra-project-cache.md, the installation guide, and the configuration reference are updated.Cache root ownership follow-up
d208cf012answers the three review findings on the cache root, the repairlock, and the store's working directories.
that other principals could write could hold a link at the name of one of
those directories, and the prune listed the link's target and removed what
was older than an hour in it. The store removes the link and creates its
own directory in its place, so a cleanup never reaches outside the cache
root. The copy of a published project is made inside that directory too, so
it cannot land in what the link pointed at.
is taken over is moved aside and compared with the lock that was observed,
so a takeover never removes the lock of a session that holds it, a session
releases only the lock it holds, and a repair that lost its lock stops
instead of changing a root another session is rebuilding. The lock protocol
moves to
src/ghidra/projectCache/GhidraProjectCacheLock.ts, because itowns the lock file.
published while it ran. Those entries are moved into the set-aside root
before the replacement is removed, so the rollback no longer discards a
project another session stored.
The new regression tests fail against the previous implementation: the
published entry was discarded by the rollback, the repair removed the lock of
the session that had taken it over, two sessions could take over the same
abandoned lock, and a file at the name of a working directory was not
replaced.
Validation on this Windows host:
npx tsc --noEmit┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó pass.npx oxfmt --checkandnpx oxlinton the changed files ┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó pass (0 errors,the repository-wide warnings only).
npx vitest run src/ghidra┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó 794 passed, 34 skipped.npx vitest run src/ghidra/projectCache┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó 69 passed, 7 skipped.npx vitest run tests/acceptance/cacheVerifyCli.test.ts┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó 3 passed.npx vitest run tests/acceptance/cachePruneCli.test.ts┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó 1 passed.npm run verify:module-boundaries;npm run verify:architecture-guards;npm run knip;npm run jscpd;npm run scan:todos;node scripts/check-doc-facts.mjs.Cache root working directory and POSIX follow-up (
06ef06c61,fd4428601,1e0854488)Answers the two follow-up review findings and runs the POSIX lanes the Windows
host could not run.
and comparing that entry's inode before removing it. A directory another
session created after the observation is put back, or left beside the root
when the name was taken again, so a repair never recursively removes a live
staging copy or a publisher's lock.
which blocks the move the rollback performs instead of relying on removing a
read-only child. Cleanup runs in a
finallyblock, so a failed assertion nolonger leaves a read-only tree behind.
the lock over; the file exists before its token is written, so the old wait
could overwrite the repair's token and let the repair run to completion. The
published-project lane pins its observation to one root inode, so the
repair's quarantine of the root no longer looks like a zero-file
publication.
Validation on Linux, head
1e0854488(the two POSIX-only lanes now run):npx tsc --noEmit┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó pass.npx vitest run src/ghidra/projectCache┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó 76 passed, no skips;GhidraProjectCacheRoot.test.tspassed 10 consecutive runs.npx vitest run src/ghidra┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó 827 passed, 1 skipped.npx vitest run tests/boundary/mcp/sessionMcp.test.ts tests/boundary/mcp/optionalProviderIsolation.test.ts tests/composition/directAnalysisFactories.test.ts tests/composition/directAnalysisXrefs.test.ts┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó 46 passed.npx vitest run tests/acceptance/cacheVerifyCli.test.ts tests/acceptance/cachePruneCli.test.ts┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó 4 passed.npx oxfmt --checkandnpx oxlintonsrc/ghidra/projectCache┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó pass(0 errors, the repository-wide warnings only).
npm run verify:module-boundaries┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó pass.npm run build:cached┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó pass; the acceptance lanes above ran against thebuild.
The merge at
1e0854488also resolves the conflicts withmain:src/application/DirectAnalysis.tskeeps main's native dispatch profilebinding, and
src/server/registerSessionStatusTool.tskeeps main'sprobeSessionAvailabilitywith this branch'starget_idandwait_msstatusarguments.
The two POSIX-only lanes are now covered on Linux, so the earlier "not re-run
here" note for them no longer applies.
Lease and staging follow-up (
a90a17584,aee75d863,89e9685f5)Answers the two cache findings from the latest automated review pass.
replaces the name atomically and never follows a link at the destination, so
a concurrent remove or prune never sees the lease absent while a hit is
using it, and a link planted at
leases/<key>.leasebefore the root wastightened is replaced instead of followed. Regression: a hit with a linked
lease leaves the link target unchanged and the lease a regular file.
profile digest, so a failed publish in one client cannot discard another
client's copy. Regression: two clients for one shared profile receive
distinct staging slots.
Validation on Linux, head
89e9685f5:npx tsc --noEmit┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó pass.npx vitest run src/ghidra┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó 829 passed, 1 skipped.npx vitest run src/ghidra/projectCache┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó 77 passed.npx vitest run src/ghidra/projectCache/GhidraProjectStore.test.ts src/ghidra/GhidraProvider.behavior.test.ts┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó 172 passed.npx oxfmt --checkandnpx oxlinton the changed files ┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó┬┤ÔöÉ┬ó pass (0 errors,the repository-wide warnings only).
The latest automated review also raised findings in the multi-target session
and background-analysis work that this branch now carries
(
src/application/binary/BinaryTargetRegistry.ts,src/application/binary/BinarySession.ts, andsrc/server/registerSessionTools.ts). Those are outside the cache change andare left to that work's owners.
Multi-target session follow-up (
4ec21a489)Answers the two review findings on the multi-target session work that this
branch carries (
src/application/binary/BinaryTargetRegistry.tsandsrc/application/binary/BinarySession.ts).that the retained cleanup owns, and the cleanup is retried inside the open.
With
REA_MAX_CONCURRENT_ANALYSES=1the open therefore waited for a permitthat only the open itself could give back, so a replacement open hung until
another request retried the cleanup explicitly. The registry now retries the
retained cleanup before it takes a new start permit; a successful retry
gives the permit back and stops reporting the slot as retained. One retry
runs at a time, so two overlapping opens do not close the same provider
twice.
Promise.raceleaves its reaction attached to that promise, so everyrequest that settled through the transition left a retained reaction behind
until the epoch was retired, which a long-lived session never does. The
retirement is now a removable listener: a request detaches itself when it
settles or is aborted, and the epoch keeps nothing for it.
so a provider that a retry released is not closed a second time when the
start that never unwound finally unwinds.
The new regression tests fail against the previous implementation: the
replacement open never started a second provider, the epoch kept a waiter for
a request that had already settled, and the released provider was closed
twice.
Validation on this Windows host:
npx tsc --noEmit├ö├ç├ pass.npx vitest run src/application/binary├ö├ç├ 197 passed.npx vitest run --project mcp-boundary├ö├ç├ 967 passed; the 16 failures arethe pre-existing POSIX-only failures this host already had without the
change.
npm run test:fast├ö├ç├ 12,210 passed; the 70 failures are the pre-existingPOSIX/macOS-only suites on this host (Hopper, ADB, WABT, Mach-O, Electron),
and no binary or session suite failed.
npx oxfmt --checkandnpx oxlinton the changed files ├ö├ç├ pass (0 errors,the repository-wide warnings only).
npm run verify:module-boundaries;npm run verify:architecture-guards;npm run knip;npm run scan:todos├ö├ç├ pass.Not re-run here: the POSIX-only cleanup lanes of the cache suites and the
native artifact build lane; they are unchanged by this commit.
Cancelled and closed-slot follow-up (
794e3050d)Answers the two review findings on the failed-start cleanup that the last
commit introduced.
An open that was cancelled while it waited for a start permit skipped the
cleanup of its failed start. The admission reported the failure it could
not acquire the permit for without running that cleanup, and the open
assumed the cleanup had already run: the client the open created was never
closed, and the target the open had replaced was closed and never
restored.
The session owns the cleanup of its failed start now. It runs once: the
admission runs it under the shared start limit, and a failure the
admission reported without running it runs it in the open. The admission
runs the cleanup for a start it could not attempt as well, so the limit
still counts a provider the cleanup could not release, and the slot that
owns that provider stays registered as retained.
The health probe of a client that starts the provider it selected runs
inside the admitted start now, so a probe that fails runs the cleanup of
the failed open under the limit that counts the provider the probe left
behind. The probe of a composed client answers without touching a child,
so the limit is not held for a provider start that never ran.
The cleanup of a failed start restored the target the open replaced before
the open checked whether it had been retired. A forced close that
released the start while it was in flight therefore left the closed slot
holding a target again, and a target that opened in that slot afterwards
could have its binding overwritten.
The cleanup restores the target only while the slot still owns it. The
lifecycle generation of the open is checked before the restoration and
again after it waited for the restored client, so a slot that was closed
while the restoration waited releases the restored client instead of
binding it.
The new regression tests fail against the previous implementation: the client
of a cancelled open was never closed, the target it replaced was never
restored, and a closed slot held the target it had before the failed open.
Validation on this Windows host:
npx tsc --noEmit- pass.npx vitest run src/application/binary src/server tests/composition/analysis-sessions- 434 passed.npx vitest run tests/boundary/mcp- the 16 failures are the pre-existing POSIX-only failures this host already had without the change.npx oxfmt --checkandnpx oxlinton the changed files - pass (0 errors, the repository-wide warnings only).npm run check:fast;npm run verify:module-boundaries;npm run verify:architecture-guards;npm run scan:todos;npm run knip;node scripts/check-doc-facts.mjs- pass.Restored start limit follow-up (
1cd961008)Answers the review finding that a restored target starts its provider outside
the shared start limit.
A cancelled replacement waits for a start permit, and the admission runs the
cleanup of that failed open, which restores the target the open replaced. The
restoration created its client without the start admission, so the provider
start that client defers ran outside the shared limit: a query on the
restored target launched an import beside a provider that was still
starting, and the analysis cap that bounds the concurrent analyses was
exceeded.
The session keeps the admission the open carries and hands it to the restored
client, so the restored target starts its provider under the same limit as
every other start of the session. The restoration does not start the provider
under that admission: the health probe of a composed client answers without
touching a child, and a probe that waited for the limit would make a
cancelled open wait for a permit it cannot use.
The new regression test fails against the previous implementation: the query on
the restored target did not run under the admission.
Validation on this Windows host:
npx tsc --noEmit- pass.npx vitest run src/application/binary- 230 passed.npx vitest run src/application/binary src/server tests/composition/analysis-sessions- 435 passed.npx vitest run src/ghidra- 801 passed, 35 skipped.npx vitest run --project mcp-boundary- the failing suites are the POSIX-only and the WABT/IDA suites this Windows host cannot run; the same suites fail without the change.npx oxfmt --checkandnpx oxlinton the changed files - pass (0 errors, the repository-wide warnings only).npm run check:fast;npm run verify:module-boundaries;npm run verify:architecture-guards;npm run scan:todos;npm run knip;node scripts/check-doc-facts.mjs- pass.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.