[GH-ISSUE #7330] [Bug] Record-order validation incorrectly reports noncanonical manifests #4359

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

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

Before submitting

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

Area

Evidence, artifacts, or reconstruction

Observed behavior

evidence-import correctly rejects a bundle with reversed records, but says its manifests are not canonical. In the executed fixture, all six non-record fields remain identical to an accepted bundle; only record order changes. A genuinely incorrect provider manifest produces the same diagnostic. Sorting the records restores acceptance.

This report concerns the false manifest attribution. Canonical-order authentication and rejection of the altered bundle are expected behavior.

Reproduction

Use the baseline source checkout with its locked dependencies and built runtime already available, and Node.js on PATH. Run from the checkout root. The following expresses the fixture generation and public CLI calls executed sequentially by the verifier through a subprocess runner. It uses two benign, targetless observations and an isolated home; no analysis provider is started.

WORK=$(mktemp -d)
mkdir -p "$WORK/home"
node_local() {
  env -i PATH="$PATH" HOME="$WORK/home" \
    XDG_CONFIG_HOME="$WORK/home/config" \
    XDG_CACHE_HOME="$WORK/home/cache" \
    XDG_DATA_HOME="$WORK/home/data" \
    XDG_STATE_HOME="$WORK/home/state" \
    REA_LOG_LEVEL=silent TMPDIR="$WORK" node "$@"
}
node_local --input-type=module <<'JS'
import { writeFile } from 'node:fs/promises';
import { createEvidence } from './dist/domain/evidence.js';
import { createEvidenceBundle } from './dist/domain/evidenceBundle.js';
const provider = { id: 'fixture', name: 'Fixture', version: '1' };
const records = ['first', 'second'].map(label =>
  createEvidence(undefined, provider, {
    operation: 'observe', parameters: { label }, result: { label }
  })
);
const canonical = createEvidenceBundle(records);
const reversed = { ...canonical, records: [...canonical.records].reverse() };
const restored = {
  ...reversed,
  records: [...reversed.records].sort((a, b) =>
    a.evidence_id < b.evidence_id ? -1 : a.evidence_id > b.evidence_id ? 1 : 0)
};
const wrongManifest = { ...canonical, providers: [] };
console.log('non-record fields equal:', Object.keys(canonical)
  .filter(key => key !== 'records')
  .every(key => JSON.stringify(canonical[key]) === JSON.stringify(reversed[key])));
for (const [name, value] of Object.entries({ canonical, reversed, restored, wrongManifest }))
  await writeFile(`${process.env.TMPDIR}/${name}.json`, JSON.stringify(value));
JS
node_local scripts/rea.mjs evidence-import "$WORK/canonical.json" --json
node_local scripts/rea.mjs evidence-import "$WORK/reversed.json" --json
node_local scripts/rea.mjs evidence-import "$WORK/restored.json" --json
node_local scripts/rea.mjs evidence-import "$WORK/wrongManifest.json" --json

Observed exit statuses, respectively: 0, 1, 0, 1. The field comparison returned true. One execution of each case was performed; the reversed import showed the incorrect wording in that execution. All generated files reside in the disposable directory named by $WORK.

Expected behavior

Keep rejecting reversed records under the authenticated canonical-form contract, but describe the violated record-order constraint accurately, or use bundle-wide canonicality wording that does not falsely identify manifests as the problem. Preserve a meaningful manifest diagnostic for the genuinely inconsistent-manifest control.

AGENTS.md, Architecture and Cleanup, requires meaningful failure reasons. docs/tool-design.md:318 requires file-error wrappers to retain the format owner's specific diagnostic. src/domain/evidenceBundle.ts:46 defines manifests separately from records; its canonical projection sorts records at line 110. The explicit reversed-order rejection test at src/domain/evidenceBundle.test.ts:24 establishes that acceptance of the altered input is not required. The comment that order has no semantics does not override this authentication requirement.

Impact and scope

P3: incorrect diagnostic wording for correctly rejected caller input. The verified effect is confusion about which part of the bundle violates canonical form. Valid canonical input succeeds; no data loss, evidence corruption, or acceptance of invalid input was observed. Sorting only the records restored this synthetic fixture without modifying any record or manifest. That workaround is specific to this record-order case.

CLI import and export were exercised. Export of the reversed file returned the same diagnostic and wrote no destination; export of the canonical file succeeded. MCP, comparison, and snapshot behavior were not executed. The report does not claim recovery is impossible: recreating or re-exporting from an original session remains a reasonable interpretation of the advice, although that session recovery was not exercised.

REA version

6.8.0, source revision dbe2c97af34361b11b9504e37611dd47715b52cb.

Runtime and platform

Node.js v24.22.1; macOS 27.0.1, darwin arm64. Used the existing built checkout runtime; no installation, rebuild, or test suite was run by this verifier.

Target and artifact context

Synthetic Evidence bundle containing two distinct targetless observe records from the fixture provider. Provider manifest contains one entry; artifact, environment, scenario, capture, and unknown arrays are empty. No executable target, external service, or analysis engine is involved.

Interface

CLI

Earliest failure stage

Request parsing or validation

Relevant output or evidence

Canonical and restored import, exit 0:

{"imported":2,"unknowns_added":0,"total":2}

Reversed-record and incorrect-provider-manifest import, each exit 1:

{"error":"Analysis failed","code":"evidence_integrity_mismatch","category":"integrity_mismatch","message":"Evidence bundle validation failed: Evidence bundle manifests are not canonical. Recreate or re-export the bundle, then try again.","retryable":false,"remediation":{"action":"Evidence bundle validation failed: Evidence bundle manifests are not canonical. Recreate or re-export the bundle, then try again."},"details":{"reason":"Evidence bundle validation failed"}}

The fixture comparison established equality of every non-record field between canonical and reversed inputs. Restoring record order produced the original canonical object. These are observed controls, not an inference from the error text.

Typed outcome or recovery expected

A validation failure whose reason accurately describes record ordering or bundle canonicality. No change to acceptance, integrity checking, error classification, or retryability is requested by this report.

Analysis or suspected cause

Source-derived: authenticateBundle in src/domain/evidenceBundle.ts:348 authenticates the records and compares the entire parsed bundle against a canonical projection. Any difference raises NonCanonicalEvidenceBundleError at line 376. The class at line 60 always names manifests, including when the difference is confined to records. describeEvidenceBundleFailure at line 254 forwards that message, and src/application/EvidenceBundleFiles.ts:88 carries it into the public integrity error. src/cliEvidenceCommands.ts:24 reaches this path through importEvidenceBundleCommand with the supplied local file.

Additional context

  • Expected source: AGENTS.md, Architecture and Cleanup; docs/tool-design.md:318; the separate manifest/record model and canonical-order rejection test cited above.
  • Failure source: Public scripts/rea.mjs evidence-import executions and the fixed manifest-only error in src/domain/evidenceBundle.ts:60.
  • Evidence provenance: observed CLI results and fixture comparisons; implementation explanation is source-derived.
  • Local verification: reproduced on the stated baseline using its existing built runtime and an isolated home.
  • Reproduction completeness: complete for the diagnostic defect through CLI import. MCP and fresh package/build verification were not run.
  • Restoration check: The reversed fixture remains rejected with an accurate reason that does not incorrectly blame its unchanged manifests. Canonical and restored fixtures continue to succeed; the deliberately incorrect provider manifest remains rejected with an appropriate reason. No implementation fix was applied during verification.

Related closed issue #3219 and PR #3288 address ledger error classification. That issue explicitly treats the manifest-only message as the desired preserved reason, so its closure does not correct this wording. Closed PR #1073 introduced per-constraint bundle messages but did not distinguish record-order mismatches. A final search of open and closed issues and relevant pull requests found no report with this narrower restoration criterion.

Triage assessment

  • Impact level: P3
  • Assessment status: supported
  • Impact basis: Correctly rejected noncanonical input receives a false manifest attribution. Canonical input succeeds and no consequential behavior or integrity change was observed.
  • Workaround status: available
  • Workaround basis: Sorting only the two records restored successful import with every record and manifest preserved. Re-export from an original session was not verified and is not needed to establish this workaround.
Originally created by @coygeek on GitHub (Oct 26, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7330 ## 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 Evidence, artifacts, or reconstruction ## Observed behavior `evidence-import` correctly rejects a bundle with reversed `records`, but says its manifests are not canonical. In the executed fixture, all six non-record fields remain identical to an accepted bundle; only record order changes. A genuinely incorrect provider manifest produces the same diagnostic. Sorting the records restores acceptance. This report concerns the false manifest attribution. Canonical-order authentication and rejection of the altered bundle are expected behavior. ## Reproduction Use the baseline source checkout with its locked dependencies and built runtime already available, and Node.js on PATH. Run from the checkout root. The following expresses the fixture generation and public CLI calls executed sequentially by the verifier through a subprocess runner. It uses two benign, targetless observations and an isolated home; no analysis provider is started. ```sh WORK=$(mktemp -d) mkdir -p "$WORK/home" node_local() { env -i PATH="$PATH" HOME="$WORK/home" \ XDG_CONFIG_HOME="$WORK/home/config" \ XDG_CACHE_HOME="$WORK/home/cache" \ XDG_DATA_HOME="$WORK/home/data" \ XDG_STATE_HOME="$WORK/home/state" \ REA_LOG_LEVEL=silent TMPDIR="$WORK" node "$@" } node_local --input-type=module <<'JS' import { writeFile } from 'node:fs/promises'; import { createEvidence } from './dist/domain/evidence.js'; import { createEvidenceBundle } from './dist/domain/evidenceBundle.js'; const provider = { id: 'fixture', name: 'Fixture', version: '1' }; const records = ['first', 'second'].map(label => createEvidence(undefined, provider, { operation: 'observe', parameters: { label }, result: { label } }) ); const canonical = createEvidenceBundle(records); const reversed = { ...canonical, records: [...canonical.records].reverse() }; const restored = { ...reversed, records: [...reversed.records].sort((a, b) => a.evidence_id < b.evidence_id ? -1 : a.evidence_id > b.evidence_id ? 1 : 0) }; const wrongManifest = { ...canonical, providers: [] }; console.log('non-record fields equal:', Object.keys(canonical) .filter(key => key !== 'records') .every(key => JSON.stringify(canonical[key]) === JSON.stringify(reversed[key]))); for (const [name, value] of Object.entries({ canonical, reversed, restored, wrongManifest })) await writeFile(`${process.env.TMPDIR}/${name}.json`, JSON.stringify(value)); JS node_local scripts/rea.mjs evidence-import "$WORK/canonical.json" --json node_local scripts/rea.mjs evidence-import "$WORK/reversed.json" --json node_local scripts/rea.mjs evidence-import "$WORK/restored.json" --json node_local scripts/rea.mjs evidence-import "$WORK/wrongManifest.json" --json ``` Observed exit statuses, respectively: `0`, `1`, `0`, `1`. The field comparison returned `true`. One execution of each case was performed; the reversed import showed the incorrect wording in that execution. All generated files reside in the disposable directory named by `$WORK`. ## Expected behavior Keep rejecting reversed records under the authenticated canonical-form contract, but describe the violated record-order constraint accurately, or use bundle-wide canonicality wording that does not falsely identify manifests as the problem. Preserve a meaningful manifest diagnostic for the genuinely inconsistent-manifest control. `AGENTS.md`, Architecture and Cleanup, requires meaningful failure reasons. `docs/tool-design.md:318` requires file-error wrappers to retain the format owner's specific diagnostic. `src/domain/evidenceBundle.ts:46` defines manifests separately from `records`; its canonical projection sorts records at line 110. The explicit reversed-order rejection test at `src/domain/evidenceBundle.test.ts:24` establishes that acceptance of the altered input is not required. The comment that order has no semantics does not override this authentication requirement. ## Impact and scope P3: incorrect diagnostic wording for correctly rejected caller input. The verified effect is confusion about which part of the bundle violates canonical form. Valid canonical input succeeds; no data loss, evidence corruption, or acceptance of invalid input was observed. Sorting only the records restored this synthetic fixture without modifying any record or manifest. That workaround is specific to this record-order case. CLI import and export were exercised. Export of the reversed file returned the same diagnostic and wrote no destination; export of the canonical file succeeded. MCP, comparison, and snapshot behavior were not executed. The report does not claim recovery is impossible: recreating or re-exporting from an original session remains a reasonable interpretation of the advice, although that session recovery was not exercised. ## REA version 6.8.0, source revision `dbe2c97af34361b11b9504e37611dd47715b52cb`. ## Runtime and platform Node.js v24.22.1; macOS 27.0.1, darwin arm64. Used the existing built checkout runtime; no installation, rebuild, or test suite was run by this verifier. ## Target and artifact context Synthetic Evidence bundle containing two distinct targetless `observe` records from the fixture provider. Provider manifest contains one entry; artifact, environment, scenario, capture, and unknown arrays are empty. No executable target, external service, or analysis engine is involved. ## Interface CLI ## Earliest failure stage Request parsing or validation ## Relevant output or evidence Canonical and restored import, exit 0: ```json {"imported":2,"unknowns_added":0,"total":2} ``` Reversed-record and incorrect-provider-manifest import, each exit 1: ```json {"error":"Analysis failed","code":"evidence_integrity_mismatch","category":"integrity_mismatch","message":"Evidence bundle validation failed: Evidence bundle manifests are not canonical. Recreate or re-export the bundle, then try again.","retryable":false,"remediation":{"action":"Evidence bundle validation failed: Evidence bundle manifests are not canonical. Recreate or re-export the bundle, then try again."},"details":{"reason":"Evidence bundle validation failed"}} ``` The fixture comparison established equality of every non-record field between canonical and reversed inputs. Restoring record order produced the original canonical object. These are observed controls, not an inference from the error text. ## Typed outcome or recovery expected A validation failure whose reason accurately describes record ordering or bundle canonicality. No change to acceptance, integrity checking, error classification, or retryability is requested by this report. ## Analysis or suspected cause Source-derived: `authenticateBundle` in `src/domain/evidenceBundle.ts:348` authenticates the records and compares the entire parsed bundle against a canonical projection. Any difference raises `NonCanonicalEvidenceBundleError` at line 376. The class at line 60 always names manifests, including when the difference is confined to `records`. `describeEvidenceBundleFailure` at line 254 forwards that message, and `src/application/EvidenceBundleFiles.ts:88` carries it into the public integrity error. `src/cliEvidenceCommands.ts:24` reaches this path through `importEvidenceBundleCommand` with the supplied local file. ## Additional context - Expected source: `AGENTS.md`, Architecture and Cleanup; `docs/tool-design.md:318`; the separate manifest/record model and canonical-order rejection test cited above. - Failure source: Public `scripts/rea.mjs evidence-import` executions and the fixed manifest-only error in `src/domain/evidenceBundle.ts:60`. - Evidence provenance: observed CLI results and fixture comparisons; implementation explanation is source-derived. - Local verification: reproduced on the stated baseline using its existing built runtime and an isolated home. - Reproduction completeness: complete for the diagnostic defect through CLI import. MCP and fresh package/build verification were not run. - Restoration check: The reversed fixture remains rejected with an accurate reason that does not incorrectly blame its unchanged manifests. Canonical and restored fixtures continue to succeed; the deliberately incorrect provider manifest remains rejected with an appropriate reason. No implementation fix was applied during verification. Related closed [issue #3219](https://github.com/morluto/rea/issues/3219) and [PR #3288](https://github.com/morluto/rea/pull/3288) address ledger error classification. That issue explicitly treats the manifest-only message as the desired preserved reason, so its closure does not correct this wording. Closed [PR #1073](https://github.com/morluto/rea/pull/1073) introduced per-constraint bundle messages but did not distinguish record-order mismatches. A final search of open and closed issues and relevant pull requests found no report with this narrower restoration criterion. ## Triage assessment - Impact level: P3 - Assessment status: supported - Impact basis: Correctly rejected noncanonical input receives a false manifest attribution. Canonical input succeeds and no consequential behavior or integrity change was observed. - Workaround status: available - Workaround basis: Sorting only the two records restored successful import with every record and manifest preserved. Re-export from an original session was not verified and is not needed to establish this workaround.
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#4359
No description provided.