[GH-ISSUE #6706] [Bug] Artifact comparison omits changes to a source map's mapped artifact identity #4075

Closed
opened 2026-10-31 00:46:38 +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/6706

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

Two ordinary directory inventories contain main.js and identical main.js.map bytes. Changing only an inert comment in main.js changes the source map's maps-source edge: its parent_artifact_id now identifies different JavaScript content. compare_artifacts omits main.js.map from changes and counts it as unchanged.

The overall result correctly says changed, with changes for . and main.js. This report concerns the missing relationship change on the map, not whole-bundle false equality. Both inventories came from the inventory engine without editing their nodes, occurrences, edges, or identities. The result was observed through the domain comparison and the registered public MCP tool over local stdio.

Reproduction

From the built repository root, run this reduced fixture using the production inventory and comparison boundaries:

mkdir -p /tmp/rea-repro
node --input-type=module <<'JS'
import { mkdir, writeFile } from 'node:fs/promises';
import { inventoryArtifact } from './dist/artifacts/inventory/ArtifactInventory.js';
import { ArtifactResourceScope } from './dist/artifacts/ArtifactResourceScope.js';
import { createEvidence } from './dist/domain/evidence.js';
import { compareArtifacts } from './dist/domain/artifactComparison.js';
const records = [];
for (const [side, source] of [
  ['left', '/* revision one */\n'],
  ['right', '/* revision two */\n']
]) {
  const path = '/tmp/rea-repro/' + side;
  await mkdir(path, { recursive: true });
  await writeFile(path + '/main.js', source);
  await writeFile(path + '/main.js.map',
    '{"version":3,"sources":[],"names":[],"mappings":""}');
  const resources = new ArtifactResourceScope();
  try {
    const graph = await inventoryArtifact(path, { resourceScope: resources });
    records.push(createEvidence(
      { path, sha256: graph.manifest.root_sha256, format: 'directory' },
      { id: 'rea-artifact-graph', name: 'REA artifact graph', version: '1' },
      { operation: 'inventory_artifact', parameters: {}, result: graph }
    ));
  } finally { await resources.close(); }
}
const [left, right] = records;
const mappedParent = record => record.normalized_result.edges
  .find(edge => edge.relation === 'maps-source').parent_artifact_id;
const changed = compareArtifacts(left, right);
console.log(JSON.stringify({
  mapped_parent_changed: mappedParent(left) !== mappedParent(right),
  comparison: changed
}, null, 2));
JS

Executed once with these file contents through the production domain boundary, followed by one public MCP comparison of the same unmodified Evidence pair. The MCP baseline compare_artifacts({left, right: left}) was executed once and returned three unchanged occurrences. No JavaScript target was executed, semantic parser used, or source map fetched.

Expected behavior

Preserve a changed semantic relationship parent in the comparison. When an existing map now has a maps-source edge to different artifact content, include a relationship change for that map, or explicitly expose that this relationship dimension is not compared.

The edge identity contract calls the parent artifact part of the semantic relationship. The producer assigns a map's semantic parent from the mapped source, which differs from the containing directory. The comparison already advertises a relations dimension.

Impact and scope

An analyst using the per-path delta cannot see that an unchanged map file now describes a different content-addressed source artifact. The reproduction's unchanged: 1 is the map even though its semantic edge differs. Whole-bundle change detection remains correct. Observed on one minimal supported directory pair; shipped-application prevalence and maintainer intent about content-bound relationship comparison are NOT_ENOUGH_INFO.

Manual inspection of each inventory's maps-source edge reveals the different parent identities and is an available workaround. No data mutation or corruption was observed.

REA version

rea-agents 6.7.0; commit 8c4f96ef4759fd78da66c4b9726825ca71d7ee0c.

Runtime and platform

Node.js v26.12.1; Linux x64. Other runtimes and platforms were not tested.

Target and artifact context

Two local directories containing an inert JavaScript comment file and a version-3 source-map JSON file. Complete production inventories; no edited graph records or recomputed identities.

Interface

MCP

Earliest failure stage

Transport or result projection

Relevant output or evidence

The production inventories yielded different maps-source.parent_artifact_id values:

left:  art_873671fb6052d766a7e6883fa15c172000b696861bb0e82967711ba2ddf76584
right: art_208b2dee33b276d7abb200787c51fcc4cb403a48ac34078ce73b0bc717cec0ec

Relevant projection of the observed public MCP result:

{
  "status": "changed",
  "summary": {"unchanged": 1, "changed": 2, "unknown": 0},
  "changes": [
    {"logical_path": ".", "dimensions": ["content"]},
    {"logical_path": "main.js", "dimensions": ["content", "relations"]}
  ],
  "limitations": []
}

The same-input baseline returned status: unchanged, summary.unchanged: 3, and changes: []. No post-fix run, full suite, installed-package comparison, or other-platform check was performed.

Typed outcome or recovery expected

A changed relationship entry for main.js.map, preserving citations to both inventories. Otherwise return an explicit limitation that semantic edge parent changes are outside the comparison.

Analysis or suspected cause

Source-derived: relationsByPath replaces the edge's semantic parent with the occurrence's containing-directory path and omits edge.parent_artifact_id. Consequently, a map's relation projection is identical when its mapped source content changes. Containment normalization avoids cascading root identity changes, but applies the same normalization to maps-source edges whose semantic parent is a sibling file.

Additional context

Searched both open and closed issues for evidence-bundle, artifact-comparison, and source-map comparison reports, and checked the supplied open-issue title index. No matching report found. #5452 concerns unresolved linked inventory IDs after CLI export/import; #4436 concerns historical bundle identity compatibility; #4212 concerns producer selection of directory targets. These are different behaviors.

The existing filesystem comparison tests exercise duplicate-path source-map uncertainty; this fixture has one unambiguous source and one map. A separate constructed-graph probe changed only a semantic edge parent and obtained whole-comparison unchanged; that probe is excluded from the valid-file reproduction above because ordinary inspection reachability of that isolated graph pair was not established.

Triage assessment

  • Impact level: P2
  • Assessment status: provisional
  • Impact basis: The executed normal-input comparison omits an observed content-bound source-map relationship change from its per-path delta. Overall change detection works; the interpretation that the relation should track the mapped content identity follows the edge identity contract, but maintainer intent about path-only relationship equivalence remains unconfirmed.
  • Workaround status: available
  • Workaround basis: The complete production inventories retain different maps-source parent_artifact_id values, which were directly inspected; callers can compare these edges manually instead of relying solely on changes[].
Originally created by @coygeek on GitHub (Oct 23, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/6706 ### 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 Two ordinary directory inventories contain `main.js` and identical `main.js.map` bytes. Changing only an inert comment in `main.js` changes the source map's `maps-source` edge: its `parent_artifact_id` now identifies different JavaScript content. `compare_artifacts` omits `main.js.map` from `changes` and counts it as unchanged. The overall result correctly says `changed`, with changes for `.` and `main.js`. This report concerns the missing relationship change on the map, not whole-bundle false equality. Both inventories came from the inventory engine without editing their nodes, occurrences, edges, or identities. The result was observed through the domain comparison and the registered public MCP tool over local stdio. ### Reproduction From the built repository root, run this reduced fixture using the production inventory and comparison boundaries: ```sh mkdir -p /tmp/rea-repro node --input-type=module <<'JS' import { mkdir, writeFile } from 'node:fs/promises'; import { inventoryArtifact } from './dist/artifacts/inventory/ArtifactInventory.js'; import { ArtifactResourceScope } from './dist/artifacts/ArtifactResourceScope.js'; import { createEvidence } from './dist/domain/evidence.js'; import { compareArtifacts } from './dist/domain/artifactComparison.js'; const records = []; for (const [side, source] of [ ['left', '/* revision one */\n'], ['right', '/* revision two */\n'] ]) { const path = '/tmp/rea-repro/' + side; await mkdir(path, { recursive: true }); await writeFile(path + '/main.js', source); await writeFile(path + '/main.js.map', '{"version":3,"sources":[],"names":[],"mappings":""}'); const resources = new ArtifactResourceScope(); try { const graph = await inventoryArtifact(path, { resourceScope: resources }); records.push(createEvidence( { path, sha256: graph.manifest.root_sha256, format: 'directory' }, { id: 'rea-artifact-graph', name: 'REA artifact graph', version: '1' }, { operation: 'inventory_artifact', parameters: {}, result: graph } )); } finally { await resources.close(); } } const [left, right] = records; const mappedParent = record => record.normalized_result.edges .find(edge => edge.relation === 'maps-source').parent_artifact_id; const changed = compareArtifacts(left, right); console.log(JSON.stringify({ mapped_parent_changed: mappedParent(left) !== mappedParent(right), comparison: changed }, null, 2)); JS ``` Executed once with these file contents through the production domain boundary, followed by one public MCP comparison of the same unmodified Evidence pair. The MCP baseline `compare_artifacts({left, right: left})` was executed once and returned three unchanged occurrences. No JavaScript target was executed, semantic parser used, or source map fetched. ### Expected behavior Preserve a changed semantic relationship parent in the comparison. When an existing map now has a `maps-source` edge to different artifact content, include a relationship change for that map, or explicitly expose that this relationship dimension is not compared. The [edge identity contract](https://github.com/morluto/rea/blob/8c4f96ef4759fd78da66c4b9726825ca71d7ee0c/src/domain/artifactIdentity.ts#L112-L129) calls the parent artifact part of the semantic relationship. The [producer](https://github.com/morluto/rea/blob/8c4f96ef4759fd78da66c4b9726825ca71d7ee0c/src/artifacts/inventory/ArtifactGraphConstruction.ts#L359-L379) assigns a map's semantic parent from the mapped source, which differs from the containing directory. The comparison already advertises a [relations dimension](https://github.com/morluto/rea/blob/8c4f96ef4759fd78da66c4b9726825ca71d7ee0c/src/domain/artifactComparison.ts#L477-L480). ### Impact and scope An analyst using the per-path delta cannot see that an unchanged map file now describes a different content-addressed source artifact. The reproduction's `unchanged: 1` is the map even though its semantic edge differs. Whole-bundle change detection remains correct. Observed on one minimal supported directory pair; shipped-application prevalence and maintainer intent about content-bound relationship comparison are NOT_ENOUGH_INFO. Manual inspection of each inventory's `maps-source` edge reveals the different parent identities and is an available workaround. No data mutation or corruption was observed. ### REA version `rea-agents` 6.7.0; commit `8c4f96ef4759fd78da66c4b9726825ca71d7ee0c`. ### Runtime and platform Node.js v26.12.1; Linux x64. Other runtimes and platforms were not tested. ### Target and artifact context Two local directories containing an inert JavaScript comment file and a version-3 source-map JSON file. Complete production inventories; no edited graph records or recomputed identities. ### Interface MCP ### Earliest failure stage Transport or result projection ### Relevant output or evidence The production inventories yielded different `maps-source.parent_artifact_id` values: ```text left: art_873671fb6052d766a7e6883fa15c172000b696861bb0e82967711ba2ddf76584 right: art_208b2dee33b276d7abb200787c51fcc4cb403a48ac34078ce73b0bc717cec0ec ``` Relevant projection of the observed public MCP result: ```json { "status": "changed", "summary": {"unchanged": 1, "changed": 2, "unknown": 0}, "changes": [ {"logical_path": ".", "dimensions": ["content"]}, {"logical_path": "main.js", "dimensions": ["content", "relations"]} ], "limitations": [] } ``` The same-input baseline returned `status: unchanged`, `summary.unchanged: 3`, and `changes: []`. No post-fix run, full suite, installed-package comparison, or other-platform check was performed. ### Typed outcome or recovery expected A `changed` relationship entry for `main.js.map`, preserving citations to both inventories. Otherwise return an explicit limitation that semantic edge parent changes are outside the comparison. ### Analysis or suspected cause Source-derived: [relationsByPath](https://github.com/morluto/rea/blob/8c4f96ef4759fd78da66c4b9726825ca71d7ee0c/src/domain/artifactComparison.ts#L521-L552) replaces the edge's semantic parent with the occurrence's containing-directory path and omits `edge.parent_artifact_id`. Consequently, a map's relation projection is identical when its mapped source content changes. Containment normalization avoids cascading root identity changes, but applies the same normalization to `maps-source` edges whose semantic parent is a sibling file. ### Additional context Searched both open and closed issues for evidence-bundle, artifact-comparison, and source-map comparison reports, and checked the supplied open-issue title index. No matching report found. #5452 concerns unresolved linked inventory IDs after CLI export/import; #4436 concerns historical bundle identity compatibility; #4212 concerns producer selection of directory targets. These are different behaviors. The existing filesystem comparison tests exercise duplicate-path source-map uncertainty; this fixture has one unambiguous source and one map. A separate constructed-graph probe changed only a semantic edge parent and obtained whole-comparison `unchanged`; that probe is excluded from the valid-file reproduction above because ordinary inspection reachability of that isolated graph pair was not established. ## Triage assessment - Impact level: P2 - Assessment status: provisional - Impact basis: The executed normal-input comparison omits an observed content-bound source-map relationship change from its per-path delta. Overall change detection works; the interpretation that the relation should track the mapped content identity follows the edge identity contract, but maintainer intent about path-only relationship equivalence remains unconfirmed. - Workaround status: available - Workaround basis: The complete production inventories retain different maps-source parent_artifact_id values, which were directly inspected; callers can compare these edges manually instead of relying solely on changes[].
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#4075
No description provided.