Skip to content

Commit 508d06a

Browse files
committed
docs(review): write back what actually shipped, and what did not
Both audit docs had drifted from the code, and a stale status doc is worse than none: two closed SEV1s were read as open during a later pass, and one of them had been fixed in another repo weeks earlier. `OPEN-FINDINGS.md` claimed its contents were uncommitted work in the tree, on a `main` that has since moved several hundred commits. Three items it listed as open were re-checked in the source and are closed — D1 (both native receivers route `input` now, via `routeInput` + `BridgeInputMapper`), D2's first SEV2 (the unreachable `try/catch` is gone), D3 (the SRI guard shipped on both sides). Each is annotated where it sits, not only in the new summary, because a reader lands mid-document. What genuinely remains is named: D2's `controller.ts` global slot, which is owed one clean §6 round, and electron's `flush()` not waiting for renderers. `cli-js-flows.md` recorded resolutions for 3 of its 8 findings while 5 had moved: §4 dry-run and §8 strip shipped in CLI 0.7.11, §7's guard shipped on both sides (with the two SEV1s found reviewing the first cut, both of which looked correct), §5 became issue #8, and §3's PREMISE was disproven rather than fixed — a debug-id on a map-less bundle is what lets the worker report `missing_sym` and name the artefact nobody uploaded, so skipping those bundles would trade a diagnostic for a few bytes. §7 and §3 also record what is still open, so neither reads as finished: stamping during `processAssets` is still the only fix correct for lazy-chunk hashes. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
1 parent aea3da3 commit 508d06a

2 files changed

Lines changed: 91 additions & 12 deletions

File tree

‎docs/review/OPEN-FINDINGS.md‎

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,37 @@
11
# Open findings — fix wave of 2026-08-27/28
22

3-
Live status doc for the in-flight fix + convergent-review cycle, in the shape of
4-
`docs/review/REMEDIATION-PLAN.md`. **Read this before touching the working tree.**
3+
Live status doc for the fix + convergent-review cycle, in the shape of
4+
`docs/review/REMEDIATION-PLAN.md`.
55

6-
## State at hand-off
6+
## Status — re-verified 2026-09-22 against the code, not against this file
7+
8+
**Everything in this document is COMMITTED and on `main`.** The hand-off note below is kept for the
9+
record but no longer describes reality: it says the work is uncommitted, and `main` has since moved
10+
several hundred commits past `36ec616`. `git status` is clean.
11+
12+
Three items were re-checked in the source because this file still listed them as open. All three are
13+
**closed**, and each is annotated in place below:
14+
15+
| item | this file said | the code says |
16+
|---|---|---|
17+
| **D1** WebView `input` dropped by both native receivers (SEV1) | blocked on a human decision | **CLOSED** — `BridgeCaptureRouter.java` routes `input` via `routeInput`, and `BGSBridgeCaptureRouter.m:223` does the same on iOS. Both landed, with `BridgeInputMapper` mapping page coordinates into the native frame. |
18+
| **D2** first SEV2 — unreachable `try/catch` around `getAttributes()` | still unfixed | **CLOSED** — `server-instrument.ts:517-520` is a direct read now, with a comment giving the reason no catch is needed. |
19+
| **D3** source-map stamping breaks SRI (SEV1) | reproduced, unfixed | **CLOSED** — guards shipped on both the CLI (0.7.11) and the plugin. See `docs/review/cli-js-flows.md` §7, which carries the detail and the one part still open. |
20+
21+
**Still genuinely open**, and the reason this file is worth keeping:
22+
23+
- **D2's second SEV2** — `performance/src/controller.ts`'s module-global `active` slot. Partly closed:
24+
`activeSpanStore` was built for the node server path (see "D2 part 2" below). The last review round
25+
(2026-09-15) fixed 2 SEV2 + 8 SEV3 and **no fresh round has run since**, so CLAUDE.md §6 convergence
26+
is owed one clean pass before this can be called done.
27+
- **`electron/src/launch-main.ts:203-204`** — `flush()` does not wait for renderers (marked OPEN (minor)
28+
below, still true). Carrying a deadline is a bridge wire change.
29+
30+
A stale status doc is worse than no status doc: two of the three closed items above were read as open
31+
SEV1s during a later pass, and one of them had been fixed in another repo weeks earlier. If you close
32+
something listed here, say so here.
33+
34+
## State at hand-off (2026-08-28 — superseded, kept for the record)
735

836
Everything below is **uncommitted work in the working tree** on `main` (80 entries in
937
`git status`, last commit `36ec616`). Nothing has been committed or pushed. The tree is
@@ -225,9 +253,17 @@ it can only keep more markers, never delete more. No configuration can hold mark
225253

226254
---
227255

228-
## Blocked on a human decision
256+
## Blocked on a human decision — D1 and D3 since CLOSED; only D2's second half remains
229257

230-
### D1 · WebView `input` stream is dropped by both native receivers — **SEV1**
258+
### D1 · WebView `input` stream is dropped by both native receivers — ~~**SEV1**~~ **CLOSED 2026-09-22**
259+
260+
> **Closed — both receivers landed the branch.** Android: `BridgeCaptureRouter.java` dispatches
261+
> `"input"` to `routeInput`, which maps each point through `BridgeInputMapper` (viewport CSS px →
262+
> native screen coordinates ÷ density) before handing it to the native input consumer. iOS:
263+
> `BGSBridgeCaptureRouter.m:223` — `else if ([fileType isEqualToString:@"input"]) [self routeInput:entry];`.
264+
> Neither option below was taken in the end: the wire change was completed rather than reverted. The
265+
> original text is kept because the mapper's existence is the reason `@bugsee/webview` must NOT emit
266+
> its own `video.aux` — see `packages/webview/src/launch.ts`.
231267
232268
`@bugsee/webview` moved off `events.user` onto the new `input` stream (correct: SDK code must
233269
never write to a `*.user` stream). Both native routers are `if/else if` chains with **no
@@ -257,8 +293,11 @@ app's own `client.addBreadcrumb()` calls have always streamed over the bridge.
257293

258294
Confirmed independently by two reviewers, still unfixed:
259295

260-
- `packages/node/src/server-instrument.ts:479-483` — a `try/catch` around `getAttributes()`
261-
that is **unreachable in production** (`getAttributes` is a required, non-throwing member of
296+
- **CLOSED 2026-09-22.** `server-instrument.ts:517-520` reads `getAttributes()` directly now, with a
297+
comment stating why no defensive catch belongs there (it is a required, non-throwing member of
298+
`Span`, and an outer catch already covers a hostile Transaction). The original finding follows.
299+
~~`packages/node/src/server-instrument.ts:479-483` — a `try/catch` around `getAttributes()`
300+
that is **unreachable in production**~~ (`getAttributes` is a required, non-throwing member of
262301
`Span`, and `finishWith` already sits inside an outer catch). What it actually accommodates is
263302
**nine `Transaction` test doubles across seven adapter packages** that omit the method, so
264303
every one of their `setName` assertions now passes via the degraded path and **F-4 is untested
@@ -274,7 +313,14 @@ Confirmed independently by two reviewers, still unfixed:
274313

275314
---
276315

277-
### D3 · Source-map stamping breaks Subresource Integrity — **SEV1**, reproduced 2026-09-18
316+
### D3 · Source-map stamping breaks Subresource Integrity — ~~**SEV1**~~ **CLOSED 2026-09-19**
317+
318+
> **Closed — the detect-and-refuse guard shipped on both sides**, the CLI (`bugsee-cli` 0.7.11,
319+
> `src/inject/sri.rs`, `--allow-sri` to override) and the plugin
320+
> (`bundler-plugin-core/src/sri.ts`). Both, not one: a user driving the CLI by hand is not covered by a
321+
> plugin-side check. `docs/review/cli-js-flows.md` §7 carries the detail, the two SEV1s found while
322+
> reviewing the first cut, and the part that is still open — stamping during `processAssets`, before
323+
> the hashes are computed, which is the only fix correct for runtime-embedded lazy-chunk hashes.
278324
279325
`@bugsee/bundler-plugin-core` runs `bugsee-cli sourcemaps inject` at webpack's `afterEmit` /
280326
unplugin's `writeBundle`, which appends bytes to every emitted `.js` AFTER the bundler computed its

‎docs/review/cli-js-flows.md‎

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ design and only a genuine failure fails the build.
5656
`@bugsee/bundler-plugin-core` passes it — except under `failOnError`, where a team that asked for strictness
5757
still hears that their build produced no maps at all. A path that does not exist stays an error either way.
5858

59-
### 3. `inject` stamps every bundle, including ones with no map (SEV3, measured)
59+
### 3. `inject` stamps every bundle, including ones with no map (SEV3, measured) — **PREMISE DISPROVEN, closed 2026-09-19**
6060

6161
`inject_paths` walks every `.js`/`.cjs`/`.mjs` and appends the runtime registration whether or not the
6262
bundle has a paired map. Measured on a real `next build` (`productionBrowserSourceMaps: true`):
@@ -68,7 +68,15 @@ Costs: pointless bytes in every server bundle, third-party files modified, and a
6868
with no map is exactly the case where the id is useless, so skipping it (or an `--exclude` glob, or
6969
skipping `node_modules`) is free.
7070

71-
### 4. The whole flow cannot be dry-run (SEV3, verified in code + measured earlier)
71+
**Closed 2026-09-19 — the premise above is wrong, and the finding is withdrawn rather than fixed.** "A
72+
bundle with no map has a useless id" does not hold: the worker treats a debug-id it cannot resolve as
73+
`missing_sym` (`crash/javascript.py:406,467`), which is how a crash tells the operator WHICH artefact
74+
was never uploaded. Strip the id from those bundles and the frame arrives anonymous — the backend can no
75+
longer name what is missing, and the most common real cause (server maps that were never turned on, §8)
76+
becomes invisible. The stamped bytes are the price of that diagnostic. `--exclude` was still added for
77+
callers who want it, but skipping map-less bundles by DEFAULT would trade a diagnostic for a few bytes.
78+
79+
### 4. The whole flow cannot be dry-run (SEV3, verified in code + measured earlier) — **SHIPPED (CLI 0.7.11 + `@bugsee/bundler-plugin-core`)**
7280

7381
`sourcemaps inject --dry-run` writes nothing, so the maps still carry no debug-id, and
7482
`debug-files upload --dry-run` over the same directory then **fails with exit 11**. The JS plugin works
@@ -78,7 +86,7 @@ comment). So the one option documented as the safe diagnostic cannot exercise th
7886
Either `inject --dry-run` should report the ids it would write, or `upload --dry-run` should accept a
7987
map with no id when it is only packing.
8088

81-
### 5. A symbol upload cannot carry the commit it came from (SEV2, verified in code)
89+
### 5. A symbol upload cannot carry the commit it came from (SEV2, verified in code) — **TRACKED: [bugsee-javascript#8](https://github.com/bugsee/bugsee-javascript/issues/8)**
8290

8391
`bundler-plugin-core` already collects VCS metadata (`vcs.ts`, 315 lines: commit SHA, branch, dirty
8492
state, CI provider) and then has nowhere to put it: `orchestrate.ts:44-50` carries it only to echo it
@@ -105,7 +113,7 @@ The CLI blocker named above is now precise: `upload build` requires `--artifact`
105113
normal — register the build, ship no bytes — is the one a web build cannot express. The register-only
106114
mode exists in Rust and is used by `xcode post-action`; nothing exposes it on the CLI.
107115

108-
### 7. Stamping after emit BREAKS Subresource Integrity (SEV1, reproduced 2026-09-18)
116+
### 7. Stamping after emit BREAKS Subresource Integrity (SEV1, reproduced 2026-09-18) — **(3) SHIPPED both sides; (1) still the real fix**
109117

110118
Confirmed, and it is the worst finding here: the app's entry script is blocked and nothing runs.
111119

@@ -143,6 +151,28 @@ all it can do. Three candidate fixes, none free:
143151

144152
At minimum the JS plugin must do (3); (1) is the real fix.
145153

154+
**Shipped 2026-09-19 — (3), on BOTH sides, because either alone leaves a hole.** The JS plugin scans the
155+
output directory before stamping (`bundler-plugin-core/src/sri.ts`, step 0 of `orchestrate`) and the CLI
156+
refuses independently (`bugsee-cli` `src/inject/sri.rs`, `--allow-sri` to override), so a user who drives
157+
the CLI by hand is covered too. Both read `<script>` AND `<link rel=modulepreload|preload>`, since a
158+
preload failing its integrity check poisons the module map just as hard.
159+
160+
Two SEV1s were found in review of the first attempt, both worth recording because both looked correct:
161+
162+
- a **CDN `publicPath`** build was stamped and shipped blank — the pinned URL resolved to nothing in the
163+
output tree, so the literal-path lookup missed it. Fixed with a file-name fallback.
164+
- a page under a dot-directory or `node_modules` was **skipped by the guard but stamped by the walk** —
165+
two different lists of files. Fixed by deriving both from one list. A test of mine had asserted that
166+
skip as correct behaviour.
167+
168+
Re-running on an already-stamped build used to exit 20 even though `--help` promises a no-op; the guard
169+
now mirrors `inject`'s own rewrite decision (`would_rewrite`), with a test pinning the two in agreement.
170+
171+
**(1) remains open and is still the real fix.** Stamping during `processAssets`, before the hashes are
172+
computed, is the only approach correct for the runtime-embedded lazy-chunk hashes as well as the HTML;
173+
it needs an in-memory stamping path the CLI does not offer. Until then the guard trades a broken page
174+
for a failed build, which is strictly better but is not the same as working.
175+
146176
### 8. Not a CLI gap, but in the same flow
147177

148178
- **Next.js server maps.** A stock `next build` emits maps for the client and for edge bundles only —
@@ -153,6 +183,9 @@ At minimum the JS plugin must do (3); (1) is the real fix.
153183
hand today.
154184
- **`sourcesContent`** rides into the upload with the map, which is how symbolication shows source lines.
155185
There is no `--strip-sources-content` for customers who would rather not ship source. Worth an option.
186+
— **SHIPPED (CLI 0.7.11 + the plugin's `stripSourcesContent`).** Review caught a SEV1 in the first cut:
187+
an INDEXED map (`sections[].map.sourcesContent`) kept shipping its source, silently, because only the
188+
top-level key was removed. The removal is recursive now.
156189

157190
## Evidence
158191
- Next.js: `packages/nextjs-e2e` built with `productionBrowserSourceMaps: true` (`next build`, exit 0),

0 commit comments

Comments
 (0)