Skip to content

Windows live findings: rescan (WV-2), engine log file (WV-3), bridge-identity probe (WV-4), empty-transport preview gate (WV-5) - #94

Merged
rohanpandula merged 4 commits into
mainfrom
fix/wv-findings
Aug 14, 2026
Merged

Windows live findings: rescan (WV-2), engine log file (WV-3), bridge-identity probe (WV-4), empty-transport preview gate (WV-5)#94
rohanpandula merged 4 commits into
mainfrom
fix/wv-findings

Conversation

@rohanpandula

@rohanpandula rohanpandula commented Aug 14, 2026

Copy link
Copy Markdown
Owner

What this fixes

Every finding from the first live Windows hardware validation except WV-1 (already shipped in beta.10) and WV-6 (deliberately deferred, see below):

  • WV-2 — restart-to-rescan: discovery attempted the bridge once at engine startup; a WSL stack that turned healthy later left the real scanner invisible until an app restart. New scanner.rescan engine method (idempotent, degrades to sim-only like startup, refused while connected) + a Rescan button in the device bar + PROTOCOL.md coverage in both copies.
  • WV-3 — no Windows logs: Start-menu launches discard stderr, so every engine diagnostic was lost (the live forensics ran on framebuffer screenshots). Engine stderr/error/termination now tee to a bounded app-log-dir file (1 MiB, one rotation, can never break the loop).
  • WV-4 — unbound bridge identity: a stale WSL bridge inherited through a VM clone passed bridge-which/bridge-version all session and then refused its first real capture on bundle identity. New bridge-identity checker probe hashes the deployed bridge's two capture-bundle identity files against the installed payload's CorrespondingSource copies; red offers the install-bridge-wsl.sh --force redeploy. Runbook documents the row; the runbook-consistency test enforces it.
  • WV-5 — silent empty-transport preview: a preview on an empty transport ran minutes of motion-adjacent work and completed with zero frames and no explanation. The engine now probes a fresh status (never a cached snapshot — a just-fed roll can't be falsely refused) after the preview approval window opens, and refuses typed NO_MEDIA before roll.preview when film is definitively absent; undetermined proceeds. A refusal retires the window token exactly like a refused roll.preview, and a rejected overlapping preview still makes zero bridge calls.
  • Relaunch race: the launcher now names the likely cause (previous WebView2 teardown) when the app exits within ten seconds of starting — previously this printed a fully armed-and-disarmed session with no hint.

Deferred: WV-6 (Tauri counterpart of the Mac manual-placement CTA on REFEED_REQUIRED) — a parity feature through the motion/binding path, not a defect fix; it stays on the findings ledger rather than being rushed here.

Verification

  • Film-absent e2e refusal is mutation-proven (disabling the gate fails the test with roll.preview reaching the mock's call log).
  • MOCK_BRIDGE_CRASH_ON gains an optional :N occurrence suffix and the WHILE_PREVIEW_PENDING hang now tracks a real requested-not-established flag, because the gate legitimately issues one pre-preview device.status. The overlap/quarantine/restart tests' call-log pins gained that same leading entry; their actual subjects (zero successor bridge calls, fenced reconnects) are unchanged and still asserted.
  • New coverage: three rescan unit tests, five bridge-identity probe tests (fake executor), log rotation, two DeviceBar rescan tests.
  • Suites: engine 25 green suites in each copy; Tauri crate 85; frontend 61 files / 440 passed / 6 skipped; vendor-sync gate green (engine-pair fingerprint re-pinned for identical two-sided edits).

Rounds 2 and 3 (two independent adversarial reviews)

Round 2 addressed the first review's blocker and required items: the film-presence probe runs under its own 30s deadline (PREVIEW_FILM_PROBE_DEADLINE) so the driver's legitimate ~10s adapter-status settle can never trip the generic 10s timeout whose expiry destroys the session; the bridge-identity probe now proves the whole driver (the deployed interpreter runs the driver's own all-components capture-bundle self-check on the copy it imports, plus a pin-table hash binding to the installed payload), honors XDG_DATA_HOME, resolves the payload through the Tauri resource dir with exe-dir fallback, and reports Unknown (not red) on dev/portable builds; rescanDevices runs under connectionChangePending; the log sink exists before the spawn attempt and records spawn failures; the runbook documents the log path; spawn_engine's displaced doc comment is restored.

Round 3 addressed the second review's remaining findings: a bridge child that fails its first handshake is terminated outright (the restart path's own terminate_uninitialized_child policy, never applied to the initial spawn) so repeated rescans during a slow bridge boot cannot orphan children contending for the scanner; rescan replaces a real backend whose bridge died (previously set-once, listed-but-dead forever); log entries are single atomic write_alls with projected-size rotation (mid-line interleaving across overlapping app instances was reachable, and a large entry could overshoot the cap); MOCK_BRIDGE_CRASH_ON fails loudly on malformed occurrence suffixes; the runbook's "five ids" lead-in says six.

Deliberately deferred, named by reviewers and accepted: rescan blocking the single dispatch thread during a cold bridge start (mitigated by the store-level busy interlock), the PROBE_IDS constant/test/runbook triplication (pre-existing), and epoch-seconds log timestamps.

…entity, film gate, launcher hint

Every change here traces to a finding from the first live Windows hardware
validation (WV-2 through WV-5 plus the relaunch race; WV-1 shipped in
beta.10):

- WV-2: device discovery ran only at engine startup, so a WSL bridge stack
  that became healthy afterwards left the real scanner invisible until a
  full app restart. New `scanner.rescan` method: one deliberate re-attempt
  of the real-backend startup, idempotent, degrading to the sim-only list
  exactly like startup does, and refused while connected so an active
  session's backend can never be swapped underneath it. The device bar
  gains a Rescan button (disabled while connected/busy). PROTOCOL.md
  documents the method in both copies.
- WV-3: a Start-menu launch discards this process's stderr, so every
  engine diagnostic was lost -- the live forensics had to run on
  framebuffer screenshots. Engine stderr/error/termination lines now tee
  to a bounded log (app log dir, 1 MiB, one rotation) that can never break
  the engine loop.
- WV-4: a stale WSL bridge (inherited through a VM clone from a commit
  window whose driver tree was internally inconsistent) passed
  bridge-which and bridge-version all session, then refused its first real
  capture on bundle identity. New `bridge-identity` checker probe: the
  deployed bridge's two capture-bundle identity files (bundle.py,
  usb_backend.py) must hash byte-identically to the installed payload's
  CorrespondingSource copies; red offers the install-bridge-wsl.sh --force
  redeploy as its fix text. The runbook documents the row (and the
  runbook-consistency test enforces that documentation).
- WV-5: a preview on an empty transport spent minutes in motion-adjacent
  work and completed with zero frames and no explanation. The engine now
  probes a fresh status -- the same live path scanner.status uses, never a
  cached snapshot, so a just-fed roll cannot be falsely refused -- after
  the preview approval window opens and refuses typed (NO_MEDIA) before
  roll.preview when film is definitively absent; an undetermined probe
  proceeds. Placed after the window opens so a rejected overlapping
  preview still makes zero bridge calls; a refusal retires the window
  token exactly like a refused roll.preview.
- Relaunch race: starting the Hardware Session within seconds of closing
  the app arms and instantly disarms with no hint (the previous WebView2
  teardown still holds its profile; the existing pre-launch process check
  cannot see it because the old app process is already gone). The launcher
  now names that likely cause whenever the app exits within ten seconds of
  starting.

Deliberately deferred: WV-6 (the Mac app's manual-placement CTA on
REFEED_REQUIRED has no Tauri counterpart) is a parity feature through the
motion/binding path, not a defect fix, and stays on the findings ledger.

Test changes: mock_bridge's MOCK_BRIDGE_CRASH_ON gains an optional :N
occurrence suffix, and its WHILE_PREVIEW_PENDING status hang now tracks a
real requested-and-not-established pending flag -- both because the film
gate legitimately issues one pre-preview device.status that the old
first-occurrence triggers would have eaten. Call-log expectations in the
overlap/quarantine/restart tests gained that same leading device.status;
their subjects (zero successor bridge calls, fenced reconnects) are
unchanged and still asserted. New coverage: film-absent e2e refusal
(mutation-proven: disabling the gate fails it with roll.preview reaching
the mock), three rescan unit tests, five bridge-identity probe tests, log
rotation, and two DeviceBar rescan tests.

Suites: engine 25 green suites in each copy (primary and mirror); Tauri
crate 85; frontend 61 files, 440 passed, 6 skipped; vendor-sync gate green
with the engine-pair fingerprint re-pinned for the identical two-sided
edits.
…terlock, sink-before-spawn

Adversarial review of the first commit surfaced one blocker and six
required fixes; all are addressed here:

- The film-presence probe now runs under its own 30-second deadline
  (PREVIEW_FILM_PROBE_DEADLINE, the eject-deadline idiom): the probe's
  status read legitimately waits on the driver's adapter-status settle --
  up to ~10s draining a post-feed medium-change attention -- while the
  generic control-plane timeout is 10s and its expiry restarts the bridge
  and destroys the session. An operator who feeds film and immediately
  asks to preview must never lose the session to the gate that exists to
  help them. fresh_status_for_session gained a with-options variant; the
  zero-argument wrapper keeps the generic bound for every other caller.
- The bridge-identity probe now proves the whole driver, not a sample:
  the deployed interpreter runs the driver's own
  verify_capture_bundle(require_python_sources=True) self-check over the
  copy it actually imports (site-packages, not the staged sources), and
  the imported pin table (bundle.py) must hash byte-identically to the
  installed payload's copy -- pin-table equality plus self-consistency
  binds every pinned component. The deploy path honors XDG_DATA_HOME
  exactly like install-bridge-wsl.sh does, the payload resolves through
  the Tauri resource directory with the executable's directory as
  fallback, and a build without the packaged payload reports an honest
  Unknown instead of a red "reinstall" instruction.
- rescanDevices now runs under connectionChangePending, so the whole
  session store sees a rescan as busy for its full duration (a rescan can
  hold the engine's single dispatch thread across a cold bridge start),
  and the device bar no longer clears an unread connection error when an
  unrelated rescan succeeds.
- The engine log sink exists before the spawn attempt and records a
  sidecar spawn failure -- the most likely "app dies instantly with no
  diagnostics" case the log exists for -- and the runbook now names the
  log file's location. spawn_engine's original doc comment is restored to
  its function (the sink's doc had displaced it).
- The Rescan button carries the shared control styling.

Suites re-run green end to end: engine both copies, Tauri crate 85,
frontend 61 files / 440 passed / 6 skipped, vendor gate with the final
engine-pair fingerprint.
…ic log writes

Second independent adversarial pass; every remaining finding addressed:

- A bridge child that fails its FIRST handshake is now terminated outright
  in spawn_with_env's error path (restart()'s own
  terminate_uninitialized_child policy, which the initial spawn never
  used): such a child owns no device and can have no in-flight USB
  transaction, so Drop's established-session leave-alive courtesy was the
  wrong policy -- and with scanner.rescan making failed startups
  user-repeatable, every impatient click during a slow bridge boot would
  have orphaned another child contending for the same physical scanner.
- scanner.rescan now replaces a real backend whose bridge has died: the
  set-once field previously kept a dead backend listed-but-unconnectable
  forever, silently no-oping the exact button an operator would press to
  fix it. Unhealthy means the child provably exited, so dropping the dead
  client is safe.
- The engine log writes one preformatted buffer per entry with a single
  write_all (writeln!'s per-fragment writes are not atomic under O_APPEND,
  and the launcher's own documented relaunch race makes overlapping app
  instances a real scenario, so mid-line interleaving was reachable), and
  rotation uses the projected size so a single large entry cannot
  overshoot the cap.
- MOCK_BRIDGE_CRASH_ON now fails loudly on a malformed occurrence suffix
  instead of silently reinterpreting it as ":1".
- The runbook's checker pre-flight lead-in says six ids, matching the list
  it introduces.

Suites: engine 25 green suites in each copy, Tauri crate 85, frontend 61
files / 440 passed / 6 skipped, vendor gate re-pinned for the identical
two-sided engine edits.
…ivery GUID

The Windows package job went red mid-day between two runs of the same
tree: Microsoft rotated the fwlink 2124701 delivery GUID (e4dd9b83... ->
eb04ea38...), so Tauri's bundler resolved the new GUID, ignored the pinned
copy staged under the old path, downloaded a fresh installer, and the
pinned-tool verifier failed closed on the unexpected directory -- the
release-toolchain lockdown catching real upstream drift exactly as
designed.

The replacement artifact was re-verified before re-pinning: the official
fwlink redirect resolves to the new GUID, and the downloaded installer
hashes 6ac57a21414742ac1a6a03bf9516a048897317cef04a49967b283093e29c31b7
at 212,668,624 bytes. Both pin sites (the installer script and
build-and-verify.ps1) move together; the installer-suite tests stay green.
@rohanpandula
rohanpandula merged commit 9e59da8 into main Aug 14, 2026
19 checks passed
@rohanpandula
rohanpandula deleted the fix/wv-findings branch August 14, 2026 17:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant