Skip to content

Make the Homebrew cask generator arm64-only to match the Intel-macOS drop #2171

Closed

Description

@malibio

Problem

#2169 dropped Intel (x86_64) macOS from release CI, making Apple Silicon the only supported macOS target. Most of the distribution surface already reflects that decision, but scripts/update-homebrew-cask.ts still carries a full Intel code path that can no longer be exercised.

This is cleanup, not a live defect. The generator already degrades correctly: resolveArchDigests() treats a missing architecture as non-fatal, and renderCask() falls through to its single-architecture branch, emitting depends_on arch: :arm64 and no Intel URL. Confirmed against the published tap — Casks/nodespace.rb is arm64-only today, correctly documented, and brew install --cask nodespace is not broken.

The cost is dead code that reads as if Intel were still supported, and a two-architecture rendering branch that is now unreachable and untestable against any real release.

Current state (verified 2026-08-19)

Already consistent with #2169 — no action needed:

  • scripts/release.ts — release-notes table dropped the Intel DMG row and the stale "Intel Mac Support" changelog entry (fixed in Drop Intel (x86_64) macOS from release CI #2169)
  • scripts/publish-install-script.ts — x86_64-apple-darwin is deliberately excluded from the target list, with a comment saying so
  • homebrew-nodespace Casks/nodespace.rb — published cask is arm64-only, depends_on arch: :arm64, with a platform-support note

Still carrying Intel:

  • scripts/update-homebrew-cask.ts
    • ArchDigest.arch: "arm" | "intel"
    • ARCH_SUFFIX: Record<"arm" | "intel", string> = { arm: "aarch64", intel: "x64" }
    • ArchDigestResult.intel?
    • resolveArchDigests() builds a wanted map including the Intel .dmg and loops both architectures — so every run downloads-or-misses an asset CI no longer produces, and reports it in missing, printing a ⚠ missing release assets warning on every release
    • renderCask()'s two-architecture branch emitting on_arm/on_intel, plus the Intel half of archNote
  • scripts/update-homebrew-cask.test.ts — a test asserting the on_arm/on_intel both-architectures rendering, and intelDigest fixtures

Fix direction

Make the generator arm64-only, matching the decision rather than tolerating its absence:

  • Collapse the arch union to arm; replace ARCH_SUFFIX with a single aarch64 constant
  • resolveArchDigests() resolves only the Apple Silicon .dmg. A missing arm asset should be a hard error (there is no other architecture to fall back to), not a warning
  • renderCask() keeps one rendering path — top-level url/sha256 plus depends_on arch: :arm64 — and drops the on_arm/on_intel branch
  • Update the tests: delete the both-architectures case and the Intel fixtures; keep coverage that the rendered cask pins arm64 and contains no x64 URL
  • Carry the rationale in a comment, as publish-install-script.ts and the published cask already do: Apple Silicon is the only supported target because x86_64 macOS artifacts cannot be tested, and this is reversible

The eliminated warning is a side benefit: today every release prints ⚠ missing release assets ... NodeSpace_<v>_x64.dmg, which is noise that trains operators to ignore that warning line.

Also in scope: correct the file's stale header comment

scripts/update-homebrew-cask.ts's header docblock still describes the script as not yet wired into CI, which is no longer true and actively misleads anyone reading it (it misled a review of this exact area). Since this issue already edits the file, fix the comment here rather than filing separately.

Two stale claims:

  1. "a PAT ... set as a repo secret once this is wired into the release flow"

    HOMEBREW_TAP_TOKEN is set as a repo secret (added 2026-08-19).

  2. "this script is a natural sibling job there, or a manual step run right after bun run release:watch reports the build finished, until it is wired into CI directly."

    It is wired in. release.yml has a sync-homebrew-cask job that runs --push on the release event with HOMEBREW_TAP_TOKEN in its env, gated on build-tauri-macos-arm (deliberately not on build-tauri, so a Windows failure cannot block the cask sync), with a notify-failure job that opens an issue if it fails. homebrew-drift-check.yml is a scheduled backstop.

Rewrite the "Where this hooks in" paragraph to describe the actual wiring and point at the sync-homebrew-cask job, so the file documents what happens rather than what was once planned. The --push/HOMEBREW_TAP_TOKEN usage lines above it stay accurate and can remain.

Comment-only — no behavior change.

Non-goals

  • No change to release.ts, publish-install-script.ts, or the published cask — all already correct
  • Not re-litigating Drop Intel (x86_64) macOS from release CI #2169. Re-adding an architecture later means restoring a suffix map and a rendering branch; the comment should say so

Acceptance criteria

  • scripts/update-homebrew-cask.ts has no intel / x64 code path
  • A missing Apple Silicon .dmg fails loudly rather than rendering a cask with no URL
  • No ⚠ missing release assets warning on a normal arm64-only release
  • renderCask() output is byte-identical to the currently published Casks/nodespace.rb for v0.2.0 (pure refactor — no behavior change to the artifact)
  • Tests updated; both-architectures test and Intel fixtures removed; bun run test:scripts passes
  • Comment records why Apple Silicon is the only target and what re-adding one would involve
  • Header docblock no longer claims the script is unwired/manual; it describes the sync-homebrew-cask job and the already-set HOMEBREW_TAP_TOKEN secret

Related

Activity

  1. mstomar125 commented on Aug 20, 2026

    @mstomar125
    Contributor

    Merged in #2174 (997032d).

    scripts/update-homebrew-cask.ts is now arm64-only, matching #2169's decision explicitly rather than tolerating Intel's absence implicitly:

    • ArchDigest.arch collapsed from "arm" | "intel" to "arm"; ARCH_SUFFIX: Record<"arm"|"intel", string> replaced with a single ARCH_SUFFIX_AARCH64 constant; ArchDigestResult.intel? dropped.
    • resolveArchDigests() resolves only the Apple Silicon .dmg and throws a hard error if it's missing — no other architecture to fall back to.
    • renderCask() keeps exactly one rendering path (top-level url/sha256 + depends_on arch: :arm64); the on_arm/on_intel branch is gone.
    • Rationale comment added on ArchDigest (why Apple Silicon only, that it's reversible, what re-adding an architecture would involve), matching publish-install-script.ts's pattern.
    • Header docblock rewritten: no longer claims the script is unwired/manual, now describes release.yml's sync-homebrew-cask job (gated on build-tauri-macos-arm, --push + HOMEBREW_TAP_TOKEN, notify-failure on failure) and homebrew-drift-check.yml as the scheduled backstop.
    • Fixed a stale comment in release.yml's sync-homebrew-cask job that still described the old tolerant/non-fatal behavior — caught by the adversarial review, addressed before merge.

    Byte-identical verification, actually checked, not assumed: rendered renderCask("v0.2.0", ...) with the real published sha256 and diffed against a live gh api repos/NodeSpaceAI/homebrew-nodespace/contents/Casks/nodespace.rb fetch — output is byte-for-byte identical (confirmed via diff -u and matching shasum -a 256). This required updating the generator's comment constants to match the tap's actual published wording, which had drifted from the old generator's single-arch output even before this change; a new test pins the two together going forward.

    Acceptance criteria

    • scripts/update-homebrew-cask.ts has no intel/x64 code path
    • A missing Apple Silicon .dmg fails loudly rather than rendering a cask with no URL
    • No ⚠ missing release assets warning on a normal arm64-only release
    • renderCask() output verified byte-identical to the published Casks/nodespace.rb for v0.2.0
    • Tests updated; both-architectures test and Intel fixtures removed; bun run test:scripts passes (110 pass, 0 fail)
    • Comment records why Apple Silicon is the only target and what re-adding one would involve
    • Header docblock no longer claims the script is unwired/manual; describes the sync-homebrew-cask job and the set HOMEBREW_TAP_TOKEN secret

    Adversarial review (general-purpose subagent) ran against the real diff, independently re-verified the byte-identical claim, and found no blockers — one real, non-blocking finding (the stale release.yml comment above) addressed before merge.

    Full pre-push gate (scripts/test-gate.ts) passed clean, including cargo test -p nodespace-app (ADR-048 Tauri-seam integration suite, 70+ tests). Along the way, found and fixed a genuinely stale local build artifact in this worktree (the nodespaced sidecar/debug binaries predated yesterday's #2167/#2168 fix by about a month, unrelated to this PR's diff) that had caused the pre-push gate's ai_chat_send_to_idle_test to hang on repeated attempts — rebuilt via bun run --cwd packages/desktop-app dev:tauri:sidecars and a direct cargo build, confirmed fixed, then the gate passed clean.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions