Conversation
Coordinate common's downstream integration to the rebranded ChairLift (projectbluefin/chairlift, io.projectbluefin.chairlift): - chairlift.Brewfile: tap ublue-os/homebrew-tap and cask ublue-os/homebrew-tap/chairlift, which pins the projectbluefin/chairlift release (v0.12.2); the old frostyard/tap cask is frozen at the pre-rebrand v0.10.1. - brew-preinstall: protect the new ublue-os/homebrew-tap/chairlift cask name in the --external-chairlift OS-diet handoff, alongside the historical unqualified, frostyard and ublue-os/tap spellings. - Rename the system-wide desktop entry, icons and bootc polkit policy from org.frostyard.ChairLift.* to io.projectbluefin.chairlift.*; the policy and desktop entry are re-vendored from upstream v0.12.2 (Exec= keeps the absolute wrapper-path edit), icons are unchanged. - check-chairlift-config: CHAIRLIFT_SCHEMA_REF v0.10.1 -> v0.12.2 and UPSTREAM_RAW -> projectbluefin/chairlift, bumped in the same change as the cask per the gate's own invariant. - test_chairlift_config.py: new IDs, new Brewfile expectations, v0.12.2 schema pin, and the v0.12.2 schema surface (8 new groups, ai_images / ai_model fields). - test_brew_preinstall.bats: handoff state test covers the new cask name. - pre-commit excludes, drift workflow and skill docs follow the rebrand. Refs: projectbluefin/chairlift#18, projectbluefin#1115 Signed-off-by: eltorrero <eltorrero@users.noreply.github.com>
There was a problem hiding this comment.
Correctness review — read the diff at 9823518.
Two hypotheses I chased and cleared, so they don't get re-raised: the vendored polkit file is byte-identical to upstream v0.12.2 data/io.projectbluefin.chairlift.bootc.policy, and the action-ID rename is safe — v0.12.2 invokes pkexec /usr/libexec/bootc-update-stage by path (internal/bootc/stage.go:44), and the exec.path annotation is unchanged (io.projectbluefin.chairlift.bootc.policy:19). Also tap "ublue-os/homebrew-tap" does resolve: Tap.fetch strips the homebrew- prefix (Homebrew Library/Homebrew/tap.rb:72).
1. The cask swap is a silent no-op on every already-provisioned machine (high)
chairlift.Brewfile:1-2 moves the cask to ublue-os/homebrew-tap/chairlift, but nothing in the diff retires the chairlift token already installed from frostyard/tap. Homebrew Caskroom is keyed by bare token, and brew bundle strips the tap before checking: cask_in_array? compares Utils.name_from_full_name(cask) (Homebrew Library/Homebrew/bundle/cask.rb:127-130), so cask_installed?("ublue-os/homebrew-tap/chairlift") sees the installed chairlift and preinstall! returns early with "already installed" (cask.rb:51-53). The upgrade branch doesn't fire either — cask_upgradable? consults brew outdated --cask, and frostyard/homebrew-tap/Casks/chairlift.rb is still version "0.10.1" with no old_token, no deprecate!, and the tap has no tap_migrations.json.
The OS-diet can't clean it up either: managed_name_present compares only the basename after the last / (system_files/shared/usr/libexec/brew-preinstall:163-174, applied at :199), so previous-state frostyard/tap/chairlift basename-matches the new ublue-os/homebrew-tap/chairlift and is skipped. Net effect: fresh installs get v0.12.2; existing users keep the frostyard v0.10.1 binary indefinitely, with no error — brew bundle's skip message is "Skipping install of ... cask", which does not match the ^Skipping cask guard at brew-preinstall:117, and it's only emitted under verbose anyway.
This needs an explicit one-time migration (uninstall the chairlift cask when its installed tap isn't ublue-os/tap, before bundling), or a tap-aware exception in managed_name_present.
2. The schema gate now inverts its own stated invariant (high, consequence of 1)
tests/check-chairlift-config:21-23 says it validates against "whichever release ublue-os/homebrew-tap's chairlift cask pins, so that binary's loader is the only one whose opinion counts", and :50 bumps CHAIRLIFT_SCHEMA_REF to v0.12.2. Given #1, the binary actually running on upgraded machines is v0.10.1. A future config.yml addition using a v0.12.2-only key (e.g. the new ai_images/ai_model fields whitelisted at tests/test_chairlift_config.py:130-131) would pass this gate and be rejected wholesale by the v0.10.1 loader — the disabledConfig() false-green the script exists to prevent.
3. No test covers the migration path (medium)
tests/test_brew_preinstall.bats:155 only extends the --external-chairlift state list. Every ChairLift bats case still writes the bare token cask "chairlift" into the Brewfile (:142, :152, :196, :431), so none exercises the shipped shape — old state containing frostyard/tap/chairlift plus a new Brewfile declaring ublue-os/homebrew-tap/chairlift, in the default non-external path. That is exactly the case #1 breaks.
Limits of this review: I could not run Homebrew against a real Bluefin image. Finding 1 is derived from reading Homebrew bundle/cask.rb and tap.rb at current main plus the two tap repos, not from a live upgrade. If Bluefin's Homebrew is pinned to a version whose bundle cask check is tap-aware, finding 1 collapses — worth confirming with one brew bundle run on a machine that already has the frostyard cask installed.
— hive: agent=reviewer backend=copilot model=claude-fable-5
…7643) The review pill never rendered. AttachReviewLinks looked up each snapshot PR with ReviewLinkKey(fp.Repo, fp.Number), but a snapshot PR's Repo is the bare repository name — the owner lives on the repo card, in FrontendRepo.Full — while the ledger is keyed by the full owner/repo the review relay recorded when it submitted. So the lookup asked for "common#1121" against a ledger holding "projectbluefin/common#1121" and missed every time. Observed on a live hive: 194 open PRs in the status payload, a ledger holding eight entries written minutes earlier, and zero PRs carrying review_url. The feature's whole purpose is answering "has the hive looked at this one?" on a queue of hundreds, and it answered "no" for every PR including the ones reviewed that hour. The existing tests did not catch it because they built the payload with full names on the PRs, a shape production never produces. The new test uses the production shape: repo card full name, bare PR repo name, ledger keyed by the full name. Lookup now tries the full name first, then the bare name. Full first because it is what the relay records and because it stays unambiguous when two configured repos share a bare name across owners. Signed-off-by: Andrew Anderson <andy@clubanderson.com>
There was a problem hiding this comment.
HUMAN DECISION NEEDED — @eltorrero merge sequencing vs dakota's fail-closed guard, and whether existing user installs must migrate off the frozen frostyard cask.
Reviewed head 1942da2 (correctness perspective).
1. Merging this breaks dakota image builds until its follow-up lands (medium/high, sequencing). dakota:files/chairlift/install.sh hard-fails unless the Brewfile is exactly tap "frostyard/tap", trusted: true + the old cask spellings ("ChairLift preinstall changed in common; reconcile the Dakota migration.", install.sh:19-25). This PR changes the Brewfile to the new shape (system_files/shared/usr/share/ublue-os/homebrew/preinstall.d/chairlift.Brewfile:1-2), so dakota's common.bst build exits 1 on the next common pin. The PR body discloses this as a follow-up, but the merge order (dakota guard widened first vs. accepting red dakota builds) is a maintainer call.
2. Existing installs likely never reach the rebranded release (medium). On machines that already have the frostyard cask installed (token chairlift, tap frozen at v0.10.1): the new state diff won't uninstall it — managed_name_present compares basenames, so frostyard/tap/chairlift (previous) matches ublue-os/homebrew-tap/chairlift (current) and removal is skipped (system_files/shared/usr/libexec/brew-preinstall:163-174,194-200) — and brew bundle resolves casks by token, so cask "ublue-os/homebrew-tap/chairlift" is satisfied by the already-installed chairlift and is not re-installed. Since frostyard/tap is frozen pre-rebrand, those users stay on v0.10.1 indefinitely despite the PR's intent to "track rebranded release". Dakota handles migration explicitly (dakota-brew-managed); plain common consumers have no equivalent path in this diff, and no test covers the already-installed-old-cask case (tests/test_brew_preinstall.bats:152-158 only covers --external-chairlift state filtering). If chairlift has shipped to real users on non-dakota images, a migration step (or acceptance of the freeze) needs an explicit decision.
Verified clean: icons are byte-identical between v0.10.1 and v0.12.2 upstream, so the pure renames are correct; the vendored polkit policy is byte-identical to upstream v0.12.2 data/io.projectbluefin.chairlift.bootc.policy; the desktop entry matches upstream v0.12.2 except the documented Exec= edit (io.projectbluefin.chairlift.desktop:14); the ublue-os/homebrew-tap cask pins v0.12.2; pkexec resolves the action via the unchanged exec.path annotation, so the action-ID rename does not strand an old installed binary.
— hive: agent=reviewer backend=copilot model=claude-fable-5 copilot=1.0.78
Danathar
left a comment
There was a problem hiding this comment.
Verified the packaging side and it's clean: the ublue-os/homebrew-tap cask pins projectbluefin/chairlift v0.12.2 with the release URL; the vendored polkit policy is byte-identical to upstream data/io.projectbluefin.chairlift.bootc.policy at v0.12.2 (action id and exec.path match); the desktop entry differs only by the header comment and the absolute Exec=; both scalable icons have the same blob SHA as upstream. Ran tests/check-chairlift-config live (✓ against v0.12.2), pytest tests/test_chairlift_config.py (29 passed) and bats tests/test_brew_preinstall.bats (48 passed) at the PR head. Note no CI ran on this PR (empty checks rollup), so please push a fresh SHA to get a real run.
Blocking: existing installs never migrate. Bluefin doesn't pass --external-chairlift, so migration is whatever brew-preinstall + brew bundle do on the next boot, and for a machine that already has frostyard/tap/chairlift v0.10.1 installed that is:
brew bundleseescask "ublue-os/homebrew-tap/chairlift"and askscask_installed?. That check is by token —cask_in_array?falls back toUtils.name_from_full_name(cask), i.e.chairlift— andchairliftis installed. It then askscask_upgradable?, which compares the installed cask against its own tap's definition;frostyard/tapis frozen at 0.10.1, so it isn't outdated. Result: "Skipping install of ublue-os/homebrew-tap/chairlift cask. It is already installed."- The removal pass then sees
frostyard/tap/chairliftdropped from the managed set, butmanaged_name_presentalso compares by token (${managed##*/}), matches it against the new cask, and skips the uninstall. - State gets stamped with the new hash, and every later boot early-exits.
So existing users keep the v0.10.1 binary indefinitely, while the image has removed org.frostyard.ChairLift.bootc.policy — the action that binary still requests. (pkexec falls back to the generic admin-auth action, so staging degrades to a password prompt rather than breaking outright, but the user-visible upgrade never happens.) Only fresh installs get v0.12.2.
Fix belongs in brew-preinstall, before bundling, something like: if brew list --cask chairlift reports the installed cask's tap as frostyard/tap (e.g. via brew info --cask --json=v2 chairlift | jq -r '.casks[0].tap'), brew uninstall --cask frostyard/tap/chairlift first so the bundle actually installs the new one — plus a bats case that stubs an installed frostyard cask and asserts the swap. dakota's scripts/test_chairlift_migration.sh is prior art for the shape.
Nit, not blocking: Homebrew's canonical tap name is ublue-os/tap (brew tap-info ublue-os/homebrew-tap normalizes to it), and that spelling was already in the handoff list. Using it in the Brewfile avoids a third spelling of the same cask in state files.
There was a problem hiding this comment.
intent-alignment
- Merge-ordering dependency on Dakota is real and will fail closed (medium). The PR body's coordination note is accurate:
projectbluefin/dakotafiles/chairlift/install.sh:20-24hard-checks the old Brewfile shape (tap "frostyard/tap", trusted: true) andexit 1s on anything else, so the first Dakota common-pin bump after this merges will break its image build until the Dakota guard follow-up lands. The failure is loud and by design ("Stop rather than silently overriding"), but whoever merges should sequence the Dakota change.
Verified against head 1942da2: ublue-os/homebrew-tap/Casks/chairlift.rb pins projectbluefin/chairlift v0.12.2; the three renamed icons are byte-identical to upstream v0.12.2; the re-vendored desktop entry differs from upstream only in comments and the absolute Exec= path; the renamed polkit policy keeps auth_admin defaults and the pinned exec.path annotation (system_files/shared/usr/share/polkit-1/actions/io.projectbluefin.chairlift.bootc.policy:15-19).
No findings from: security, style, docs-currency.
— hive: agent=reviewer backend=copilot model=claude-fable-5 copilot=1.0.78
There was a problem hiding this comment.
correctness
- Medium — legacy-cask migration check doesn't verify the cask is installed (
system_files/shared/usr/libexec/brew-preinstall:104-110).brew info --cask --json=v2 chairlift | jq '.casks[0].tap'returns the source tap for a cask that is merely resolvable, not necessarily installed. Nothing in this PR untapsfrostyard/tap(it stops being re-trusted once out of the Brewfile, but stays tapped), so on a host where chairlift is not installed and bare-name resolution hits the frozen frostyard cask, the script runsbrew uninstall --cask frostyard/tap/chairliftagainst a not-installed cask, fails, setsbundle_failed=1, and exits 1 with state unstamped (brew-preinstall:107-110, 137-140). It self-heals only if the same-boot bundle successfully installs the new cask; paired with any chairlift bundle failure it retries a spurious error every boot. Gate on installation, e.g.jq '.casks[0] | select(.installed != null) | .tap'orbrew list --cask chairliftfirst. Consider also untappingfrostyard/tapafter a successful migration so the frozen v0.10.1 cask can't shadow bare-name resolution.
intent-alignment
- Info — PR body omits the migration/uninstall behavior. The body's "Changes" section never mentions that
brew-preinstallnow auto-uninstalls an installedfrostyard/tap/chairliftbefore bundling (brew-preinstall:100-112) — the single most behavior-significant change on user machines. The tests cover it (tests/test_brew_preinstall.bats:797-891); the description should too.
style
- Low — two spellings of the same tap. Homebrew strips the
homebrew-repo prefix, sotap "ublue-os/homebrew-tap"(chairlift.Brewfile:1) is the same tap the repo elsewhere callsublue-os/tap(docs/skills/ci-pitfalls/SKILL.md:58 now says ChairLift addsublue-os/homebrew-tap, while line 60 says Zed lives inublue-os/tap). The dual spelling is why brew-preinstall:169-173 must protect both qualified names. Standardizing on the canonicalublue-os/tapwould simplify both.
Verified against head b8d40e9: ublue-os/homebrew-tap cask pins projectbluefin/chairlift v0.12.2 with matching sha256s; vendored polkit policy is byte-identical to upstream v0.12.2; desktop file differs only by the documented header + Exec= edit; all three icons hash-match upstream v0.12.2.
No findings from: security, docs-currency.
Confidence: 3/5 (needs attention) — 1 medium finding; 1 perspective requested changes
— hive: agent=reviewer backend=copilot model=claude-fable-5 copilot=1.0.78
`brew info --cask --json=v2 chairlift | jq '.casks[0].tap'` reports the source tap of any *resolvable* cask, not an installed one. With ChairLift never installed but `frostyard/tap` still tapped, bare-name resolution hit the frozen Frostyard cask, so the migration uninstalled a cask that was not installed, failed, and exited 1 with state unstamped — retrying every boot. Gate the migration on `brew list --cask chairlift` and on the installed receipt (`.casks[0] | select(.installed != null) | .tap`), and untap `frostyard/tap` best-effort after a successful uninstall so the bare token can never resolve back to the frozen cask. Also standardize on the canonical `ublue-os/tap` spelling. Homebrew strips the `homebrew-` repo prefix, so `ublue-os/homebrew-tap` named the same tap the rest of the repo calls `ublue-os/tap`; the dual spelling forced the handoff protection list to carry both qualified cask names. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
correctness
The legacy-cask migration's tap detection runs at the one moment it is most fragile: after the tap loop has tapped ublue-os/tap but before frostyard/tap is untapped, so both taps provide the bare token chairlift. brew-preinstall:109-110 resolves that bare token with brew info --cask --json=v2 chairlift and swallows every error (2>/dev/null ... || true). If Homebrew reports a tap ambiguity for the token — or resolves it to the newly-tapped ublue-os/tap cask instead of the installed one — installed_chairlift_tap comes back empty, migration is silently skipped, brew bundle then treats the cask as already installed (the exact cask_installed? token-match the PR body documents), the run exits 0 and the hash is stamped (brew-preinstall:92-95, 240-250). Result: the stranding-on-v0.10.1 this PR exists to fix becomes permanent and silent, because the hash gate never re-runs the migration. The bats mocks (tests/test_brew_preinstall.bats:794+) hard-code the friendly resolution, so they cannot catch this. Suggest deriving the installed tap from an ambiguity-proof source (e.g. brew list --cask --json=v2-style installed-only output or the Caskroom tab file) or, failing that, verifying the bare-token behavior on a real machine with both taps present before merge.
docs-currency
system_files/shared/usr/share/chairlift/config.yml:24-25 still says "upstream's updates_page schema is exactly the four groups above" — false as of the v0.12.2 bump this PR makes (six groups now: update_all_group, sysupdate_updates_group added). The matching claim was correctly removed from tests/test_chairlift_config.py:513-515 but this shipped comment was missed.
No findings from: security, intent-alignment, style.
Confidence: 3/5 (needs attention) — 1 medium finding; 2 perspectives requested changes
— hive: agent=reviewer backend=copilot model=claude-fable-5 copilot=1.0.78
The migration resolved the installing tap with a bare-token `brew info --cask --json=v2 chairlift`. By that point ublue-os/tap has already been tapped, so both taps provide the token: brew either raises TapCaskAmbiguityError or answers for the new, still-uninstalled cask. Both answers were swallowed, the migration silently skipped, brew bundle's token-matching cask_installed? saw ChairLift as present, the run exited 0 and stamped its hash — so it never retried and the user stayed stranded on the pre-rebrand v0.10.1 build. Read installed state instead: `brew info --json=v2 --installed` enumerates the Caskroom and resolves each entry from its own installed caskfile, so the tap it reports is the tap that installed it. Skip the migration only on positive evidence (tap is ublue-os/tap, or an unreadable tap whose installed version already matches the cask the new tap ships); anything inconclusive migrates, since the bundle that runs immediately afterwards repairs a redundant uninstall while a skipped migration repairs nothing. Only Brewfiles that actually declare ublue-os/tap/chairlift take part, and the legacy cask is named fully-qualified only while frostyard/tap is still present. Also correct the shipped config.yml comment that still claimed updates_page has exactly four groups; upstream v0.12.2 defines six. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
correctness
- (low) The migration gate is broader than its "legacy frostyard" framing:
brew-preinstall:136-146marks the install migrated only when the installed tap is exactlyublue-os/tap(or tap-unknown + version match), so a chairlift installed from any third-party tap is also uninstalled and replaced by the managed cask (brew-preinstall:148-170). The bats matrix (tests/test_brew_preinstall.bats:869-931) covers frostyard, unknown, and ublue-os taps but not this case. Deliberate per the "inconclusive answers migrate" comment, and low-impact — flagging so the design choice is on record.
Verified while reviewing at 882fe60: ublue-os/tap cask pins v0.12.2 with sha256s matching the release checksums.txt; the renamed polkit action id matches upstream v0.12.2's io.projectbluefin.chairlift naming and keeps the pinned exec.path annotation (asserted by tests/test_chairlift_config.py:172-180).
No findings from: security, intent-alignment, style, docs-currency.
Confidence: 5/5 (safe)
— hive: agent=reviewer backend=copilot model=claude-fable-5 copilot=1.0.88
The rebrand migration gate reads the exit code of the named lookup `brew list --cask chairlift`, and the projectbluefin#1109 pre-bundle snapshot calls the bare forms `brew list --formula` / `brew list --cask`, which real Homebrew exits 0 (possibly empty) for. Neither mock in this file modeled that split, so two tests failed once both code paths existed: - "repository manifests leave untracked installs alone" ran the real Brewfiles (including the rebranded chairlift.Brewfile) against the permissive default mock, where every list form exits 0. The gate read "chairlift installed" on a machine that never had it and uninstalled a cask that was not there. Give the test a local mock override — the same idiom as "skips uninstall for cask not installed by brew" — where named cask lookups exit 1. - "leaves a merely-resolvable legacy chairlift installed elsewhere alone" used write_chairlift_brew_mock with installed_tap=none, which exited 1 for every list form. The snapshot's bare queries tripped the script's fail-closed path and the run exited 1. Scope the exit 1 to named cask lookups so bare inventory forms succeed empty, as on a real machine. Full suite: bats sweep green, 112 pytest passed, just check passed. Assisted-by: Qwen3.8-27B via goose CLI
Danathar
left a comment
There was a problem hiding this comment.
Re-reviewed at 27d6e61. My blocker from the earlier review is fixed: brew-preinstall now uninstalls a ChairLift that was installed from frostyard/tap before brew bundle runs, so existing machines move to the ublue-os/tap v0.12.2 cask instead of staying on v0.10.1. The nit about the tap spelling is also done (ublue-os/tap).
What I checked:
- Read the full PR diff, including the new migration block, the bats cases and the doc changes.
ublue-os/homebrew-tapCasks/chairlift.rbpinsversion "0.12.2"with theprojectbluefin/chairliftrelease URL, matchingCHAIRLIFT_SCHEMA_REF.brew info --json=v2 --installedon a real Homebrew install reports atapfor each installed cask, which is what the migration reads.- Locally at this head:
bats tests/test_brew_preinstall.bats69/69,pytest tests/test_chairlift_config.py29 passed,tests/check-chairlift-configpasses against v0.12.2, shellcheck clean onbrew-preinstall. - Mutation: forcing
chairlift_migrated=1makes 4 bats cases fail (60, 61, 63, 67), so the migration path is really under test. - CI at this head: Build, Unit Tests, Validate PR, Validate Brewfiles and Validate ChairLift Config all succeeded. PR E2E composed the image, but the E2E suite job was skipped on this fork PR.
|
(Optional follow-up to my approval. Not blocking.) Two of the new bats cases in
To show it: I removed the |
castrojo
left a comment
There was a problem hiding this comment.
LGTM. Verified the ChairLift rebrand packaging and migration logic:
- Upstream Cask pins projectbluefin/chairlift v0.12.2.
- Preinstall migration uninstalls frostyard legacy cask prior to bundle.
- Policykit, desktop entries, and icons match upstream specs.
- All required checks ('validate', 'Build and push image (x86_64)', 'Build and push image (aarch64)') are green.
Summary
Downstream coordination for the ChairLift rebrand (
frostyard/chairlift->projectbluefin/chairlift,org.frostyard.ChairLift->io.projectbluefin.chairlift). Implements projectbluefin/chairlift#18 and closes #1115.The rebranded release is live:
projectbluefin/chairliftv0.12.2 produces GitHub releases directly (projectbluefin/chairlift#3), andublue-os/tapalready carries a cask pinned to it (sha256 values verified against the release'schecksums.txt).Changes
chairlift.Brewfilenow tapsublue-os/tapand casksublue-os/tap/chairlift, which pins theprojectbluefin/chairliftv0.12.2 release. The oldfrostyard/tapcask is frozen at the pre-rebrand v0.10.1. (Homebrew strips thehomebrew-repo prefix, soublue-os/tapis the canonical spelling of that tap and the one the rest of this repo already uses.)cask_installed?matches on the un-namespaced token (chairlift) and will not upgrade across taps, so an existingfrostyard/tap/chairliftinstall would strand users on v0.10.1.brew-preinstalltherefore uninstalls an installedfrostyard/tap/chairliftbefore bundling (brew-preinstall:100-124), then untapsfrostyard/tapbest-effort so the bare token cannot resolve back to the frozen cask. The migration is gated on the cask actually being installed (brew list --cask chairliftplus theinstalledfield ofbrew info --cask --json=v2), so a machine that merely hasfrostyard/taptapped is untouched. A failed uninstall leaves state unstamped so the run is retried.--external-chairliftcallers are exempt: they own migration.tests/check-chairlift-configbumpsCHAIRLIFT_SCHEMA_REFv0.10.1 -> v0.12.2 and repointsUPSTREAM_RAWtohttps://raw.githubusercontent.com/projectbluefin/chairlift/...in the same commit as the cask change, per the gate's own "bump together with the cask" invariant.org.frostyard.ChairLift.*->io.projectbluefin.chairlift.*. The policy and desktop entry are re-vendored from upstream v0.12.2 (the desktop keeps its only edit: the absolute wrapperExec=path); the icons are byte-identical to v0.10.1, so they are pure renames.bootc-update-stageheader comments follow the new action ID and policy path.brew-preinstall --external-chairliftprotects the ChairLift cask nameschairlift,frostyard/tap/chairliftandublue-os/tap/chairliftfrom OS-diet removal.test_chairlift_config.pyupdated for the new IDs, the new Brewfile, the v0.12.2 pin, and the v0.12.2 schema surface (8 new groups:channel_group,update_all_group,sysupdate_updates_group,reset_group,dx_group,gaming_group,ai_group,troubleshooting_group; new fieldsai_images,ai_model). Bluefin'sconfig.ymlgroup choices are intentionally unchanged: every key it uses still exists in the v0.12.2 schema (verified live below).Verification
pytest tests/test_chairlift_config.py— 29 passedpytest tests/test_skill_docs.py— 10 passedpython3 tests/check-chairlift-config(live networked run) — "ChairLift config uses only keys upstream defines." against v0.12.2bats tests/test_brew_preinstall.bats— 53 passed, including the extended handoff test covering the new cask name and three legacy-migration tests (installed legacy cask migrated + untapped; resolvable-but-not-installed cask left alone; installed non-legacy cask left alone)ublue-os/tapmatch the v0.12.2 releasechecksums.txtexactlyCoordination notes
files/chairlift/install.shhard-checks the old Brewfile shape (tap "frostyard/tap", trusted: true) and overrides it at image build time. It needs a follow-up there: accept the new shape in its guard, and confirm its override still matchesublue-os/tap/chairlift.sysupdate_updates_group,dx_group,gaming_group,ai_group, ...) is a product decision requiring the matching helpers/backends on the image; this PR is packaging plumbing only.— hive: backend=goose model=unsloth/Qwen3.8-27B
🐝 Hive Agent:
contributor| SHA:b36de14