[GH-ISSUE #6514] [Bug] missing middle trace step marks the shared following interaction changed #3907

Closed
opened 2026-10-31 00:45:08 +00:00 by bsakaguchi · 0 comments
Owner

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

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

compare-process-captures reports interaction: "changed" and an interaction observed_change finding when the only observation difference is a missing process sample before a shared interaction. The declared finite variant is [ready, worker, typed]; the left capture contains that sequence and the right contains [ready, typed]. The comparison correctly detects the missing worker, but its trace diagnostic also labels the following shared typed observation unexpected and changes the interaction dimension. Both interaction arrays have the same payload, timestamp, count and per-source index; no pair of shared events changes relative order. The interaction's global journal position shifts because the process sample is absent.

This is a remaining case after the earlier finite-omission repair: the corresponding trailing-process omission now produces correct attribution. Raw event equality alone is insufficient to establish a defect because explicit trace ordering can legitimately affect interaction status; the reproduction includes a genuine reordering control.

Reproduction

Run from the source checkout with its pinned toolchain, locked dependencies and compiled runtime prepared. Verification used the supplied prepared runtime; installation and build were not rerun. Fresh-checkout prerequisites are npm ci and npm run build:cached. The following complete synthetic fixture uses the production capture/specification parsers and invokes the supported offline CLI. It writes only into a disposable directory and gives every CLI child an explicit environment with isolated home, configuration, cache and state paths.

REA_REPO="$PWD" REA_WORK="$(mktemp -d)" node --input-type=module <<'JS'
import assert from 'node:assert/strict';
import { mkdirSync, writeFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { pathToFileURL } from 'node:url';
import { spawnSync } from 'node:child_process';
const repo = process.env.REA_REPO;
const work = process.env.REA_WORK;
const load = file => import(pathToFileURL(join(repo, 'dist', file)).href);
const { EMPTY_PROCESS_CAPTURE_EXAMPLE: base } = await load('domain/process/processCaptureExample.js');
const { parseProcessCapture } = await load('domain/process/processCaptureParsing.js');
const { processTraceSpecificationSchema } = await load('domain/process/processTraceSpecification.js');
const { createEvidence } = await load('domain/evidence.js');
const { PROCESS_PROVIDER } = await load('domain/process/processEvidenceProvider.js');
const { findChangedBehavior } = await load('domain/changedBehavior.js');
const ready = { sequence: 0, at_ms: 0, data: 'ready' };
const worker = { at_ms: 10, pid: 4242, parent_pid: 0, command: 'worker', process_group_id: 4242, session_id: 4242 };
const typed = { sequence: 0, scheduled_at_ms: 20, dispatched_at_ms: 21, type: 'input', data: 'go', outcome: 'dispatched' };
function capture(order, input = typed) {
  const c = structuredClone(base);
  c.frames = [ready];
  c.process_samples = order.includes('worker') ? [worker] : [];
  c.interaction_events = [input];
  Object.assign(c.truncation_details.raw_terminal, { observed_bytes: 5, retained_bytes: 5, observed_frames: 1, retained_frames: 1 });
  c.truncation_details.process.retained_samples = c.process_samples.length;
  const collections = { ready: 'frames', worker: 'process_samples', typed: 'interaction_events' };
  c.event_journal = [
    { collection: 'filesystem_checkpoints', index: 0 },
    ...order.map(id => ({ collection: collections[id], index: 0 })),
    { collection: 'lifecycle', index: 0 }, { collection: 'lifecycle', index: 1 },
    { collection: 'filesystem_checkpoints', index: 1 },
  ].map((entry, capture_order) => ({ ...entry, capture_order }));
  return parseProcessCapture(c);
}
const captures = {
  full: capture(['ready', 'worker', 'typed']),
  missing: capture(['ready', 'typed']),
  reordered: capture(['ready', 'typed', 'worker']),
  changed: capture(['ready', 'worker', 'typed'], { ...typed, data: 'stop' }),
};
const finite = {
  events: [
    { id: 'ready', source: 'terminal_raw', exact: ready, cardinality: { kind: 'required' } },
    { id: 'worker', source: 'process', exact: worker, cardinality: { kind: 'optional' } },
    { id: 'typed', source: 'interaction', exact: typed, cardinality: { kind: 'required' } },
  ],
  language: { kind: 'finite_traces', variants: [{ id: 'normal', trace: ['ready', 'worker', 'typed'] }] },
};
const tail = structuredClone(finite);
tail.language.variants[0].trace = ['ready', 'typed', 'worker'];
const required = structuredClone(finite);
required.events[1].cardinality = { kind: 'required' };
for (const [name, result] of Object.entries(captures)) {
  const evidence = createEvidence(undefined, PROCESS_PROVIDER, {
    predicateType: 'rea.process-capture', operation: 'capture_process_scenario', parameters: {},
    result, confidence: 'observed', authority: 'controlled-replay',
  });
  writeFileSync(join(work, name + '.json'), JSON.stringify(evidence));
}
for (const [name, value] of Object.entries({ finite, tail, required })) {
  writeFileSync(join(work, name + '.json'), JSON.stringify(processTraceSpecificationSchema.parse(value)));
}
const env = { PATH: dirname(process.execPath) + ':/usr/bin:/bin', NO_COLOR: '1' };
for (const key of ['HOME', 'XDG_CONFIG_HOME', 'XDG_CACHE_HOME', 'XDG_STATE_HOME', 'TMPDIR', 'DSH_HOME', 'DSH_AGENTS_HOME']) {
  env[key] = join(work, key.toLowerCase());
  mkdirSync(env[key], { recursive: true });
}
function compare(label, left, right, spec) {
  const args = [join(repo, 'scripts/rea.mjs'), 'compare-process-captures', join(work, left + '.json'), join(work, right + '.json'), ...(spec ? [join(work, spec + '.json')] : []), '--format', 'json'];
  const run = spawnSync(process.execPath, args, { cwd: work, env, encoding: 'utf8', timeout: 30000, maxBuffer: 8 * 1024 * 1024 });
  assert.equal(run.status, 0, run.stdout + run.stderr);
  writeFileSync(join(work, label + '.output.json'), run.stdout);
  const evidence = JSON.parse(run.stdout);
  const r = evidence.normalized_result;
  const findings = findChangedBehavior({ comparisons: [evidence] }).result.findings.items.map(({ dimension, status, classification }) => ({ dimension, status, classification }));
  console.log(JSON.stringify({ label, exit: run.status, status: r.status, terminal: r.terminal, interaction: r.interaction, process: r.process, trace: r.trace?.verdict, sides: r.trace && [r.trace.left.status, r.trace.right.status], diagnostic: r.trace?.diagnostic, first: r.first_divergence, findings }));
  return r;
}
assert.deepEqual(captures.full.interaction_events, captures.missing.interaction_events);
console.log('interaction arrays identical: true');
compare('exact', 'full', 'missing');
compare('middle-omission', 'full', 'missing', 'finite');
compare('reverse', 'missing', 'full', 'finite');
compare('identical', 'full', 'full', 'finite');
compare('tail-omission', 'reordered', 'missing', 'tail');
compare('required-omission', 'full', 'missing', 'required');
compare('true-order', 'full', 'reordered', 'finite');
compare('true-payload', 'full', 'changed', 'finite');
JS

The optional cardinality on worker permits reaching finite-language matching; it does not make the step optional within the sole declared variant. The required-omission control retains that variant and rejects the missing step through cardinality instead.

Expected behavior

For the middle-omission pair, preserve overall changed, process changed, trace verdict different, left trace pass, right trace fail, and the first divergence at process sample 0. Interaction should remain unchanged, and the changed-behavior findings should contain only process. The omission must remain a failure of the original finite language.

Continue reporting interaction changes for genuine interaction payload differences and for a violated ordering constraint between observed interaction/process events. Equal interaction arrays must not override such ordering evidence. The defect here is assigning a process-only omission to the following shared interaction merely because its token position shifts.

Impact and scope

P2: the CLI returns a false additional changed dimension in derived comparison Evidence, and the changed-behavior aggregate converts it to an interaction observed_change. This can misdirect reconstruction or analysis of which behavior changed. The aggregate changed result and genuine process divergence remain correct. The executed scope is synthetic complete captures with one missing middle process event and one shared following interaction; live-capture frequency and other finite-language shapes were not measured.

A demonstrated workaround is to retain the original traced comparison for conformance and run the same inputs without the specification for exact observation attribution. Keep both results: dropping trace validation alone loses the caller's required language check. The required-cardinality control also gives correct attribution for this sole variant, but that change is not a general substitute for arbitrary finite languages.

REA version

rea-agents 6.7.0 at source revision b395190e42.

Runtime and platform

Node.js v24.18.0; npm 11.16.0; macOS 27.0.1; arm64. The existing focused source tests used Vitest 5.0.3.

Target and artifact context

Synthetic canonical process-capture Evidence based on the public empty-capture example, with matching comparison and normalization commitments, complete journals, no truncation and no residual unknowns. No target process, user application, PTY, debugger, native trace launcher or external analysis engine ran.

Interface

CLI

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

  • Expected source: docs/process-capture.md:80-91,454-461 documents explicit trace constraints and dimension-specific attribution; src/domain/process/processComparison.ts:317-378 applies trace results to relevant dimensions. src/domain/process/processTraceComparison.test.ts:511-556 establishes omission-only attribution, while its ordering regression at lines 657-666 preserves genuine cross-source ordering changes with equal collections. The independent controls above establish both behaviors with the interaction source itself.
  • Failure source: The real CLI comparison in the reproduction returns the additional interaction change below. src/domain/process/processTraceEvaluation.ts:133-215 derives missing/unexpected IDs from fixed token windows, and src/domain/process/processComparison.ts:337-357 projects the shared following interaction's ID/location into a changed interaction dimension. The supported route is src/cli/processCommands.ts:32-60 through src/application/process/ProcessCli.ts:123-168.
  • Evidence provenance: observed
  • Local verification: reproduced
  • Reproduction completeness: complete
  • Restoration check: Rerun the exact middle-omission inputs and original specification; require interaction unchanged and no interaction finding, while preserving process changed, overall changed, trace different, left pass/right fail and process sample 0 as first divergence. Preserve the identical, trailing-omission and required-cardinality controls. True-order and true-payload controls must still report interaction changed; suppressing trace validation or every change to equal arrays would fail these checks.

All eight CLI calls in the inline reproduction exited 0. Relevant observed fields:

interaction arrays identical: true
exact:             overall=changed interaction=unchanged process=removed
middle-omission:   overall=changed interaction=changed   process=changed trace=different left=pass right=fail
reverse:           overall=changed interaction=changed   process=changed trace=different left=fail right=pass
identical:         overall=unchanged interaction=unchanged process=unchanged trace=equivalent
tail-omission:     overall=changed interaction=unchanged process=changed trace=different
required-omission: overall=changed interaction=unchanged process=changed trace=different
true-order:        overall=changed interaction=changed   process=changed trace=different
true-payload:      overall=changed interaction=changed   process=unchanged trace=different

The middle-omission result contains:

{
  "diagnostic": {
    "kind": "trace",
    "side": "right",
    "message": "Observed events do not match any finite trace variant.",
    "event_ids": ["worker", "typed"],
    "locations": [{"collection":"interaction_events","index":0,"capture_order":2}]
  },
  "first_divergence": {"status":"found","dimension":"process","index":0,"left_at_ms":10,"right_at_ms":null,"left":{"at_ms":10,"pid":4242,"parent_pid":0,"command":"worker","process_group_id":4242,"session_id":4242},"right":null},
  "findings": [
    {"dimension":"interaction","status":"changed","classification":"observed_change"},
    {"dimension":"process","status":"changed","classification":"observed_change"}
  ]
}

An additional independent replay ran ten CLI cases, including identical nonconforming captures and an explicitly allowed omission variant, with assertions on their current outcomes. The existing focused processTraceComparison.test.ts suite passed all 16 tests with one Vitest worker. No source fix or post-fix restoration run was performed. MCP delivery, live captures, other platforms, broad suites and builds were not exercised.

Analysis or suspected cause

Source-derived: after matching ready, the finite evaluator compares expected worker with actual typed, records both IDs and the interaction location, and stops that variant. It does not distinguish this shifted shared suffix from a genuine reordering at that point. The dimension projection then treats both diagnostic sources as changed. The genuine-order control produces the same first token mismatch but has both observations present; a correction must distinguish the omission from that actual ordering difference. This explanation does not prescribe an implementation or relax the accepted trace language.

Additional context

Closest prior report: #3181, closed after the finite-omission repair, required preserving equal unrelated dimensions while retaining the missing process step. Its linked merge contains the finite-diagnostic repair. That change is present in the tested checkout; its trailing-omission regression and the interaction-specific tail control above pass. The remaining case omits a middle token before a shared following event, which the repaired best-prefix diagnostic calls unexpected. This report supplies that still-failing case after the original trailing-omission restoration passes.

#2616 addressed projecting a predicate failure across every covered dimension. #3931 addressed losing unrelated unknown coverage. Both concern different producing conditions from the complete-evidence two-ID diagnostic here. #5923 covers first-divergence localization for genuine ordering failures; the omission case here correctly locates process sample 0. Searches covered open and closed issues using finite-trace omission, trace attribution and interaction trace terms, including the exact related reports and repair discussions.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: The executed offline CLI reports a false interaction change and the aggregate emits an interaction observed_change finding for a process-only omission. The correct overall change and process divergence survive, bounding the observed failure to attribution rather than lost detection.
  • Workaround status: available
  • Workaround basis: The same Evidence compared without a trace specification returns interaction unchanged and process removed. Keeping that exact result alongside the original finite comparison preserves both observation attribution and the original trace-conformance failure without changing capture data or the accepted language.
Originally created by @coygeek on GitHub (Oct 23, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/6514 ## 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 `compare-process-captures` reports `interaction: "changed"` and an interaction `observed_change` finding when the only observation difference is a missing process sample before a shared interaction. The declared finite variant is `[ready, worker, typed]`; the left capture contains that sequence and the right contains `[ready, typed]`. The comparison correctly detects the missing `worker`, but its trace diagnostic also labels the following shared `typed` observation unexpected and changes the interaction dimension. Both interaction arrays have the same payload, timestamp, count and per-source index; no pair of shared events changes relative order. The interaction's global journal position shifts because the process sample is absent. This is a remaining case after the earlier finite-omission repair: the corresponding trailing-process omission now produces correct attribution. Raw event equality alone is insufficient to establish a defect because explicit trace ordering can legitimately affect interaction status; the reproduction includes a genuine reordering control. ## Reproduction Run from the source checkout with its pinned toolchain, locked dependencies and compiled runtime prepared. Verification used the supplied prepared runtime; installation and build were not rerun. Fresh-checkout prerequisites are `npm ci` and `npm run build:cached`. The following complete synthetic fixture uses the production capture/specification parsers and invokes the supported offline CLI. It writes only into a disposable directory and gives every CLI child an explicit environment with isolated home, configuration, cache and state paths. ```sh REA_REPO="$PWD" REA_WORK="$(mktemp -d)" node --input-type=module <<'JS' import assert from 'node:assert/strict'; import { mkdirSync, writeFileSync } from 'node:fs'; import { dirname, join } from 'node:path'; import { pathToFileURL } from 'node:url'; import { spawnSync } from 'node:child_process'; const repo = process.env.REA_REPO; const work = process.env.REA_WORK; const load = file => import(pathToFileURL(join(repo, 'dist', file)).href); const { EMPTY_PROCESS_CAPTURE_EXAMPLE: base } = await load('domain/process/processCaptureExample.js'); const { parseProcessCapture } = await load('domain/process/processCaptureParsing.js'); const { processTraceSpecificationSchema } = await load('domain/process/processTraceSpecification.js'); const { createEvidence } = await load('domain/evidence.js'); const { PROCESS_PROVIDER } = await load('domain/process/processEvidenceProvider.js'); const { findChangedBehavior } = await load('domain/changedBehavior.js'); const ready = { sequence: 0, at_ms: 0, data: 'ready' }; const worker = { at_ms: 10, pid: 4242, parent_pid: 0, command: 'worker', process_group_id: 4242, session_id: 4242 }; const typed = { sequence: 0, scheduled_at_ms: 20, dispatched_at_ms: 21, type: 'input', data: 'go', outcome: 'dispatched' }; function capture(order, input = typed) { const c = structuredClone(base); c.frames = [ready]; c.process_samples = order.includes('worker') ? [worker] : []; c.interaction_events = [input]; Object.assign(c.truncation_details.raw_terminal, { observed_bytes: 5, retained_bytes: 5, observed_frames: 1, retained_frames: 1 }); c.truncation_details.process.retained_samples = c.process_samples.length; const collections = { ready: 'frames', worker: 'process_samples', typed: 'interaction_events' }; c.event_journal = [ { collection: 'filesystem_checkpoints', index: 0 }, ...order.map(id => ({ collection: collections[id], index: 0 })), { collection: 'lifecycle', index: 0 }, { collection: 'lifecycle', index: 1 }, { collection: 'filesystem_checkpoints', index: 1 }, ].map((entry, capture_order) => ({ ...entry, capture_order })); return parseProcessCapture(c); } const captures = { full: capture(['ready', 'worker', 'typed']), missing: capture(['ready', 'typed']), reordered: capture(['ready', 'typed', 'worker']), changed: capture(['ready', 'worker', 'typed'], { ...typed, data: 'stop' }), }; const finite = { events: [ { id: 'ready', source: 'terminal_raw', exact: ready, cardinality: { kind: 'required' } }, { id: 'worker', source: 'process', exact: worker, cardinality: { kind: 'optional' } }, { id: 'typed', source: 'interaction', exact: typed, cardinality: { kind: 'required' } }, ], language: { kind: 'finite_traces', variants: [{ id: 'normal', trace: ['ready', 'worker', 'typed'] }] }, }; const tail = structuredClone(finite); tail.language.variants[0].trace = ['ready', 'typed', 'worker']; const required = structuredClone(finite); required.events[1].cardinality = { kind: 'required' }; for (const [name, result] of Object.entries(captures)) { const evidence = createEvidence(undefined, PROCESS_PROVIDER, { predicateType: 'rea.process-capture', operation: 'capture_process_scenario', parameters: {}, result, confidence: 'observed', authority: 'controlled-replay', }); writeFileSync(join(work, name + '.json'), JSON.stringify(evidence)); } for (const [name, value] of Object.entries({ finite, tail, required })) { writeFileSync(join(work, name + '.json'), JSON.stringify(processTraceSpecificationSchema.parse(value))); } const env = { PATH: dirname(process.execPath) + ':/usr/bin:/bin', NO_COLOR: '1' }; for (const key of ['HOME', 'XDG_CONFIG_HOME', 'XDG_CACHE_HOME', 'XDG_STATE_HOME', 'TMPDIR', 'DSH_HOME', 'DSH_AGENTS_HOME']) { env[key] = join(work, key.toLowerCase()); mkdirSync(env[key], { recursive: true }); } function compare(label, left, right, spec) { const args = [join(repo, 'scripts/rea.mjs'), 'compare-process-captures', join(work, left + '.json'), join(work, right + '.json'), ...(spec ? [join(work, spec + '.json')] : []), '--format', 'json']; const run = spawnSync(process.execPath, args, { cwd: work, env, encoding: 'utf8', timeout: 30000, maxBuffer: 8 * 1024 * 1024 }); assert.equal(run.status, 0, run.stdout + run.stderr); writeFileSync(join(work, label + '.output.json'), run.stdout); const evidence = JSON.parse(run.stdout); const r = evidence.normalized_result; const findings = findChangedBehavior({ comparisons: [evidence] }).result.findings.items.map(({ dimension, status, classification }) => ({ dimension, status, classification })); console.log(JSON.stringify({ label, exit: run.status, status: r.status, terminal: r.terminal, interaction: r.interaction, process: r.process, trace: r.trace?.verdict, sides: r.trace && [r.trace.left.status, r.trace.right.status], diagnostic: r.trace?.diagnostic, first: r.first_divergence, findings })); return r; } assert.deepEqual(captures.full.interaction_events, captures.missing.interaction_events); console.log('interaction arrays identical: true'); compare('exact', 'full', 'missing'); compare('middle-omission', 'full', 'missing', 'finite'); compare('reverse', 'missing', 'full', 'finite'); compare('identical', 'full', 'full', 'finite'); compare('tail-omission', 'reordered', 'missing', 'tail'); compare('required-omission', 'full', 'missing', 'required'); compare('true-order', 'full', 'reordered', 'finite'); compare('true-payload', 'full', 'changed', 'finite'); JS ``` The optional cardinality on `worker` permits reaching finite-language matching; it does not make the step optional within the sole declared variant. The `required-omission` control retains that variant and rejects the missing step through cardinality instead. ## Expected behavior For the middle-omission pair, preserve overall `changed`, process `changed`, trace verdict `different`, left trace `pass`, right trace `fail`, and the first divergence at process sample 0. Interaction should remain `unchanged`, and the changed-behavior findings should contain only process. The omission must remain a failure of the original finite language. Continue reporting interaction changes for genuine interaction payload differences and for a violated ordering constraint between observed interaction/process events. Equal interaction arrays must not override such ordering evidence. The defect here is assigning a process-only omission to the following shared interaction merely because its token position shifts. ## Impact and scope P2: the CLI returns a false additional changed dimension in derived comparison Evidence, and the changed-behavior aggregate converts it to an interaction `observed_change`. This can misdirect reconstruction or analysis of which behavior changed. The aggregate changed result and genuine process divergence remain correct. The executed scope is synthetic complete captures with one missing middle process event and one shared following interaction; live-capture frequency and other finite-language shapes were not measured. A demonstrated workaround is to retain the original traced comparison for conformance and run the same inputs without the specification for exact observation attribution. Keep both results: dropping trace validation alone loses the caller's required language check. The required-cardinality control also gives correct attribution for this sole variant, but that change is not a general substitute for arbitrary finite languages. ## REA version rea-agents 6.7.0 at source revision b395190e4273b2542a599aa2cdce61107f3a7ebc. ## Runtime and platform Node.js v24.18.0; npm 11.16.0; macOS 27.0.1; arm64. The existing focused source tests used Vitest 5.0.3. ## Target and artifact context Synthetic canonical process-capture Evidence based on the public empty-capture example, with matching comparison and normalization commitments, complete journals, no truncation and no residual unknowns. No target process, user application, PTY, debugger, native trace launcher or external analysis engine ran. ## Interface CLI ## Earliest failure stage Native analysis or reconstruction ## Relevant output or evidence - Expected source: `docs/process-capture.md:80-91,454-461` documents explicit trace constraints and dimension-specific attribution; `src/domain/process/processComparison.ts:317-378` applies trace results to relevant dimensions. `src/domain/process/processTraceComparison.test.ts:511-556` establishes omission-only attribution, while its ordering regression at lines 657-666 preserves genuine cross-source ordering changes with equal collections. The independent controls above establish both behaviors with the interaction source itself. - Failure source: The real CLI comparison in the reproduction returns the additional interaction change below. `src/domain/process/processTraceEvaluation.ts:133-215` derives missing/unexpected IDs from fixed token windows, and `src/domain/process/processComparison.ts:337-357` projects the shared following interaction's ID/location into a changed interaction dimension. The supported route is `src/cli/processCommands.ts:32-60` through `src/application/process/ProcessCli.ts:123-168`. - Evidence provenance: observed - Local verification: reproduced - Reproduction completeness: complete - Restoration check: Rerun the exact middle-omission inputs and original specification; require interaction unchanged and no interaction finding, while preserving process changed, overall changed, trace different, left pass/right fail and process sample 0 as first divergence. Preserve the identical, trailing-omission and required-cardinality controls. True-order and true-payload controls must still report interaction changed; suppressing trace validation or every change to equal arrays would fail these checks. All eight CLI calls in the inline reproduction exited 0. Relevant observed fields: ```text interaction arrays identical: true exact: overall=changed interaction=unchanged process=removed middle-omission: overall=changed interaction=changed process=changed trace=different left=pass right=fail reverse: overall=changed interaction=changed process=changed trace=different left=fail right=pass identical: overall=unchanged interaction=unchanged process=unchanged trace=equivalent tail-omission: overall=changed interaction=unchanged process=changed trace=different required-omission: overall=changed interaction=unchanged process=changed trace=different true-order: overall=changed interaction=changed process=changed trace=different true-payload: overall=changed interaction=changed process=unchanged trace=different ``` The middle-omission result contains: ```json { "diagnostic": { "kind": "trace", "side": "right", "message": "Observed events do not match any finite trace variant.", "event_ids": ["worker", "typed"], "locations": [{"collection":"interaction_events","index":0,"capture_order":2}] }, "first_divergence": {"status":"found","dimension":"process","index":0,"left_at_ms":10,"right_at_ms":null,"left":{"at_ms":10,"pid":4242,"parent_pid":0,"command":"worker","process_group_id":4242,"session_id":4242},"right":null}, "findings": [ {"dimension":"interaction","status":"changed","classification":"observed_change"}, {"dimension":"process","status":"changed","classification":"observed_change"} ] } ``` An additional independent replay ran ten CLI cases, including identical nonconforming captures and an explicitly allowed omission variant, with assertions on their current outcomes. The existing focused `processTraceComparison.test.ts` suite passed all 16 tests with one Vitest worker. No source fix or post-fix restoration run was performed. MCP delivery, live captures, other platforms, broad suites and builds were not exercised. ## Analysis or suspected cause Source-derived: after matching `ready`, the finite evaluator compares expected `worker` with actual `typed`, records both IDs and the interaction location, and stops that variant. It does not distinguish this shifted shared suffix from a genuine reordering at that point. The dimension projection then treats both diagnostic sources as changed. The genuine-order control produces the same first token mismatch but has both observations present; a correction must distinguish the omission from that actual ordering difference. This explanation does not prescribe an implementation or relax the accepted trace language. ## Additional context Closest prior report: [#3181](https://github.com/morluto/rea/issues/3181), closed after the finite-omission repair, required preserving equal unrelated dimensions while retaining the missing process step. Its linked merge contains the [finite-diagnostic repair](https://github.com/morluto/rea/commit/fc7e41ff3b1d24b0f8c1d49eff3dd7360c2e2681). That change is present in the tested checkout; its trailing-omission regression and the interaction-specific tail control above pass. The remaining case omits a middle token before a shared following event, which the repaired best-prefix diagnostic calls unexpected. This report supplies that still-failing case after the original trailing-omission restoration passes. [#2616](https://github.com/morluto/rea/issues/2616) addressed projecting a predicate failure across every covered dimension. [#3931](https://github.com/morluto/rea/issues/3931) addressed losing unrelated unknown coverage. Both concern different producing conditions from the complete-evidence two-ID diagnostic here. [#5923](https://github.com/morluto/rea/issues/5923) covers first-divergence localization for genuine ordering failures; the omission case here correctly locates process sample 0. Searches covered open and closed issues using finite-trace omission, trace attribution and interaction trace terms, including the exact related reports and repair discussions. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: The executed offline CLI reports a false interaction change and the aggregate emits an interaction observed_change finding for a process-only omission. The correct overall change and process divergence survive, bounding the observed failure to attribution rather than lost detection. - Workaround status: available - Workaround basis: The same Evidence compared without a trace specification returns interaction unchanged and process removed. Keeping that exact result alongside the original finite comparison preserves both observation attribution and the original trace-conformance failure without changing capture data or the accepted language.
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#3907
No description provided.