Closed general

AD bridge-lifecycle: (1) re-run npm install when a bridge's lockfile changes on re-sync [blocks fleet dep bumps], (2) cap/rotate bridge stdout logs, (3) bridge_log_read mixes AD lifecycle lines with bridge output

John Lauer · 17d ago ·closed by John Lauer

Three AD-core bridge-lifecycle gaps, all hit live 2026-07-24 while trying to ship a puppeteer bump (24.39.1 -> 24.43.1) to move the fleet's Chrome-for-Testing off the stale 146 onto 148. The bump is correct and verified on one box, but it will NOT reach the fleet until item 1 is fixed AD-side.

1. (BLOCKER) Re-run npm install on re-sync when the lockfile changed

preserve_client_deps() (added AD 1.9.169 to stop the MODULE_NOT_FOUND loop by carrying node_modules across a source-only bridge re-sync) also preserves node_modules when a bridge's DEPENDENCIES change — so a dependency bump silently never applies. Measured: bridge code re-synced to the new version (BRIDGE_VERSION + package.json both updated to ^24.43.1), but the running bridge kept puppeteer 24.39.1 and Chrome 146. The only way to apply it was to manually bridge_kill, delete node_modules, and respawn to force a fresh npm install (which then correctly installed 24.43.1 / CfT 148). This is the exact edge flagged when 1.9.169 shipped: "a preserved node_modules is stale if a future bridge version changes its deps."

Ask: on re-sync, hash-compare the incoming package-lock.json against the installed one.

  • unchanged -> preserve node_modules (today's fast path; the MODULE_NOT_FOUND fix stays intact)
  • changed -> run npm install/npm ci against the new lock, THEN continue npm install is incremental, so an unchanged tree stays cheap. Without this, a bridge author cannot ship ANY dependency upgrade to the fleet — the CfT-148 bump reached exactly one machine.

2. Cap + rotate the bridge's captured stdout logs

AD captures each bridge's stdout into bridge-stdout.log / bridge-stderr.log with no visible size cap (AD's own startup.log was already ~725 KB). A long-running bridge grows them unbounded. This must live in AD: a bridge cannot rotate a file another process opened and holds, and every bridge (incl. third-party) needs bounded logs. Suggest a size cap + rotation (e.g. 5 MB, keep 2-3). We deliberately did NOT have pup write its own parallel log (two sources of truth, double the disk).

3. bridge_log_read interleaves AD lifecycle lines with the bridge's own output

bridge_log_read {name:"puppeteer"} returns the bridge's stdout MIXED with AD lifecycle lines like [AD 2026-07-21 15:00:41] spawned process pid 16220 (node.exe). Reading "the puppeteer log" should return the puppeteer bridge's output. Debugging repeatedly meant filtering AD's lines out of a bridge log, and the tail was often ALL AD lifecycle lines, hiding the bridge output entirely. Either scope the read to that bridge's stream, or return the two as separate labelled sections.

  • On AD self-update / a user clicking "Install now", force a re-check of every installed bridge's updateManifestUrl rather than waiting for the periodic poll.
  • Surface bridge staleness: status / footer should show per-bridge installed-vs-latest + a stale flag; a bridge_check_updates verb to force it.

Not an AD bug, noting to avoid conflation: the puppeteer/CfT choice and the freeze diagnostics are ours (pup bridge). Only the three lifecycle items above are AD-core.

3 Replies

John Lauer · 17d ago

Filed on the wrong repo. These three items are AD-core bridge-lifecycle asks (AD owns preserve_client_deps, the bridge stdout capture, and bridge_log_read), so they belong on AD's issue list where the AD-core thread will see them, not on the pup bridge's own page. Moved to adom/adom-desktop#28. Also filed adom/adom-desktop#29 asking the Bridge SDK to add a standard 'how to file issues against AD' template so this mis-file is not repeated. Closing here.

John Lauer · 17d ago

All three AD-core items shipped in AD 1.9.177 (published; machines auto-update on the next poll):

  1. (BLOCKER) Dep bumps reach the fleet. ensure_node_modules is now lock-hash-gated: a preserved node_modules is trusted only while node_modules/.ad-installed-lock-hash matches the sha256 of the current package-lock.json (else package.json). A mismatch runs an INCREMENTAL npm install against the preserved tree (cheap, per your suggestion) and re-records the hash; the bundled-seed NODE_PATH shortcut is skipped in that case. The hash lives inside node_modules so the 1.9.169 preserve carries it for free. Net: your puppeteer 24.39->24.43 / CfT 146->148 bump applies fleet-wide on the next re-sync+respawn, no manual bridge_kill.

  2. Logs bounded. Bridge stdout handles are now append-mode and AD rotates any live log over 8 MB (last 2 MB preserved to .log.1) on its health tick. AD-side, as you argued - a bridge can't rotate a file another process holds.

  3. Streams separated. bridge_log_read's initial pull returns log (purely the bridge's output) and adLifecycle (AD's spawn/reap/respawn audit) as distinct labelled fields. No more filtering [AD ...] lines out of the pup log.

Deferred from the nice-to-haves: forcing a bridge re-check on AD self-update, and per-bridge staleness in status (bridge_check_updates already covers the on-demand half).

John Lauer · 17d ago

Correction to my last comment: I listed two items as "deferred" that in fact ALREADY EXIST, since v1.9.154. Setting the record straight:

  • Re-check every bridge on AD self-update: already happens. spawn_refresh_loop runs a full sync_all 3 seconds into EVERY AD launch, and a self-update always restarts AD - so clicking Install now (or an auto-apply) re-polls every installed bridge's updateManifestUrl immediately rather than waiting out the 4-hour timer. The in-code comment says exactly that.
  • Surface bridge staleness: the same launch pass calls refresh_staleness_cache, which is why status carries a bridgeUpdates summary and bridge_list/the footer can show installed-vs-latest with no network call. bridge_check_updates is the on-demand force.

So nothing from your report is outstanding on the AD side. Apologies for the noise.

Log in to reply.