[PR #1149] [MERGED] fix(evidence): cancel exports before atomic publication #2683

Closed
opened 2026-10-17 21:09:01 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/1149
Author: @N0zoM1z0
Created: 10/9/2026
Status: ✅ Merged
Merged: 10/9/2026
Merged by: @N0zoM1z0

Base: main ← Head: fix/evidence-export-cancellation


📝 Commits (1)

  • 9812462 fix(evidence): cancel exports before atomic publication

📊 Changes

6 files changed (+308 additions, -16 deletions)

View changed files

📝 docs/mcp-contracts.md (+2 -0)
📝 src/application/EvidenceBundleFiles.ts (+11 -1)
📝 src/application/JsonFiles.ts (+78 -14)
📝 src/server/registerSessionRecordTools.ts (+2 -1)
📝 tests/boundary/filesystem/evidenceBundleFiles.test.ts (+106 -0)
➕ tests/boundary/mcp/evidenceExportCancellation.test.ts (+109 -0)

📄 Description

Summary

Cancelling export_evidence_bundle rejected the client promise while REA continued serializing and publishing the file. Forward request cancellation through the shared file writer and stop before advancing the source, writing further parts, or submitting atomic publication. Progress on #1065.

Problem and expected behavior

A complete native Windows Notion ASAR baseline rejected cancellation in 1.829 ms, then continued for 33.854 seconds and published all 336,236,424 bytes. An analyst should be able to cancel an export, keep the existing destination and retained Evidence, and continue using the same session.

Change and scope

  • Pass the pinned SDK's context.mcpReq.signal to the application export workflow.
  • Check cancellation before validation for already cancelled requests, between serialized parts, and immediately before atomic publication. Close interrupted source iterators and keep the existing staged-file cleanup.
  • Preserve canonical bytes, the one-part streaming memory model, caller-selected paths, no-overwrite atomic linking and overwrite atomic renaming. Successful publication can win cancellation that arrives after the filesystem operation is submitted.
  • Preserve existing no-signal writer callers and their error types. Cancellation is returned through the existing tagged error contract.

Observed native cancellation behavior, with 20 ms filesystem polling granularity:

Target / destination Before: cancellation to staged-content removal After: cancellation to staged-content removal After: complete staging-directory removal
Notion / new destination 33,854 ms; full file published 29 ms; no publication 29 ms
Obsidian / existing destination 40,374 ms; original replaced 39 ms; original preserved 69 ms

Baseline probes timed staged-content removal and subsequently checked complete directory cleanup; they did not separately time directory removal. These are guarded acceptance observations rather than universal latency bounds. Whole-analysis/export timings vary with host load; this PR does not claim a parser or successful-export throughput improvement.

Contract and boundary impact

  • Semantic owner and earliest changed stage: MCP request control is forwarded to the shared application export/file boundary.
  • CLI and MCP/tool-catalog contract: no schema, field, inventory or named-handler changes; successful complete export data and CLI behavior remain unchanged.
  • Provider, bridge, target-format, or platform compatibility: no provider changes. Complete real native Windows packaged Notion and Obsidian ASAR workflows passed.
  • Evidence, artifact, provenance, or reconstruction contract: retained Evidence is unchanged. Interrupted exports do not publish a partial bundle.
  • Process execution, authorization, cleanup, or containment impact: no new processes or authority; owned staging cleanup and original destination preservation are tested.
  • Generated metadata, package, or installation impact: no committed generated files or version bump.

Representative request:

{
  "name": "export_evidence_bundle",
  "arguments": { "path": "<absolute-bundle-path>" }
}

Evidence and regression coverage

  • Tests added or updated: already cancelled requests without source/path effects; mid-stream cancellation for new and existing destinations; iterator closure; cancellation at source exhaustion; preserved canonical round trips and subsequent writes.
  • Pinned SDK integration observes actual staged bytes before sending cancellation, checks staging removal and the original destination, then pings and performs a complete second export in the same session. Client-local rejection alone is not acceptance.
  • Base reproduction or other evidence: native Windows full Notion baseline above. The corresponding export, serialization and JavaScript application sources are unchanged between that installed baseline and frozen branch base 441813c0.
  • User-visible CLI/MCP output: successful export still returns its selected path, complete byte count and record/unknown counts; cancellation uses the existing cancelled error category.
  • Remaining proof gaps: final installed-package verification, both complete native Windows baseline/candidate comparisons, and all 22 exact-head CI checks passed. Synchronous source parsing/graph constructors and external-client waiting remain separate #1065 tasks.

For evidence-bearing changes:

  • Observed, derived, and inferred claims remain distinguishable.
  • Artifact identity, source provenance, and failed attempts remain preserved.
  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

  • npm run build:cached — passed with bounded local Node/native-TypeScript budgets and two-CPU affinity.
  • npm run check -- --concurrency=1 — all six static tasks passed.
  • npm run test:focused -- tests/boundary/filesystem/evidenceBundleFiles.test.ts tests/boundary/mcp/evidenceExportCancellation.test.ts — all 16 tests passed; final run family RSS peak 848,035,840 bytes.
  • npm run docs:check — passed.
  • git diff --check — passed.
  • Complete installed-package CLI/MCP verifier — passed in 218.554 s; process-family RSS peak 1,520,533,504 bytes, minimum host available 8,921,317,376 bytes. Complete catalog (138 tools), installation/update/setup, Evidence and CLI/MCP lifecycle checks passed.
  • Real native Windows final installed package — both complete Notion and Obsidian workflows passed with two-CPU affinity, BelowNormal priority, a 1.5 GiB Node heap and guarded memory/disk reserves. Cancellation preserved the original destination, removed owned staging and allowed complete subsequent export, trace, ping and close in the same session. All 336,236,424 / 429,232,879 exported bytes match the corresponding baseline SHA-256 exactly; Evidence IDs and complete selected trace digests also match. Compare the same pre-trace ledger checkpoint because trace requests retain additional Evidence.
  • Native process-family working-set peaks — 1,399,402,496 / 1,633,468,416 bytes. Minimum free host memory — 5,450,117,120 / 2,707,415,040 bytes. Both runs exited zero without supervisor errors or a resource stop; large exports were deleted after verification.
  • CI — all 22 checks passed on 9812462c, including test shards/coverage, Linux and macOS x64/arm64 package baselines, Windows package/capability checks, and real Apple artifact CLI/MCP checks.

Compatibility, safety, and release

  • Breaking changes or migration steps: none; complete public data shapes and canonical bytes are preserved.
  • Real Hopper/Ghidra, browser, or OS coverage: no real Hopper/Ghidra/browser verification for this file-export change. Native Windows real-app workflows are being verified separately.
  • Package or release metadata impact: candidate uses the existing development package version; no published-fix claim.
  • Security, privacy, process, or containment review: no target execution, extra permissions or truncation. Tests use isolated caller-selected output directories and resource guards; public records contain no host paths or credentials.

Review checklist

  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/1149 **Author:** [@N0zoM1z0](https://github.com/N0zoM1z0) **Created:** 10/9/2026 **Status:** ✅ Merged **Merged:** 10/9/2026 **Merged by:** [@N0zoM1z0](https://github.com/N0zoM1z0) **Base:** `main` ← **Head:** `fix/evidence-export-cancellation` --- ### 📝 Commits (1) - [`9812462`](https://github.com/morluto/rea/commit/9812462c780b2d45de9df154d99647f27a9ab7ad) fix(evidence): cancel exports before atomic publication ### 📊 Changes **6 files changed** (+308 additions, -16 deletions) <details> <summary>View changed files</summary> 📝 `docs/mcp-contracts.md` (+2 -0) 📝 `src/application/EvidenceBundleFiles.ts` (+11 -1) 📝 `src/application/JsonFiles.ts` (+78 -14) 📝 `src/server/registerSessionRecordTools.ts` (+2 -1) 📝 `tests/boundary/filesystem/evidenceBundleFiles.test.ts` (+106 -0) ➕ `tests/boundary/mcp/evidenceExportCancellation.test.ts` (+109 -0) </details> ### 📄 Description ## Summary Cancelling `export_evidence_bundle` rejected the client promise while REA continued serializing and publishing the file. Forward request cancellation through the shared file writer and stop before advancing the source, writing further parts, or submitting atomic publication. Progress on #1065. ## Problem and expected behavior A complete native Windows Notion ASAR baseline rejected cancellation in 1.829 ms, then continued for 33.854 seconds and published all 336,236,424 bytes. An analyst should be able to cancel an export, keep the existing destination and retained Evidence, and continue using the same session. ## Change and scope - Pass the pinned SDK's `context.mcpReq.signal` to the application export workflow. - Check cancellation before validation for already cancelled requests, between serialized parts, and immediately before atomic publication. Close interrupted source iterators and keep the existing staged-file cleanup. - Preserve canonical bytes, the one-part streaming memory model, caller-selected paths, no-overwrite atomic linking and overwrite atomic renaming. Successful publication can win cancellation that arrives after the filesystem operation is submitted. - Preserve existing no-signal writer callers and their error types. Cancellation is returned through the existing tagged error contract. Observed native cancellation behavior, with 20 ms filesystem polling granularity: | Target / destination | Before: cancellation to staged-content removal | After: cancellation to staged-content removal | After: complete staging-directory removal | | --- | --- | --- | --- | | Notion / new destination | 33,854 ms; full file published | 29 ms; no publication | 29 ms | | Obsidian / existing destination | 40,374 ms; original replaced | 39 ms; original preserved | 69 ms | Baseline probes timed staged-content removal and subsequently checked complete directory cleanup; they did not separately time directory removal. These are guarded acceptance observations rather than universal latency bounds. Whole-analysis/export timings vary with host load; this PR does not claim a parser or successful-export throughput improvement. ## Contract and boundary impact - Semantic owner and earliest changed stage: MCP request control is forwarded to the shared application export/file boundary. - CLI and MCP/tool-catalog contract: no schema, field, inventory or named-handler changes; successful complete export data and CLI behavior remain unchanged. - Provider, bridge, target-format, or platform compatibility: no provider changes. Complete real native Windows packaged Notion and Obsidian ASAR workflows passed. - Evidence, artifact, provenance, or reconstruction contract: retained Evidence is unchanged. Interrupted exports do not publish a partial bundle. - Process execution, authorization, cleanup, or containment impact: no new processes or authority; owned staging cleanup and original destination preservation are tested. - Generated metadata, package, or installation impact: no committed generated files or version bump. Representative request: ```json { "name": "export_evidence_bundle", "arguments": { "path": "<absolute-bundle-path>" } } ``` ## Evidence and regression coverage - Tests added or updated: already cancelled requests without source/path effects; mid-stream cancellation for new and existing destinations; iterator closure; cancellation at source exhaustion; preserved canonical round trips and subsequent writes. - Pinned SDK integration observes actual staged bytes before sending cancellation, checks staging removal and the original destination, then pings and performs a complete second export in the same session. Client-local rejection alone is not acceptance. - Base reproduction or other evidence: native Windows full Notion baseline above. The corresponding export, serialization and JavaScript application sources are unchanged between that installed baseline and frozen branch base `441813c0`. - User-visible CLI/MCP output: successful export still returns its selected path, complete byte count and record/unknown counts; cancellation uses the existing `cancelled` error category. - Remaining proof gaps: final installed-package verification, both complete native Windows baseline/candidate comparisons, and all 22 exact-head CI checks passed. Synchronous source parsing/graph constructors and external-client waiting remain separate #1065 tasks. For evidence-bearing changes: - [x] Observed, derived, and inferred claims remain distinguishable. - [x] Artifact identity, source provenance, and failed attempts remain preserved. - [x] Unsupported, incomplete, unavailable, or uncertain outcomes remain visible. ## Validation performed - `npm run build:cached` — passed with bounded local Node/native-TypeScript budgets and two-CPU affinity. - `npm run check -- --concurrency=1` — all six static tasks passed. - `npm run test:focused -- tests/boundary/filesystem/evidenceBundleFiles.test.ts tests/boundary/mcp/evidenceExportCancellation.test.ts` — all 16 tests passed; final run family RSS peak 848,035,840 bytes. - `npm run docs:check` — passed. - `git diff --check` — passed. - Complete installed-package CLI/MCP verifier — passed in 218.554 s; process-family RSS peak 1,520,533,504 bytes, minimum host available 8,921,317,376 bytes. Complete catalog (138 tools), installation/update/setup, Evidence and CLI/MCP lifecycle checks passed. - Real native Windows final installed package — both complete Notion and Obsidian workflows passed with two-CPU affinity, BelowNormal priority, a 1.5 GiB Node heap and guarded memory/disk reserves. Cancellation preserved the original destination, removed owned staging and allowed complete subsequent export, trace, ping and close in the same session. All 336,236,424 / 429,232,879 exported bytes match the corresponding baseline SHA-256 exactly; Evidence IDs and complete selected trace digests also match. Compare the same pre-trace ledger checkpoint because trace requests retain additional Evidence. - Native process-family working-set peaks — 1,399,402,496 / 1,633,468,416 bytes. Minimum free host memory — 5,450,117,120 / 2,707,415,040 bytes. Both runs exited zero without supervisor errors or a resource stop; large exports were deleted after verification. - CI — all 22 checks passed on `9812462c`, including test shards/coverage, Linux and macOS x64/arm64 package baselines, Windows package/capability checks, and real Apple artifact CLI/MCP checks. ## Compatibility, safety, and release - Breaking changes or migration steps: none; complete public data shapes and canonical bytes are preserved. - Real Hopper/Ghidra, browser, or OS coverage: no real Hopper/Ghidra/browser verification for this file-export change. Native Windows real-app workflows are being verified separately. - Package or release metadata impact: candidate uses the existing development package version; no published-fix claim. - Security, privacy, process, or containment review: no target execution, extra permissions or truncation. Tests use isolated caller-selected output directories and resource guards; public records contain no host paths or credentials. ## Review checklist - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [x] User-visible CLI/MCP changes include representative output. - [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-17 21:09:01 +00:00
Sign in to join this conversation.
No milestone
No project
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#2683
No description provided.