[GH-ISSUE #4520] [Bug] compare_application_versions reports identical modules as changed when only their byte location moved (Bitwarden 2026.9.1 → 2026.10.0: 0 unchanged) #1797

Closed
opened 2026-10-16 21:10:20 +00:00 by bsakaguchi · 5 comments
Owner

Originally created by @Rinkia on GitHub (Oct 16, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/4520

Before submitting

  • I searched the open and closed issues for a related report (compare_application_versions location, version comparison location changed, application versions unchanged). Related: #3955 (managed runtime locations in version comparison, a different input) and #4020 (structural fingerprint semantics).
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Evidence, artifacts, or reconstruction

Observed behavior

I compared two public Bitwarden desktop releases' Webpack-bundled main.js (analyze_javascript_application --source-path main.js on each ASAR, then compare_application_versions). The matching is right:

  • matching.exact_module_source_digest: 1123, which is exactly the number of Webpack modules whose source text is byte-identical between the two bundles in my independent reference.

But every one of those pairs is classified changed, and the summary becomes:

{"unchanged":0,"added":0,"removed":0,"changed":1323,"unknown":1168}

The changed dimensions show why:

node_kind:dimensions items
javascript-module:location 1107
ipc-channel:location 34
endpoint:location 12
electron-preload:location 1
javascript-module:location+relationships 16
javascript-module:content+location+properties 2
others (asar-entry, artifact, … properties/content) 151

1,154 items differ only in location, i.e. their byte offset in main.js. Any edit early in a bundle shifts every later module. All 34 IPC channel names are the same literal set in both versions (independently extracted), yet all 34 channels are changed by location alone.

So a reader of the summary (or an agent) can't tell "2 modules were edited" from "1,323 things changed". The per-item dimensions are correct, but the top-level classification and summary hide them.

Reproduction

  • Bitwarden-2026.9.1-amd64.deb (sha256 da5e0177da10805152268ee9d29cbaf278c4ea10650b0ebcd03c5697537fab82) and Bitwarden-2026.10.0-amd64.deb (fcabfc7da3c327e2625b105e951cee4e60703bb8e256f0aac9cc9bc83ec7063f), both from https://github.com/bitwarden/clients/releases; both digests match the GitHub assets.
  • opt/Bitwarden/resources/app.asar → main.js (5,082,597 and 5,042,030 bytes).
  • rea analyze-javascript-application <asar> --source-path main.js --format json for each, then rea compare-application-versions '{"left":<9.1 Evidence>,"right":<10.0 Evidence>}'.
  • Independent reference: parse each bundle with @babel/parser (no execution) and hash every __webpack_modules__ entry's source text. The result is 1,162 vs 1,153 modules: 1,123 identical, 29 same ID with new content, 10 only in 9.1, 1 only in 10.0.

rea-agents@6.5.0. I didn't run this on main; the comparison sources show no related change since 6.5.0.

Expected behavior

A pair matched by exact content or module-source digest, whose only differing dimension is location, should not count as a content change. Either:

  • classify it unchanged (keeping location in its dimensions or a moved flag); or
  • add a distinct status (moved, relocated) and a summary bucket for it.

The summary would then show about 1,150 unchanged-or-moved items next to the few real content and relationship changes. Documenting how location is treated would also help (docs/javascript-application-workflows.md, "Version comparison").

Impact and scope

Any version comparison of bundled JavaScript, where location shifts are the norm. Tested: one real pair as above.

Originally created by @Rinkia on GitHub (Oct 16, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4520 ### Before submitting - [x] I searched the open and closed issues for a related report (compare_application_versions location, version comparison location changed, application versions unchanged). Related: #3955 (managed runtime locations in version comparison, a different input) and #4020 (structural fingerprint semantics). - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Evidence, artifacts, or reconstruction ### Observed behavior I compared two public Bitwarden desktop releases' Webpack-bundled `main.js` (`analyze_javascript_application --source-path main.js` on each ASAR, then `compare_application_versions`). The matching is right: - `matching.exact_module_source_digest: 1123`, which is exactly the number of Webpack modules whose source text is byte-identical between the two bundles in my independent reference. But every one of those pairs is classified `changed`, and the summary becomes: ```json {"unchanged":0,"added":0,"removed":0,"changed":1323,"unknown":1168} ``` The changed dimensions show why: | `node_kind:dimensions` | items | |---|---:| | `javascript-module:location` | 1107 | | `ipc-channel:location` | 34 | | `endpoint:location` | 12 | | `electron-preload:location` | 1 | | `javascript-module:location+relationships` | 16 | | `javascript-module:content+location+properties` | 2 | | others (`asar-entry`, `artifact`, … `properties`/`content`) | 151 | 1,154 items differ **only** in `location`, i.e. their byte offset in `main.js`. Any edit early in a bundle shifts every later module. All 34 IPC channel names are the same literal set in both versions (independently extracted), yet all 34 channels are `changed` by location alone. So a reader of the summary (or an agent) can't tell "2 modules were edited" from "1,323 things changed". The per-item `dimensions` are correct, but the top-level classification and summary hide them. ### Reproduction - `Bitwarden-2026.9.1-amd64.deb` (sha256 `da5e0177da10805152268ee9d29cbaf278c4ea10650b0ebcd03c5697537fab82`) and `Bitwarden-2026.10.0-amd64.deb` (`fcabfc7da3c327e2625b105e951cee4e60703bb8e256f0aac9cc9bc83ec7063f`), both from https://github.com/bitwarden/clients/releases; both digests match the GitHub assets. - `opt/Bitwarden/resources/app.asar` → `main.js` (5,082,597 and 5,042,030 bytes). - `rea analyze-javascript-application <asar> --source-path main.js --format json` for each, then `rea compare-application-versions '{"left":<9.1 Evidence>,"right":<10.0 Evidence>}'`. - Independent reference: parse each bundle with `@babel/parser` (no execution) and hash every `__webpack_modules__` entry's source text. The result is 1,162 vs 1,153 modules: 1,123 identical, 29 same ID with new content, 10 only in 9.1, 1 only in 10.0. `rea-agents@6.5.0`. I didn't run this on `main`; the comparison sources show no related change since 6.5.0. ### Expected behavior A pair matched by exact content or module-source digest, whose only differing dimension is `location`, should not count as a content change. Either: - classify it `unchanged` (keeping `location` in its dimensions or a `moved` flag); or - add a distinct status (`moved`, `relocated`) and a summary bucket for it. The summary would then show about 1,150 unchanged-or-moved items next to the few real content and relationship changes. Documenting how `location` is treated would also help (`docs/javascript-application-workflows.md`, "Version comparison"). ### Impact and scope Any version comparison of bundled JavaScript, where location shifts are the norm. Tested: one real pair as above.
Author
Owner

@morluto commented on GitHub (Oct 17, 2026):

Published on main in 556504edc (fix(javascript): distinguish relocation from application changes).

Location-only paired items now count as unchanged when both graphs are complete. Their location dimension, both node IDs, and both observations/coordinates remain available. Content/property changes remain definite, complete relationship changes remain changed, and incomplete coverage remains unknown where it prevents a conclusion. Pairing tiers and confidence are preserved. The result uses the existing statuses and schema.

Controlled reproduction: the compiled public CLI analyzed two tiny Webpack bundles differing only by an earlier comment, then compared their retained Evidence. Before the fix, the identical factories were classified changed by location; afterward they are unchanged while the edited containing asset stays changed. A clean baseline at 1e36e707b also fails five of six corrected domain controls; the complete relationship-change control already passes. All six pass with the fix. The original Bitwarden releases were not rerun.

Executed validation:

  • 29 focused tests across seven domain/change-graph/compiled-CLI files.
  • Seven CLI/MCP boundary tests across three files, including inline and retained Evidence, schema advertisement and SDK transport.
  • Final strengthened CLI regression rerun, npm run check:fast, npm run docs:check including five conformance tests, and normal commit/push hooks.

Completed comparison of retained real CLI analysis Evidence, including input authentication, graph comparison, change-graph construction and full Evidence serialization: two alternating warm filesystem repeats, baseline/candidate elapsed 110.38/109.92ms, CPU 138.10/135.01ms, sampled family RSS 106.08/89.53MB, raw cl100k_base complete reply tokens 15,253/14,211. Separate first processes recorded; caches not flushed. The inputs are identical; the baseline's incorrect classifications are intentionally corrected. Source nodes, observations, source relationships, matching and coverage were checked equal between outputs; only classification-derived facts change. CPU uses wait4; sampled RSS can miss peaks. No speed or memory improvement claim from this small sample. Whole-agent/catalog/retry, CLI/MCP adapter overhead, input analysis, cancellation and large-bundle costs remain unmeasured. No target execution or heavy profiling.

The nearby unresolved relationship-target alignment defect is tracked independently in #4681. It predates this change and requires preserving identity uncertainty at the relationship producer; this fix does not force any ambiguous node pair.

<!-- gh-comment-id:6229719232 --> @morluto commented on GitHub (Oct 17, 2026): Published on main in 556504edc (`fix(javascript): distinguish relocation from application changes`). Location-only paired items now count as `unchanged` when both graphs are complete. Their `location` dimension, both node IDs, and both observations/coordinates remain available. Content/property changes remain definite, complete relationship changes remain changed, and incomplete coverage remains unknown where it prevents a conclusion. Pairing tiers and confidence are preserved. The result uses the existing statuses and schema. Controlled reproduction: the compiled public CLI analyzed two tiny Webpack bundles differing only by an earlier comment, then compared their retained Evidence. Before the fix, the identical factories were classified changed by location; afterward they are unchanged while the edited containing asset stays changed. A clean baseline at 1e36e707b also fails five of six corrected domain controls; the complete relationship-change control already passes. All six pass with the fix. The original Bitwarden releases were not rerun. Executed validation: - 29 focused tests across seven domain/change-graph/compiled-CLI files. - Seven CLI/MCP boundary tests across three files, including inline and retained Evidence, schema advertisement and SDK transport. - Final strengthened CLI regression rerun, `npm run check:fast`, `npm run docs:check` including five conformance tests, and normal commit/push hooks. Completed comparison of retained real CLI analysis Evidence, including input authentication, graph comparison, change-graph construction and full Evidence serialization: two alternating warm filesystem repeats, baseline/candidate elapsed 110.38/109.92ms, CPU 138.10/135.01ms, sampled family RSS 106.08/89.53MB, raw cl100k_base complete reply tokens 15,253/14,211. Separate first processes recorded; caches not flushed. The inputs are identical; the baseline's incorrect classifications are intentionally corrected. Source nodes, observations, source relationships, matching and coverage were checked equal between outputs; only classification-derived facts change. CPU uses wait4; sampled RSS can miss peaks. No speed or memory improvement claim from this small sample. Whole-agent/catalog/retry, CLI/MCP adapter overhead, input analysis, cancellation and large-bundle costs remain unmeasured. No target execution or heavy profiling. The nearby unresolved relationship-target alignment defect is tracked independently in #4681. It predates this change and requires preserving identity uncertainty at the relationship producer; this fix does not force any ambiguous node pair.
Author
Owner

@morluto commented on GitHub (Oct 17, 2026):

Follow-up in 4d980d017 for #4681: complete inventory alone cannot establish relationship alignment. The tiny relocation fixture's containing chunk has no cross-version match, so its exact factory bytes and location-only difference remain explicit while overall item status is now unknown with a relationship-identity limitation. This is not counted as a content change. Fully resolved location-only pairs still classify unchanged, as covered by the domain regression.

The source-directory sibling control has the same distinction: exact main-file pairing remains exact, while its unpaired changed neighbor prevents an unchanged relationship conclusion. Source observations, source edges, candidate sets, and confidence are preserved. Final CLI/MCP/domain validation and measured cost limitations are recorded in the #4681 publication comment.

<!-- gh-comment-id:6229846808 --> @morluto commented on GitHub (Oct 17, 2026): Follow-up in 4d980d017 for #4681: complete inventory alone cannot establish relationship alignment. The tiny relocation fixture's containing chunk has no cross-version match, so its exact factory bytes and location-only difference remain explicit while overall item status is now `unknown` with a relationship-identity limitation. This is not counted as a content change. Fully resolved location-only pairs still classify unchanged, as covered by the domain regression. The source-directory sibling control has the same distinction: exact main-file pairing remains exact, while its unpaired changed neighbor prevents an unchanged relationship conclusion. Source observations, source edges, candidate sets, and confidence are preserved. Final CLI/MCP/domain validation and measured cost limitations are recorded in the #4681 publication comment.
Author
Owner

@Rinkia commented on GitHub (Oct 18, 2026):

Re-ran the Bitwarden pair from the report on the published rea-agents@6.7.0. That release includes 556504edc and 4d980d017. I used the same .deb digests and the same commands: analyze-javascript-application <app.asar> --source-path main.js, then compare-application-versions.

6.5.0 6.7.0
unchanged 0 0
changed 1,323 152
unknown 1,168 2,342
exact_module_source_digest matches 1,123 1,123

The 1,107 javascript-module items that differed only by location are no longer changed. They are now unknown, with dimensions location+coverage and the limitations "Incomplete graph coverage prevents a complete node-level conclusion." and "Relationship target identity remains unresolved…". The 34 IPC channels (location+coverage) and 13 endpoints behave the same way. The remaining changed items are ASAR entries and artifacts (properties/content) plus the one module with a real content change. That fixes the original problem: relocation no longer reads as a change.

One follow-up question. As far as I can tell, these graphs are incomplete because --source-path main.js selects one file out of the ASAR. source_selection.unselected_files is 74 and 78, and graph coverage.status is partial on both sides. That is the scoped workflow the docs recommend for large Electron apps. If so, can a location-only pair from a scoped analysis ever be classified unchanged, or is unknown the intended result for every scoped comparison? If unknown is intended, I think a one-line note in the version-comparison docs would help. I'm not asking for a behaviour change.

<!-- gh-comment-id:6249959192 --> @Rinkia commented on GitHub (Oct 18, 2026): Re-ran the Bitwarden pair from the report on the published `rea-agents@6.7.0`. That release includes 556504edc and 4d980d017. I used the same `.deb` digests and the same commands: `analyze-javascript-application <app.asar> --source-path main.js`, then `compare-application-versions`. | | 6.5.0 | 6.7.0 | |---|---:|---:| | unchanged | 0 | 0 | | changed | 1,323 | 152 | | unknown | 1,168 | 2,342 | | `exact_module_source_digest` matches | 1,123 | 1,123 | The 1,107 `javascript-module` items that differed only by `location` are no longer `changed`. They are now `unknown`, with dimensions `location+coverage` and the limitations "Incomplete graph coverage prevents a complete node-level conclusion." and "Relationship target identity remains unresolved…". The 34 IPC channels (`location+coverage`) and 13 endpoints behave the same way. The remaining `changed` items are ASAR entries and artifacts (properties/content) plus the one module with a real content change. That fixes the original problem: relocation no longer reads as a change. One follow-up question. As far as I can tell, these graphs are incomplete because `--source-path main.js` selects one file out of the ASAR. `source_selection.unselected_files` is 74 and 78, and graph `coverage.status` is `partial` on both sides. That is the scoped workflow the docs recommend for large Electron apps. If so, can a location-only pair from a scoped analysis ever be classified `unchanged`, or is `unknown` the intended result for every scoped comparison? If `unknown` is intended, I think a one-line note in the version-comparison docs would help. I'm not asking for a behaviour change.
Author
Owner

@CassieFox23 commented on GitHub (Oct 18, 2026):

Checked on Linux: this is fixed on main by 556504edc. The commit's message says "Refs #4520", which is why GitHub left this issue open.

  • src/domain/javascript/javascriptApplicationVersionRelocation.test.ts and tests/acceptance/applications/applicationVersionRelocationCli.test.ts pass on main 36d156ff0 on Node 22.23.1, 24.18.0 and 26.11.1 (6 and 2 tests).
  • On the commit's parent, 6 of 7 fail, expected 'changed' to be 'unknown'.
  • No test checks the docs sentence about location.

Thanks, Rinkia, for the clear report.

If nothing else is open here, this can be closed.

🤖 Generated with Claude Code (Sonnet 5.5, verified by Opus 5.5) 🦊

<!-- gh-comment-id:6254887416 --> @CassieFox23 commented on GitHub (Oct 18, 2026): Checked on Linux: this is fixed on main by 556504edc. The commit's message says "Refs #4520", which is why GitHub left this issue open. - `src/domain/javascript/javascriptApplicationVersionRelocation.test.ts` and `tests/acceptance/applications/applicationVersionRelocationCli.test.ts` pass on main 36d156ff0 on Node 22.23.1, 24.18.0 and 26.11.1 (6 and 2 tests). - On the commit's parent, 6 of 7 fail, `expected 'changed' to be 'unknown'`. - No test checks the docs sentence about location. Thanks, Rinkia, for the clear report. If nothing else is open here, this can be closed. 🤖 Generated with Claude Code (Sonnet 5.5, verified by Opus 5.5) 🦊
Author
Owner

@morluto commented on GitHub (Oct 18, 2026):

Closing as fixed on main after reconciling this report with the landed owner/consumer changes.

  • 556504edc: fix(javascript): distinguish relocation from application changes. Validated with focused domain, compiled CLI and MCP workflows, static checks and docs checks. A tiny public CLI bundle fixture reproduces the issue; the reported Bitwarden releases were not rerun.

Evidence scope: this closure uses the landed source, regression coverage and validation already recorded in the linked commits/thread. No new local tests or native-provider reproduction were run during this backlog pass; previously documented platform and real-provider gaps still apply.

<!-- gh-comment-id:6256008606 --> @morluto commented on GitHub (Oct 18, 2026): <!-- rea-backlog-reconciliation-2026-10-19-4520 --> Closing as fixed on `main` after reconciling this report with the landed owner/consumer changes. - [556504edc](https://github.com/morluto/rea/commit/556504edcbb0f8cd9eaf81a91b18ff891b8f5457): fix(javascript): distinguish relocation from application changes. Validated with focused domain, compiled CLI and MCP workflows, static checks and docs checks. A tiny public CLI bundle fixture reproduces the issue; the reported Bitwarden releases were not rerun. Evidence scope: this closure uses the landed source, regression coverage and validation already recorded in the linked commits/thread. No new local tests or native-provider reproduction were run during this backlog pass; previously documented platform and real-provider gaps still apply.
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#1797
No description provided.