Skip to content

feat(preview): check and install newer preview builds at startup - #374

Open
jonybur wants to merge 3 commits into
mainfrom
feat/preview-auto-update
Open

feat(preview): check and install newer preview builds at startup#374
jonybur wants to merge 3 commits into
mainfrom
feat/preview-auto-update

Conversation

@jonybur

@jonybur jonybur commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

Preview installs update via the self-hosted update_url feeds, but peerd's offscreen keepalive holds the MV3 SW alive - exactly the state where Chrome parks a downloaded extension update forever waiting for an idle that never comes, so preview testers quietly fall behind.

What changed

  • New background/update-check.js: on Chrome, force the update_url poll at boot / panel-open (coalesced + throttled; only a completed check burns the window) and runtime.reload() when the downloaded update can apply with nothing live (no turn or goal run, no UI port, no engine tab, no other extension page), re-attempting when a surface closes. On Firefox (no requestUpdateCheck API), read the gecko feed and offer the XPI via a notice, persisted in storage.session so it survives event-page respawns.
  • The onUpdateAvailable listener registers ONLY on self-hosted manifests: on Firefox a listener's mere presence defers every add-on update until reload/browser restart, so a store-package listener would break AMO auto-updates; a disabled toggle restores the no-listener default there.
  • Feed update_link hosts pinned to github.com / peerd.ai; version strings shape-checked.
  • Setting autoUpdateEnabled: preview-only channel key (absent from store CHANNEL_DEFAULTS, patch-gated on key presence), default ON, toggle in Settings -> Behavior. Dev (load-unpacked) has no update_url, so every path is a structural no-op there.
  • NoticeBar gains a generic https-only open-url action.

How verified
56 new bun tests (feed parsing, version compare, throttle/coalesce races, listener gating, Firefox disabled-default, notice persistence across respawn) + the settings-patch gate tests; full local gate set on the branch: typecheck, lint, boundary, imports matrix, copy/hygiene/invariants, tscheck floor (698 -> 699), gen drift, 5712 bun tests, 865 in-browser, packaged page boot both channels, pinned-Firefox suite (858 Gecko + store smoke), live e2e 318/318 across 66 states. Live feeds confirmed reachable with open CORS.

Preview installs are self-hosted (update_url feeds -> GitHub release
artifacts), but peerd's offscreen keepalive holds the MV3 SW alive, which
is exactly the state where Chrome parks a downloaded extension update
forever. background/update-check.js closes that gap: Chrome forces the
update_url poll at boot and reloads when a downloaded update can apply
with nothing live (no turn or goal run, no UI port, no engine tab, no
other extension page), re-attempting when a surface closes; Firefox (no
requestUpdateCheck API) reads the gecko feed and offers the XPI in a
notice, persisted in storage.session so it survives event-page respawns.

The onUpdateAvailable listener registers ONLY on self-hosted manifests:
on Firefox a listener's mere presence defers every add-on update until
reload()/browser restart, so a listener on the store package would break
AMO's automatic updates; a disabled toggle there restores the
no-listener default (apply immediately). Feed update_links are pinned to
github.com/peerd.ai and version strings shape-checked before they reach
the notice.

Setting: autoUpdateEnabled, a preview-only channel key (absent from
store CHANNEL_DEFAULTS, patch-gated on key presence), default ON, with
an Auto-update toggle in Settings -> Behavior. Dev (load-unpacked) has
no update_url so every path is a structural no-op there. The side
panel's NoticeBar gains a generic https-only open-url action.

Signed-off-by: Jonathan Bursztyn <jobur93@gmail.com>
@jonybur
jonybur requested a review from NotASithLord as a code owner August 9, 2026 16:59
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

The UI renders differently than the committed baselines — 2 of 54 screens changed (before ⟶ after below).

options-behavioroptions-behavior · up to 0.33% changed

dark — 0.33% of pixels (before ⟶ after)

options-behavior dark before/after

light — 0.32% of pixels (before ⟶ after)

options-behavior light before/after

Full-res before/after/diff PNGs: download the visual-diff-… artifact.

Intended? Re-run this workflow on the branch with update_visual_baselines checked, then commit the fresh baselines/linux-x64/ and regenerate GALLERY.md with bun run gallery.

github-actions Bot added a commit that referenced this pull request Aug 9, 2026
The options-behavior captures moved 0.32% - the new Auto-update row in
the Behavior band. Reseeded on the CI authority via the
update_visual_baselines dispatch and eyeballed per PNG; goal-running
(0.01%, a tool-card ms flap) and multi-turn-transcript.dark (0.0000%
within tolerance) rode along from the fresh capture.

Signed-off-by: Jonathan Bursztyn <jobur93@gmail.com>
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

Visual regression

No visual drift. Every state renders identically to the committed baselines.

📸 Browse the visual gallery — 58 baseline screens (light + dark) as of this commit.

Composer: the input textarea never grew with its draft, and above the
370px wrap threshold the mode-row pills squeezed until their labels
broke onto two lines. The textarea now autosizes (bounded by the
existing min/max heights, re-run on panel resize) and the mode row
wraps at every width with nowrap pills. The narrow-sidebar e2e check
now asserts wrap-plus-unsqueezed across the width matrix instead of
the old nowrap-above-370 rule.

Redesign turns 1-3 remainder (a11y): nav rail aria-current, wired
aria-controls on the "Why this matters" disclosures and denylist
groups (including the expanded-but-empty body), a permanently mounted
role=status outcome banner, and armed-confirm focus management - the
destructive verb takes focus on the arm gesture only, Escape/Cancel
return focus to the arm control, and a completed action lands on
search.

Design turn 4:
- Stop card (4c): an origin-lock stop renders in the transcript as a
  slotted card (STOPPED + group chip, origin-only headline, the
  landing rule's verbatim reason, the what-peerd-doesn't-know box)
  instead of prose paragraphs. The card model is pure in
  origin-lock-report.js and rides the actor-reply envelope; the
  orchestrator's prose report is byte-identical to before. Only the
  handoff card carries an action - prefill the composer with the
  sessionless-read message; it never sends and grants nothing. No
  generic stop offers an action: the landing is the one address a
  hostile page controls, and a button would turn a page-chosen
  destination into a one-click trusted instruction.
- Confirm modal (4d): the session button states what it actually
  grants ("Allow all writes" plus "this chat, this site/any site",
  derived from the same rule as the grant key), a helper-raised
  prompt explains why the session grant is absent instead of hiding
  it silently, and a quiet "No answer counts as Reject." line appears
  at ninety seconds - timed from the prompt's raise, re-armed per
  prompt id.
- Settle outcomes (4e): the confirm coordinator now reports how each
  prompt settled (answer/timeout/abort/stop, plus which surface
  answered); the SW records settles no surface saw - including
  fail-closed denials while peerd wasn't open - and replays them via
  the snapshot; the transcript renders one quiet line per settle,
  suppressed on the surface that answered. Outcomes for actor-raised
  confirms map to the root chat so helper prompts are covered too.

Verified: eslint, strict tsc (coverage floor 699 -> 705), copy
hygiene, boundary/imports/pages checks, 5722 bun tests, 871
in-browser tests (new reducer-fold suite), e2e 68 states / 322
checks including two new visual states (sidepanel-confirm,
sidepanel-stop-card). The new states need the update_visual_baselines
dispatch after merge to gain committed Linux baselines.

Signed-off-by: Jonathan Bursztyn <jobur93@gmail.com>
@NotASithLord

Copy link
Copy Markdown
Owner

The preview update work is worth landing, but this branch now conflicts with main and the third commit adds a separate UI, confirmation, and origin-lock redesign. That makes the current diff too broad to review or merge safely.

I am extracting the first two commits onto current main for focused adversarial review. The UI redesign should remain separate so it can receive its own security, user UX, model UX, and visual review.

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.

2 participants