ADR 0108 — Installations opt in to dev builds in Settings
- Status: Accepted
- Date: 2026-10-28
- Amends: ADR 0066 — the dashboard offers dev builds to installations that opt in
- Related: ADR 0023, installation, configuration
Context
Section titled “Context”ADR 0066 publishes dev prereleases again, but only imprint update --dev and the install scripts’ dev flags reach them. The dashboard’s update notice runs imprint update --check --json without a flag and therefore never offers a prerelease. On 2026-10-28 the owner asked for “a channel for updates for dev updates in the update flow that users can opt in to at settings”.
Three facts shape where the choice lives:
- The dashboard’s Settings page is generated from
imprint/config_schema.py: each setting appears under the group named by its key’s prefix, with its choices. Precedence there is environment variable, thenconfig.json, then the default. - The CLI is the single implementation of release resolution (ADR 0023). The dashboard asks it for a report and starts it to update.
- On an installation running a dev build,
imprint updatewithout a flag installs the latest stable release after confirmation, even when it is older (ADR 0066, Consequences).
Decision
Section titled “Decision”The setting. update.channel (IMPRINT_UPDATE_CHANNEL) takes stable, the default, or dev. It appears in Settings → Updates.
The CLI resolves it. Without --version, imprint update takes the channel from --stable or --dev when one is passed, and otherwise from the setting. The setting is read through config_schema.resolve in the installation’s Python, so imprint update sees exactly what imprint config get update.channel shows. A setting that cannot be read, or holds an unknown value, stops the command with a message naming the flags; it never falls back to a channel silently. --check --json reports the channel it used and whether the release is a prerelease.
The dashboard passes no channel. It still runs imprint update --check --json and imprint update -y. Its cached report is valid only for the channel currently set, so changing the setting checks again at once instead of after the six-hour cache. The update dialog marks a prerelease as a dev build.
The channels themselves are unchanged: stable is /releases/latest, dev the highest version among the 30 newest releases.
Rejected alternatives
Section titled “Rejected alternatives”- The dashboard passing
--devfrom its own reading of the setting, with the CLI defaulting to stable. An opted-in installation would then be offered dev builds in the dashboard whileimprint updatein a terminal offered the latest stable release, older than the dev build installed, and installed it after confirmation. The two update paths would disagree about the same installation. - The CLI parsing
config.jsonand the environment variable itself. That is a second implementation of the precedenceconfig_schemaowns, and of its value parsing; the two could drift. - A state file of the CLI’s own, like the install profile in
data/profile.json. The Settings page is generated fromconfig_schema; a file outside it would need its own API and UI. - Clearing the cached report when the configuration endpoint saves this key. It ties the generic configuration endpoint to one setting. Keying the cache by channel needs no event and also covers a change made with
imprint config setor the environment.
Consequences
Section titled “Consequences”- An installation set to dev is offered each dev build in the dashboard as it is published, and stable releases once they are newer.
- Switching back to stable offers nothing until a stable release is newer than the build installed.
imprint update --stablestill installs the latest stable release after confirmation, even when it is older. imprint updatewithout a flag starts the installation’s Python once to read the setting. When that Python cannot run, the command fails and asks for--stableor--dev, which skip the setting.- Installing with
install.sh --dev,install.ps1 -DevorIMPRINT_CHANNEL=devdoes not set the channel: the installation follows stable until the setting is changed. - Installations on a release before this one ignore the setting, because their CLI does not read it. It takes effect after the next update.
Invalidation conditions
Section titled “Invalidation conditions”- If
imprint updatemust work without the installation’s Python and without a flag, for example to repair a broken environment, the channel must move to a store the CLI reads itself, and the Settings page must reach it through the API. - If another channel is published, the setting’s choices and the CLI’s accepted values must change together.
- If the dashboard stops asking the CLI for its update report (ADR 0023), the channel resolution and the cache key move with it.
Validation
Section titled “Validation”- Go:
cmd/update_test.gocovers the flags (none,--dev,--stable,--versionwith--devrefused) and the channel choice: a flag over the setting in both directions, a flag needing no readable setting, an unreadable setting failing with the flags named, and an unknown value refused.go vet ./cmd/andgo build ./...pass. - Live: a CLI built from this change, in an install tree whose Python imports the repository’s
config_schema, reported against the live releases API:channelstable by default, dev fromIMPRINT_UPDATE_CHANNEL=dev, dev fromconfig.json, stable with--stableover a dev setting, and refusednightly. Without a Python it failed naming the flags. The dev channel’s latest was then the stablev0.32.1, as ADR 0066 expects when no prerelease is newer. - Python:
tests/test_updates.pychecks that switching the setting to dev checks again and caches the dev report, and that the dashboard still runsupdate --check --jsonwithout a channel. - Browser:
imprint/ui/tests/update.spec.tschecks that a prerelease is marked as a dev build and a stable release is not, and the existing update and settings specs pass. They ran inmcr.microsoft.com/playwright:v1.64.1-noble: Chromium lacks system libraries in the WSL used. - Not verified: an update from one dev build to the next on a real installation of each type.