Repository navigation
fix(cli): keep captured source Evidence when one-shot delivery never commits - #8632
Merged
Merged
Conversation
…commits A completed observation that was cancelled at final close, failed cleanup, or never reached bundle commit returned its evidence links but dropped the source records the invocation had already captured. The caller could neither read those records nor tell whether they were missing, captured or written. Report the closure at publishCliAnalysisEvidence, the shared boundary every --evidence_output command uses. details.source_closure carries authentic captured records within 64 KiB and explicit omissions: not_captured for a link this invocation holds no record for, and not_inlined for a captured record outside this response. A committed bundle keeps its receipt instead, nothing is written after cancellation, and successful delivery is unchanged. Fixes #8589 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
[Medium impact] The PR appears safe to merge; no new actionable issues were found. SummaryAdds bounded
Diagram%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Completed Evidence] --> B{Final close succeeds?}
B -->|No or cancelled| C[Original typed failure]
B -->|Yes| D[Select view and publish bundle]
D -->|Failure before commit| C
C --> E[Authenticate partial observation]
E --> F[Attach bounded source_closure]
D -->|Failure after commit| G[Keep published receipt]
D -->|Success| H[Return existing success output]
Reviews (3) · Last reviewed commit: "fix(cli): keep the typed failure when co..." · Reviewed by Greptile |
…t finish A captured source with a data-sized evidence_links array made pending.push(...links) exceed V8's call-argument limit. On final-close cancellation or a refused publication that RangeError replaced the original typed failure, which is the one outcome this delivery step exists to preserve. Walk the closure through a Set, which is a deduplicating breadth-first queue, so no link becomes a call argument and each link costs one lookup however often it repeats. undeliveredSourceClosure now owns authentication and never throws: if examining the closure fails, it reports collection_failure with the bounded error type and an unknown closure state, and the original failure is still returned. Fault the final-close tests on the scope the command gave to matching, after matching completed, and assert that close was reached, so a moved close fails instead of passing on an earlier one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
coyoteXujie
pushed a commit
to coyoteXujie/rea
that referenced
this pull request
Nov 2, 2026
…commits (morluto#8632) * fix(cli): keep captured source Evidence when one-shot delivery never commits A completed observation that was cancelled at final close, failed cleanup, or never reached bundle commit returned its evidence links but dropped the source records the invocation had already captured. The caller could neither read those records nor tell whether they were missing, captured or written. Report the closure at publishCliAnalysisEvidence, the shared boundary every --evidence_output command uses. details.source_closure carries authentic captured records within 64 KiB and explicit omissions: not_captured for a link this invocation holds no record for, and not_inlined for a captured record outside this response. A committed bundle keeps its receipt instead, nothing is written after cancellation, and successful delivery is unchanged. Fixes morluto#8589 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): keep the typed failure when collecting source closure cannot finish A captured source with a data-sized evidence_links array made pending.push(...links) exceed V8's call-argument limit. On final-close cancellation or a refused publication that RangeError replaced the original typed failure, which is the one outcome this delivery step exists to preserve. Walk the closure through a Set, which is a deduplicating breadth-first queue, so no link becomes a call argument and each link costs one lookup however often it repeats. undeliveredSourceClosure now owns authentication and never throws: if examining the closure fails, it reports collection_failure with the bounded error type and an unknown closure state, and the original failure is still returned. Fault the final-close tests on the scope the command gave to matching, after matching completed, and assert that close was reached, so a moved close fails instead of passing on an earlier one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What broke: A completed one-shot observation cancelled at final close (or whose cleanup failed, or whose bundle never committed) kept its Evidence links but dropped the captured source records, with no statement of what happened to them.
The fix:
publishCliAnalysisEvidence, the shared--evidence_outputboundary, now addsdetails.source_closureto those failures: authentic captured records within 64 KiB, plus explicitnot_capturedandnot_inlinedomissions.The risk: Low. Only failures with a requested, uncommitted bundle and a completed Evidence observation change; successful delivery was byte-identical to base in a real-process comparison, and nothing is written after cancellation.
Summary
Fixes #8589
The report was observed on draft heads #8585 and #8588, whose
includeEvidenceSourcesandrea trace --evidence_outputare not on main. The same defect does ship on main at the same boundary:match-native-functions --evidence_outputcaptures its source closure and passes it topublishCliAnalysisEvidence, whose failure branch returned the projected error without it.Problem and expected behavior
Smallest trigger on main:
rea match-native-functions REQUEST --source_bundle SOURCES --evidence_output OUT --json, with SIGINT arriving at the start of finalArtifactResourceScope.close(). Close succeeds. The result iscancelledwithdetails.partial_observation.evidence_links, but no source record, no bundle and no statement about those sources.Violated invariant (own the lifecycle): completed facts survive later cancellation or finalization through typed failures, with explicit coverage. Expected: keep or explicitly describe the closure, without turning cancellation into delivery, writing after cancellation, overstating retention or sending an unbounded error.
Change and scope
undeliveredSourceClosureinAnalysisEvidenceSources.tswalks the observation's links and the captured records breadth-first through aSet, so no link becomes a call argument and each link costs one lookup however often it repeats. Records go inline until 64 KiB (the allowance used for other retained process diagnostics; a record that does not fit is skipped, so smaller later records can still fit). Up to 64 omissions are listed andomitted_counthas the total.publishCliAnalysisEvidenceattaches it to every failure before commit: final-close cancellation, cleanup failure, cancellation during publication, an existing output file, and a refused view. Every--evidence_outputcommand that returns its failure through this function gets this.evidenceDeliveryCommitted), so nosource_closureis added.collection_failurenames the error type (not its message), the closure state is unknown, and the original failure is still returned.not_capturednever fabricates a record, and the ancestors of such a link stay unknown. Embeddedinspect_artifactsources are not duplicated. With explicitsensitiveValues, captured records stay out of error output asnot_inlined.Not included:
rea function --evidence_outputand similar direct commands do not capture linked sources on main, on success either (source-derived fromcoreBinaryCommands.ts). Failures now report those links asnot_captured. Changing what success delivers is outside this fix.sourceEvidenceon failure to get records rather thannot_captured.runAnalysison those heads returns sources only on success.inspect-with-objdumpandcapture-browser-scenarioreturn failures without calling this function, andinspect_managed_membersdelivers throughdeliverAnalysisEvidence. A source search found no linked or captured sources in their producers, so they are unchanged (source-derived, not executed).Scope decision: not applicable; this is an ordinary fix within existing read-only boundaries.
Contract and boundary impact
AnalysisEvidenceSources.tsowns the closure;publishCliAnalysisEvidenceis the delivery consumer.finishAnalysisCommandandrunAnalysisare unchanged. No superseded path to remove;isObjectis now exported rather than duplicated.details.source_closureon the qualifying CLI failures, documented indocs/cli.md.code,retryable,remediationand exit status are unchanged. MCP and the catalog are unchanged.parseEvidence); an unauthenticated observation cannot select sources.Expected effects (check known effects; use documentation-only on its own).
Unchecked items do not establish absence; leave uncertainties visible.
Evidence and regression coverage
tests/process-global/oneShotSourceClosure.test.tsdrives the registered command through real final close: interrupt, cleanup failure, both together, summary delivery with clean retry, an oversized source, a dependency with 200,000 links, and the success control. The fault fires only on the scope the command gave to matching, after matching completed, and every run asserts that close was reached once; another test closes an unrelated scope first.tests/boundary/filesystem/undeliveredSourceClosure.test.tscovers never-captured and transitive links, the size and omission bounds, explicit exclusions, embedded sources, cancellation before commit, an existing output, late cancellation and cleanup failure after commit, untouched failures, tampered observations, 200,000-entry link sets, exceptions during collection,deliverCliAnalysisEvidence, and productionrunDirectAnalysiswith a synthetic provider.createClifromdist/cli.js, real SIGINT sent by a wrapper at the start of real final close, synthetic Evidence inputs):complete: truecmpidenticalcmpidenticalApart from
source_closure, the base and fixed interrupt errors compared equal as parsed JSON. The wrapper fires on the first scope close; both interrupt runs recorded exactly one, and the completed observation was present.srcrestored fromorigin/main: 8 of 9 process-global and 19 of 24 boundary tests failed. The tests that passed are controls for unchanged behavior.With
srcfrom the previous head 2f3ba28, 2 of 9 process-global and 5 of 24 boundary tests failed. The registered command printed{"code":"UNKNOWN","message":"Maximum call stack size exceeded"}in place of the typedcancelledorcleanup_incompleteresult. Faulting the first close instead of the final one failed the unrelated-scope test, and forcingevidenceDeliveryCommittedto false failed both commit-receipt tests.Records are abbreviated here; each is the complete Evidence record.
trace_featureflow in the report exists only on the drafts and was not run; thematch-native-functionsruns andrunDirectAnalysistests use synthetic inputs and a synthetic provider.scripts/rea.mjsruntime was not exercised under cancellation, because the wrapper patches the per-moduledistcopy. Only its ordinary success path ran.collection_failurecovers thrown errors. Heap exhaustion cannot be caught; authenticating here costs the same as theparseEvidencecall on the success path.Lifecycle regressions covered: cancellation during final cleanup and during publication, cleanup failure after success, committed output followed by cancellation or incomplete cleanup, and retry after failure. Boundary regressions covered: malformed and non-Evidence observations, capacity bounds, and explicit omission.
For evidence-bearing changes:
Validation performed
npm run check:fast— passednpm run format:check— passednpm run docs:check— passednpm run metadata:check— passednpx vitest run --project boundary --project cli-boundary --project process-global --project composition --project acceptanceon the 13 related files, includingevidenceBundleFiles,commandEvidenceDelivery,evidenceOutputPublicationCli,finishAnalysisCommand,commandFinalizationCancellation,historicalCaptureSnapshotRedaction,webCaptureDeliveryRedactionand acceptancenativeFunctionMatching— 13 files and 176 tests passednpm run build:cached— results as tabulatedCompatibility, safety, and release
omittedare digests. No new files, processes or network use.Author readiness
Human owner: @kaoru0822-kitauji
Declarations entered by Claude Code on the owner's standing written instruction.
Before merge
type(scope): outcome.🤖 Generated with Claude Code