← Cycles
Design · c139

Updates

activecreated 2026-11-11· last activity 2026-11-13· mode: assemblage (qupdate's sidecar, c137's delivery modes, c62's partner sources and c131's footer, connected into one page) with archaeology (the notes are drafted from what the cycle records already say).

The user-facing half of updating the native app: Settings → Updates with the current and new version and release notes, a preference that can make updates invisible, the trace a quiet install leaves, and the difference between the build-partner era (one channel, internal notes) and a later structured rollout (channels, staged percentages, public notes, organisation policy). The low-level update (`qupdate`) exists; engineering calls go to Tyler.

New in this cycle: The update's states, preference and trace, and the two eras of rollout

Why

Every build partner installs the native app, and it will change weekly while the program moves. qcontrol already updates itself: qupdate reads a sidecar JSON CI publishes beside each binary, downloads with a checksum and replaces in place. Nothing of that is visible. There are no states a person can read, no preference, no channels, no release notes, no restart, and no word for "someone else manages this". Mark asked for that half: updates launched from Settings, invisible if the person's preference says so, the current and new version with a link to the notes, and an early era for build partners, who get our internal notes, that looks different from the structured rollout a mature product needs.

The brand's "invisible when working, visible when needed" meets its hardest case here. An update is something we do to the person's machine. Done well it costs them nothing and tells them what changed; done badly it is a restart in the middle of a demo.

An update and its statesSketch: An update and its states, drawn 2026-11-11 in the design system; Mark's own drawings may replace it.

Objective

Done means: the prior art read and turned into what we copy and refuse; the model (states, preference, trace, feed, two eras) written and drawn; Settings → Updates mocked in the native skin for every state in both eras, with the tray and the trace; a shot program; the story; the calls for Mark with defaults and Tyler's dependencies listed at a review stop. Later, after the rulings: the states as stories in ../qnative, and the feed contract agreed with Tyler.

Scope

  • Cycle docs: cycles/c139.updates/ (initial-prompt.md, plan.md, prior-art.md, review-1.md)
  • Design site: app/pages/pages/native/settings-updates.vue, app/pages/pages/native/updates-tray.vue, the knob app/data/c139-updates-mock.ts and what each state says app/data/c139-updates-view.ts, the shared knobs app/composables/useUpdatesMock.ts, the native skin (app/components/native/Window.vue: the rail's Settings item and the footer's trace; Icon.vue: nine glyphs; new TrayMenu.vue), the sketch app/pages/cycles/design/sketches/c139-updates.vue, the story app/data/stories/c139.ts, scripts/shot-programs/c139-updates.json and the sketch's entry in c130-sketches-design.json
  • Sister projects: none changed. ../qnative gets the states as stories in Phase 4; ../qcontrol's qupdate is read through c130's research, never changed
  • Out: updating the self-hosted control plane (c134; an operator updating a server); the organisation's update policy page on the plane (later, with c134); first install and the installer (c131); downgrade

Key Changes

  • kick-off (2026-11-11): created from Mark's prompt (initial-prompt.md, verbatim). c138 was the highest cycle in cycles/ and on the remote, so this is c139. plan.md written from c130's platform research §5, c137's plan (D9 delivery modes) and inventory (row 24, app-update dropped), c62's records and the /partner-digest skill: the two binaries, the feed, nine states, the preference, the trace, two eras, seven rules, twelve proposed defaults, three phases after this stop, six dependencies for Tyler.
  • Phase 0, prior art (2026-11-11): prior-art.md, written by a research agent in the same session. It covers seven desktop apps' update settings (Zed, VS Code, Firefox, 1Password, Slack, the Claude desktop app and Raycast) and five ways of giving some people a build first (VS Code Insiders, Chrome's channels, TestFlight, staged percentages, B2B early access), each in the same rows, with sixteen questions and a default for each.
    • The reading backed D1, D2, D5–D8 and D10.
    • It found the model stricter than every precedent on five counts: no restart while the window is open, the sensor's sentence, a visible trace, no skip, and one channel source.
    • It found the model thinner on seven. Four became D13–D16: the idle-relaunch guard, Ask me first's clock, the age line for an install that stopped updating, and "what to try" with a history that shows failures. The rest went into the plan's later era.
    • Linear, Arc and Figma were too thin to table. Some vendor pages were blocked and are cited from search excerpts, marked as such.
  • Phase 1, the model (2026-11-11): plan.md §The shape, drawn as An update and its states with the c130 kit and registered in program-sketches.ts. The sketch shows the plumbing (the feed, the updater, the state machine, the surfaces), the path, the three states that leave it, the preference matrix, the trace and the two eras. It is captured as c139-sketch-updates.png for the Why and the story's hero, and ## The shape sits above.
  • Phase 2, the mocks (2026-11-11): Settings › Updates and the tray and the trace, in the native skin (c132 medium A).
    • Settings › Updates is the app's first Settings page, at the foot of the rail. It has a state card (one sentence, what happens next, the next step) with the versions of the app and qcontrol under it and Copy version info. Below are the preference as three tiles, the channel (Build partners now; Stable or Beta later) and the history with a state. The notes sit in the right column: internal now, drafted from the cycle records with each line's source and "what to try"; public later. The footer carries the trace (0.2.0 ready, updated).
    • The data. Every state in both eras is set by a marked knob (?state= ?pref= ?era= ?sensor=1 ?skip=1), since no world carries update state (c132 D6). qcontrol's version, the harness count and the source line are read from the worlds. One view function (c139-updates-view.ts) gives every surface its words, so the page, the footer and the tray cannot disagree.
    • Walkable. The buttons step through the states, each followed by a toast as c137 D12 rules.
    • The tray page shows the menu on a desktop, the window's footer in the same state, and every state side by side.
    • Registered and captured. Both pages are in page-registry.ts (phase native, collapse c139-updates). scripts/shot-programs/c139-updates.json (scale: 2, clip: ".native-window") ran here: sixteen captures plus the sketch, filed in public/cycles/design/.
    • The layer. Untouched. A dense UxToggleCard is flagged for c135.
  • Phase 3, the story (2026-11-11): app/data/stories/c139.ts, wired in cycle-stories-mock.ts. It records Mark's four asks as his decisions and has five outcomes, with the sketch as the hero and seventeen captures.
  • Review stop 1 (2026-11-11): review-1.md holds eleven calls for Mark, each with a recommended default and the capture that shows it: the preference's default, what invisible means, inline or linked internal notes, skip, who owns the notes, one update or two, when an automatic install may restart, the version string, where Settings lives, the clock and the age line, and the era as data. Tyler's six dependencies (T1–T6) are listed separately, along with what is out of scope (updating the self-hosted plane, c134) and what was and wasn't verified.
    • Environment. The layer package returned 401 from GitHub Packages in this cloud session, so the site ran against a read-only clone of q-nuxt-layer 0.9.37, with package.json and the lockfile restored. Nothing went into ../qnative; that is Phase 4, after the rulings.
  • review stop 1 walked (2026-11-13): Mark ruled the eleven calls (review-1.md §Answered). Nine as their defaults (Automatically; a quiet trace; notes inline; no skip; one page, two rows; the guarded idle restart; tag and short SHA; Ask me first's clock and the 60-day line; the era from the feed). Two changed: the release notes are drafted automatically from the commit messages, with room for manual additions (engineering and design now, product later); App Settings is a rail item with a submenu grouping General · Updates · Notifications · Data · Developer (read with design c147: Safety & Security keeps its own Settings, App Settings › Notifications points to it; to confirm). Phase 4 (the native build) and the lab's update to calls 5 and 9 go to cloud sessions; the app couldn't start them from the walking conversation, so their briefs wait in cloud-native-prompt.md (qpoint-io/qnative) and cloud-lab-prompt.md (qpoint-io/design), to start under New session → Cloud.

The shape

Documents: the plan · Mark's prompt · prior art · review 1

Drawn as An update and its states on 2026-11-11; the record behind it is plan.md.

The problem. The app will update often, on machines whose owners are watching what it costs them, and the updater we have has no face. Built late, an update becomes a dialog, a restart at the wrong moment or a silent change nobody can explain. And what a build partner should see when the app changes (our internal notes, the cycle trail, the sharp edges fixed) is not what a customer should see once the product rolls out in stages.

The core idea. One page, one state machine, three preferences, two eras. The state machine is the protocol: every state says what is true in one sentence and what happens next. Silent means nothing interrupts, not that nothing is said: a quiet install leaves a trace where the person already looks. The era is data from the feed (the channel, the notes' audience), not a flag in the app, so the structured rollout is the same page reading more fields.

The pieces.

  • Nine states: up to date · checking · available · downloading (download, verify, stage) · ready to restart · installed, then what's new · failed · offline · managed elsewhere (a package manager now; the organisation's policy later). One machine per binary: the app and qcontrol, on one page with one Update.
  • The preference: Automatically (the default, installed at quit, at restart, or when nobody is looking, under a guard that waits out tours, streams and sessions) · Ask me first (it says how long the update has waited, never prompts) · Manually. Checks always run.
  • The trace: the footer's v0.2.0 · updated for seven days, the Updates page leading with what's new, the history, one tray line while an update is ready. No inbox message (c137 row 24 stands), no OS notification, no toast.
  • The feed: qupdate's sidecar plus channel, notes and size now; rollout, min_version and pulled later.
  • Two eras: now, one channel with internal notes inline and the trail a link away; later, Stable and Beta, staged percentages, public notes and the plane's policy.
  • The mocks: Settings → Updates and the tray and the trace in the native skin, rows from the worlds, the update state a marked knob.

The pattern we follow. Modularity is purpose plus protocol: the update's purpose is a current, verified app; its protocol is the nine states; what the notes say and which channels exist are slots the feed fills. Assemblage: the pieces exist (qupdate's sidecar and checksum, c137's quiet mode and its decision to keep updates out of the inbox, the footer that names version and source, the partner digest's sources), and this cycle connects them. Replicate first: the partner era is qupdate's one latest with a face; the later era is drawn but not built.

What stays open. The calls in review-1.md: the preference's default, what silent means, inline or linked internal notes, skip, who owns the notes, one update or two, when an automatic install may restart, the version string, Settings' seat. Tyler's dependencies: signing and notarisation, qupdate or the app's own updater, the feed's new fields, the sensor's update and its gap, knowing a package manager owns the install, restart mechanics. Out of scope: updating the self-hosted control plane (c134), the organisation's policy page.

Visual record

18 captures — heroes, page slices, and full-page renders. Click to view.

Phase 2 · Settings › Updates and the tray in the native skin, every state and both eras

2026-11-11· 16 captureslatest
Up to date: 0.1.0 is the newest on the build-partner channel, checked five minutes ago; Check now. The notes panel points at the cycle records, since 0.1.0 has none of its own.
Up to date: 0.1.0 is the newest on the build-partner channel, checked five minutes ago; Check now. The notes panel points at the cycle records, since 0.1.0 has none of its own. open page →
Checking: asking downloads.qpoint.io for the newest version on the build-partner channel.
Checking: asking downloads.qpoint.io for the newest version on the build-partner channel. open page →
Available, Manually: you have 0.1.0 · 71dd21a, 0.2.0 was published Nov 10 (8.6 MB); the release carries qcontrol 0.9.5, which needs an administrator; Update · Not now. Internal notes inline, each line with its source.
Available, Manually: you have 0.1.0 · 71dd21a, 0.2.0 was published Nov 10 (8.6 MB); the release carries qcontrol 0.9.5, which needs an administrator; Update · Not now. Internal notes inline, each line with its source. open page →
The same state with a Skip this version link, for review-1's call on skip (the plan's default is no skip).
The same state with a Skip this version link, for review-1's call on skip (the plan's default is no skip). open page →
Downloading in the background: 5.5 of 8.6 MB, then verify (the checksum) and stage beside the running app; Cancel until staged.
Downloading in the background: 5.5 of 8.6 MB, then verify (the checksum) and stage beside the running app; Cancel until staged. open page →
Ready to restart, Ask me first: qcontrol keeps watching while the app restarts; Restart now · When I quit. The footer reads v0.1.0 · 0.2.0 ready.
Ready to restart, Ask me first: qcontrol keeps watching while the app restarts; Restart now · When I quit. The footer reads v0.1.0 · 0.2.0 ready. open page →
Installed quietly: updated to 0.2.0 yesterday at 18:02, while the window was closed; what's new leads the page; the footer reads v0.2.0 · updated. qcontrol 0.9.5 waits: a quiet install never asks for a password.
Installed quietly: updated to 0.2.0 yesterday at 18:02, while the window was closed; what's new leads the page; the footer reads v0.2.0 · updated. qcontrol 0.9.5 waits: a quiet install never asks for a password. open page →
Failed: the download didn't match the published checksum, so nothing changed; you're still on 0.1.0; Try again · Copy details.
Failed: the download didn't match the published checksum, so nothing changed; you're still on 0.1.0; Try again · Copy details. open page →
Offline: downloads.qpoint.io isn't reachable; last checked two days ago; tries again every hour, and nothing on this machine depends on it.
Offline: downloads.qpoint.io isn't reachable; last checked two days ago; tries again every hour, and nothing on this machine depends on it. open page →
Managed by Homebrew: Qpoint doesn't replace itself; the command to run, and the newest from Qpoint; the preference shown, locked, with the reason.
Managed by Homebrew: Qpoint doesn't replace itself; the command to run, and the newest from Qpoint; the preference shown, locked, with the reason. open page →
Later, a structured rollout: the same page with public notes and a link to the changelog, the version without its SHA, and the channel as Stable or Beta.
Later, a structured rollout: the same page with public notes and a link to the changelog, the version without its SHA, and the channel as Stable or Beta. open page →
Later: HQ manages updates on this machine and keeps Qpoint at 0.1.0 until it approves 0.2.0; the preference and the channel locked; Contact IT.
Later: HQ manages updates on this machine and keeps Qpoint at 0.1.0 until it approves 0.2.0; the preference and the channel locked; Contact IT. open page →
The tray, Ask me first: a dot on the icon and Restart to update to 0.2.0; the window's footer reads 0.2.0 ready.
The tray, Ask me first: a dot on the icon and Restart to update to 0.2.0; the window's footer reads 0.2.0 ready. open page →
The tray, Automatically: Restart to update is there for whoever opens the menu, with no dot; it installs when you quit.
The tray, Automatically: Restart to update is there for whoever opens the menu, with no dot; it installs when you quit. open page →
After a quiet install: no update line; the menu's version line and the window's footer say updated.
After a quiet install: no update line; the menu's version line and the window's footer say updated. open page →
Three failed tries: Updates aren't installing, with an amber dot on the icon (R3's one exception).
Three failed tries: Updates aren't installing, with an amber dot on the icon (R3's one exception). open page →

Sketches — the structures, drawn in the design system

2026-11-10· 2 captures
Nine states from up to date to managed elsewhere, three preferences, one trace, and the same page in two eras: build partners now, a structured rollout later.
Nine states from up to date to managed elsewhere, three preferences, one trace, and the same page in two eras: build partners now, a structured rollout later. open page →
c139 full
open page →

Artifacts

Qpoint Brand Style Guide