Skip to content

Acquisition coherence — 4 design questions for team sign-off (Q3/Q4/Q6/Q7) #49

@radical

Description

@radical

Acquisition coherence — 4 design questions for team sign-off

Status issue: #29 · Microsoft tracking: microsoft#15949 · Runbook: https://gist.github.com/radical/86bce917075fd87e684be5c3aecb0c37

These four decisions block implementation work in B3 (#40), B4 (#41), B5 (#42), and the --break-install path in B2 (#39). I'm batching them so the trade-offs can be weighed against each other in one pass instead of four separate threads.

Each question has my recommended lean. Sign-off needed on the lean, or pick a different option.


Q3 — Channel scope (#34)

Where does aspire.config.json's channel field live and who reads it?

Option What it means Pro Con
A — Global, last-writer-wins Today's behavior Simplest impl Causes W34: S.u --channel daily poisons W's view of channel
B — Per-route (own section under installs.<route>.channel) Each route reads its own Clean isolation; no cross-route bleed Need migration; project-level aspire update must pick a route to read from (active PATH binary)
C — Hybrid: global default + per-route override Project commands read route override if present, else global Backward compatible; isolates explicit overrides More config code paths; harder to reason about

Lean: B. Cleanest semantics; the only reason for global-default (C) is migration, and migration cost is low (one-shot read-old-write-new on first run after upgrade). PATH-active binary is the right "active route" definition.

Q4 — Hive scope (#35)

Where do PR-script and dev-channel SDK hives live, and how are they isolated?

Option Layout Pro Con
A — Single shared ~/.aspire/hives/ keyed by hive ID Today's layout Simplest Routes don't own their hives; leakage on uninstall
B — Route-scoped: ~/.aspire/hives/<install-id>/<hive-id>/ Each route owns its hives Uninstall is just rm -rf <install-id>/; clean Disk usage if multiple routes use the same NuGet content
C — Content-addressed dedup with route-owned references hives/by-content/<hash>/, route dir has symlinks/manifests No duplication; clean ownership Significant impl complexity for v1

Lean: B. Aligns with the install-id model from B0 (#33); makes uninstall trivial. Disk dup is acceptable for v1; revisit C in v2 if it actually hurts.

Q6 — Running CLI vs --self semantics (#36)

What does aspire update --self do when other aspire processes are running?

Option Behavior Pro Con
A — Refuse hard Print "N aspire processes running, stop them first" and exit Safe; never corrupts a running process's bundle User friction; common case is "I forgot a long aspire run in another tab"
B — Warn and proceed (atomic flip) Warn, do versioned bundle install, atomic binary swap; running CLIs keep their old bundle dir UX-friendly; standard package-manager behavior Requires correct atomicity (today's reparse flip is non-atomic on Windows — gap in B5)
C — Warn, proceed, with --force-while-running to suppress warning Same as B but explicit opt-in to silence Best of both Adds a flag

Lean: C. Same as --break-install philosophy — warn loudly by default, give an opt-out for users who know what they're doing. Conditional on B5 (#42) closing the Windows atomicity gap — without that, we should pin to A on Windows.

Q7 — Self-update on package-manager-installed binaries (#37)

What happens when aspire update --self runs from a binary owned by winget/brew/dotnet-tool?

(dotnet-tool already redirects. This is about W and H.)

Option Behavior Pro Con
1 — Silent clobber (today) Replace the pkg-mgr-owned binary Works for end users who don't know/care Corrupts pkg-mgr state (W1 in bae142); next winget upgrade/brew upgrade is unpredictable
2 — Refuse, redirect Print "this is a winget install; run winget upgrade Microsoft.Aspire" and exit Pkg-mgr stays consistent Some users genuinely want a non-stable channel and pkg-mgr only ships stable
3 — Refuse + side-install Refuse to mutate W's binary; install S-style copy at ~/.aspire/bin/aspire so PATH precedence makes it active Both routes coherent; user gets daily Creates a "shadow install" that user didn't ask for; confusing
4 — Refuse with explicit --break-install to opt into option 1 behavior Default refuse; flag opts into clobber + warning Honest; user owns the consequence Users may not discover the flag
5 — Refuse + --break-install, plus suggest the script route in the refusal message Same as 4, but the refusal message includes "or use bash <(curl -fsSL https://aspire.dev/install.sh) --channel daily" Best UX: refuses by default, points users at the right tool, escape hatch exists None significant

Lean: 5. Naming is --break-install (mirrors pip --break-system-packages honesty). See bae142 W1 for evidence the silent clobber is a real bug.


Cross-cutting impact summary

Decision Blocks
Q3 B3 #40 (channel write semantics), B2 #39 (notification text per route), B4 #41 (uninstall channel sweep)
Q4 B4 #41 (uninstall sweep includes hives), B5 #42 (storage layout)
Q6 B2 #39 (--self flow), B5 #42 (atomicity requirement validates the lean)
Q7 B2 #39 (the whole --break-install code path)

If you sign off on all 4 leans, B0 + B1 are already feasible and B2/B3/B4/B5 unblock immediately. If you push back on any, comment on the relevant question issue (#34, #35, #36, #37); I'll re-thread there.

Metadata

Metadata

Assignees

No one assigned

    Labels

    acquisitionAspire CLI acquisition coherence workdecision-neededNeeds design or product decisionstatus-issueMaster tracker / status issue

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions