[GH-ISSUE #7371] [Bug] Process comparison accepts conflicting final filesystem snapshots and reports unchanged #4380

Open
opened 2026-10-31 00:49:22 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 27, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/7371

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Process capture or runtime observation

Observed behavior

node scripts/rea.mjs compare-process-captures "$WORK/baseline.json" "$WORK/contradictory.json" --json accepts a caller-authored capture whose files_after and filesystem_effects record a created file while its final filesystem checkpoint is empty. The CLI exits 0 with overall and filesystem status unchanged and no first divergence. Putting the same file and effect into the final checkpoint makes the comparison report changed.

Reproduction

From a fresh checkout at the source revision below, use Node 24.22.1 and prepare the runtime with npm ci && npm run build:cached. Verification used existing locked dependencies and rebuilt the runtime; the lockfile had not changed. Run this from the checkout root. It generates all synthetic Evidence inline, isolates home/config/data/cache/state/temp folders under $WORK, and launches no target or analysis provider. The failing case and consistent control each reproduced in both of two runs.

set -eu
export WORK="${WORK:-$PWD/work}"
mkdir -p "$WORK"/home "$WORK"/config "$WORK"/data "$WORK"/cache "$WORK"/state "$WORK"/tmp
export HOME="$WORK/home" XDG_CONFIG_HOME="$WORK/config" XDG_DATA_HOME="$WORK/data" XDG_CACHE_HOME="$WORK/cache" XDG_STATE_HOME="$WORK/state" TMPDIR="$WORK/tmp"
node --input-type=module <<'JS'
import {writeFileSync} from 'node:fs';
import {EMPTY_PROCESS_CAPTURE_EXAMPLE as example} from './dist/domain/process/processCaptureExample.js';
import {parseProcessCapture} from './dist/domain/process/processCaptureParsing.js';
import {createEvidence} from './dist/domain/evidence.js';
import {PROCESS_PROVIDER} from './dist/domain/process/processEvidenceProvider.js';
const file={path:'root_0:created.txt',type:'file',mode:0o100644,size:4,sha256:'b'.repeat(64),symlink_target:null};
const effect={path:file.path,status:'created',before:null,after:file};
for(const kind of ['baseline','contradictory','consistent']) {
  const raw=structuredClone(example);
  if(kind!=='baseline') {
    raw.files_after=[file]; raw.filesystem_effects=[effect];
    raw.truncation_details.filesystem_after.hashed_bytes=4;
  }
  if(kind==='consistent') {
    raw.filesystem_checkpoints[1].files=[file];
    raw.filesystem_checkpoints[1].effects=[effect];
  }
  const result=parseProcessCapture(raw);
  const evidence=createEvidence(undefined,PROCESS_PROVIDER,{
    predicateType:'rea.process-capture',operation:'capture_process_scenario',
    parameters:{fixture:kind},result,confidence:'observed',authority:'controlled-replay',
    environment:{id:'synthetic-fixture',platform:'fixture',architecture:'fixture',isolation:'process'},limitations:result.limitations
  });
  writeFileSync(`${process.env.WORK}/${kind}.json`,JSON.stringify(evidence));
  console.log(kind,'accepted','files_after',result.files_after.length,'checkpoint_files',result.filesystem_checkpoints[1].files.length);
}
JS
for kind in contradictory consistent; do
  node scripts/rea.mjs compare-process-captures "$WORK/baseline.json" "$WORK/$kind.json" --json > "$WORK/$kind-comparison.json"
done
node --input-type=module <<'JS'
import {readFileSync} from 'node:fs';
for(const kind of ['contradictory','consistent']) {
  const r=JSON.parse(readFileSync(`${process.env.WORK}/${kind}-comparison.json`,'utf8')).normalized_result;
  console.log(kind,JSON.stringify({status:r.status,filesystem:r.filesystem,first_divergence:r.first_divergence.status}));
}
JS

Expected behavior

A semantically accepted capture should describe the same final filesystem state in its top-level fields and final checkpoint. Reject this contradiction with a typed validation issue, or otherwise ensure comparison cannot report unchanged while the accepted capture's final facts record a creation. The consistent created-file control should remain changed.

At the stated revision, docs/process-capture.md:128-135,245-249 directs callers to files_after for observed full-file digests and describes before/after snapshots and classified effects. The native producer uses the same snapshots for both representations: src/process/capture/ProcessHarness.ts:614-629 creates checkpoint files/effects, and src/process/capture/ProcessCaptureLifecycle.ts:371-375 stores their top-level counterparts. src/domain/process/processCaptureParsing.ts:6-22 describes its parsed output as semantically verified and promises rejection of invalid semantics.

Impact and scope

P2: an imported capture can present two incompatible final filesystem states while the public comparison issues an unchanged result. This is a bounded result-integrity failure in caller-authored synthetic Evidence; native producer frequency and downstream reconstruction behavior were not tested. The conflicting facts remain available for manual inspection, so checking top-level arrays against their checkpoints exposes this case. No security boundary crossing or target data loss was observed.

REA version

Exact node scripts/rea.mjs --version output: 6.8.0. Source commit: ec40c10749b5c4091fb08bc28c6f3f38c2a6968e (fetched main).

Runtime and platform

Node.js v24.22.1; macOS 27.0.1; darwin, arm64 (measured). No native analysis engine was used.

Target and artifact context

Three synthetic process-capture Evidence records based on src/domain/process/processCaptureExample.ts, with matching commitments and complete coverage accounting. One regular-file record has a synthetic four-byte size and digest; no actual created file or live capture is claimed. Only the contradictory fixture disagrees between its top-level final facts and final checkpoint.

Interface

CLI

Earliest failure stage

Request parsing or validation

Relevant output or evidence

Both CLI comparisons exited 0. The fixture generator directly calls the production parser before wrapping the records in content-authenticated Evidence; CLI import independently admits those records. Selected output:

baseline accepted files_after 0 checkpoint_files 0
contradictory accepted files_after 1 checkpoint_files 0
consistent accepted files_after 1 checkpoint_files 1
contradictory {"status":"unchanged","filesystem":"unchanged","first_divergence":"none"}
consistent {"status":"changed","filesystem":"changed","first_divergence":"found"}

Typed outcome or recovery expected

Return an explicit invalid-capture/semantic validation failure for the conflicting facts, preserving the valid consistent control. Do not silently discard the top-level observations or treat the contradiction as proof of equivalence.

Analysis or suspected cause

Source-derived: src/domain/process/processCaptureValidation.ts:246-266,349-416 checks checkpoint ordering/truncation and top-level filesystem coverage without reconciling their contents or effects. src/domain/process/processComparison.ts:131-150 uses only filesystem_checkpoints for filesystem comparison. The supported import path at src/application/process/ProcessEvidence.ts:45-78 validates Evidence integrity, workflow, provider and capture semantics, but the missing invariant lets both versions of the final state through.

Additional context

Related closed #6218 and merged #6298 address inconsistent aggregate statuses in imported comparison Evidence; this report concerns inconsistent snapshot facts inside imported capture Evidence. Closed #3180 concerns ignored checkpoint timestamps under a passing trace; this reproduction uses no trace and equal checkpoint times. No matching open duplicate was found. Native capture, MCP transport, trace evaluation, downstream verification and a post-fix restoration run were not executed.

Originally created by @coygeek on GitHub (Oct 27, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7371 ## Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ## Area Process capture or runtime observation ## Observed behavior `node scripts/rea.mjs compare-process-captures "$WORK/baseline.json" "$WORK/contradictory.json" --json` accepts a caller-authored capture whose `files_after` and `filesystem_effects` record a created file while its final filesystem checkpoint is empty. The CLI exits 0 with overall and filesystem status `unchanged` and no first divergence. Putting the same file and effect into the final checkpoint makes the comparison report `changed`. ## Reproduction From a fresh checkout at the source revision below, use Node 24.22.1 and prepare the runtime with `npm ci && npm run build:cached`. Verification used existing locked dependencies and rebuilt the runtime; the lockfile had not changed. Run this from the checkout root. It generates all synthetic Evidence inline, isolates home/config/data/cache/state/temp folders under `$WORK`, and launches no target or analysis provider. The failing case and consistent control each reproduced in both of two runs. ```sh set -eu export WORK="${WORK:-$PWD/work}" mkdir -p "$WORK"/home "$WORK"/config "$WORK"/data "$WORK"/cache "$WORK"/state "$WORK"/tmp export HOME="$WORK/home" XDG_CONFIG_HOME="$WORK/config" XDG_DATA_HOME="$WORK/data" XDG_CACHE_HOME="$WORK/cache" XDG_STATE_HOME="$WORK/state" TMPDIR="$WORK/tmp" node --input-type=module <<'JS' import {writeFileSync} from 'node:fs'; import {EMPTY_PROCESS_CAPTURE_EXAMPLE as example} from './dist/domain/process/processCaptureExample.js'; import {parseProcessCapture} from './dist/domain/process/processCaptureParsing.js'; import {createEvidence} from './dist/domain/evidence.js'; import {PROCESS_PROVIDER} from './dist/domain/process/processEvidenceProvider.js'; const file={path:'root_0:created.txt',type:'file',mode:0o100644,size:4,sha256:'b'.repeat(64),symlink_target:null}; const effect={path:file.path,status:'created',before:null,after:file}; for(const kind of ['baseline','contradictory','consistent']) { const raw=structuredClone(example); if(kind!=='baseline') { raw.files_after=[file]; raw.filesystem_effects=[effect]; raw.truncation_details.filesystem_after.hashed_bytes=4; } if(kind==='consistent') { raw.filesystem_checkpoints[1].files=[file]; raw.filesystem_checkpoints[1].effects=[effect]; } const result=parseProcessCapture(raw); const evidence=createEvidence(undefined,PROCESS_PROVIDER,{ predicateType:'rea.process-capture',operation:'capture_process_scenario', parameters:{fixture:kind},result,confidence:'observed',authority:'controlled-replay', environment:{id:'synthetic-fixture',platform:'fixture',architecture:'fixture',isolation:'process'},limitations:result.limitations }); writeFileSync(`${process.env.WORK}/${kind}.json`,JSON.stringify(evidence)); console.log(kind,'accepted','files_after',result.files_after.length,'checkpoint_files',result.filesystem_checkpoints[1].files.length); } JS for kind in contradictory consistent; do node scripts/rea.mjs compare-process-captures "$WORK/baseline.json" "$WORK/$kind.json" --json > "$WORK/$kind-comparison.json" done node --input-type=module <<'JS' import {readFileSync} from 'node:fs'; for(const kind of ['contradictory','consistent']) { const r=JSON.parse(readFileSync(`${process.env.WORK}/${kind}-comparison.json`,'utf8')).normalized_result; console.log(kind,JSON.stringify({status:r.status,filesystem:r.filesystem,first_divergence:r.first_divergence.status})); } JS ``` ## Expected behavior A semantically accepted capture should describe the same final filesystem state in its top-level fields and final checkpoint. Reject this contradiction with a typed validation issue, or otherwise ensure comparison cannot report unchanged while the accepted capture's final facts record a creation. The consistent created-file control should remain changed. At the stated revision, `docs/process-capture.md:128-135,245-249` directs callers to `files_after` for observed full-file digests and describes before/after snapshots and classified effects. The native producer uses the same snapshots for both representations: `src/process/capture/ProcessHarness.ts:614-629` creates checkpoint files/effects, and `src/process/capture/ProcessCaptureLifecycle.ts:371-375` stores their top-level counterparts. `src/domain/process/processCaptureParsing.ts:6-22` describes its parsed output as semantically verified and promises rejection of invalid semantics. ## Impact and scope P2: an imported capture can present two incompatible final filesystem states while the public comparison issues an unchanged result. This is a bounded result-integrity failure in caller-authored synthetic Evidence; native producer frequency and downstream reconstruction behavior were not tested. The conflicting facts remain available for manual inspection, so checking top-level arrays against their checkpoints exposes this case. No security boundary crossing or target data loss was observed. ## REA version Exact `node scripts/rea.mjs --version` output: `6.8.0`. Source commit: `ec40c10749b5c4091fb08bc28c6f3f38c2a6968e` (fetched main). ## Runtime and platform Node.js `v24.22.1`; macOS `27.0.1`; `darwin`, `arm64` (measured). No native analysis engine was used. ## Target and artifact context Three synthetic process-capture Evidence records based on `src/domain/process/processCaptureExample.ts`, with matching commitments and complete coverage accounting. One regular-file record has a synthetic four-byte size and digest; no actual created file or live capture is claimed. Only the contradictory fixture disagrees between its top-level final facts and final checkpoint. ## Interface CLI ## Earliest failure stage Request parsing or validation ## Relevant output or evidence Both CLI comparisons exited 0. The fixture generator directly calls the production parser before wrapping the records in content-authenticated Evidence; CLI import independently admits those records. Selected output: ```text baseline accepted files_after 0 checkpoint_files 0 contradictory accepted files_after 1 checkpoint_files 0 consistent accepted files_after 1 checkpoint_files 1 contradictory {"status":"unchanged","filesystem":"unchanged","first_divergence":"none"} consistent {"status":"changed","filesystem":"changed","first_divergence":"found"} ``` ## Typed outcome or recovery expected Return an explicit invalid-capture/semantic validation failure for the conflicting facts, preserving the valid consistent control. Do not silently discard the top-level observations or treat the contradiction as proof of equivalence. ## Analysis or suspected cause Source-derived: `src/domain/process/processCaptureValidation.ts:246-266,349-416` checks checkpoint ordering/truncation and top-level filesystem coverage without reconciling their contents or effects. `src/domain/process/processComparison.ts:131-150` uses only `filesystem_checkpoints` for filesystem comparison. The supported import path at `src/application/process/ProcessEvidence.ts:45-78` validates Evidence integrity, workflow, provider and capture semantics, but the missing invariant lets both versions of the final state through. ## Additional context Related closed [#6218](https://github.com/morluto/rea/issues/6218) and merged [#6298](https://github.com/morluto/rea/pull/6298) address inconsistent aggregate statuses in imported comparison Evidence; this report concerns inconsistent snapshot facts inside imported capture Evidence. Closed [#3180](https://github.com/morluto/rea/issues/3180) concerns ignored checkpoint timestamps under a passing trace; this reproduction uses no trace and equal checkpoint times. No matching open duplicate was found. Native capture, MCP transport, trace evaluation, downstream verification and a post-fix restoration run were not executed.
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#4380
No description provided.