Review everything shipped this weekend, and fix what the reviewers caught

Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
Gabriel Brown
2026-08-24 13:29:42 -04:00
parent ffce48964e
commit 07db1068f1
42 changed files with 959 additions and 219 deletions
+20 -7
View File
@@ -100,14 +100,19 @@ const free = model.createCustomProfile([], {
})
assert.equal(free.profile.name, 'Nord')
assert.equal(free.profile.id, 'custom-nord')
// A stored custom colliding with a catalog name is dropped; the same record
// against the three-entry fallback is kept, because there "Nord" is free.
// A stored custom colliding with a catalog name is RENAMED, never dropped —
// upgrades that add shipped themes must not delete a user's saved theme. The
// same record against the three-entry fallback keeps its name, because there
// "Nord" is free. Ids stay the identity either way.
const impostor = {
id: 'custom-nord', name: 'Nord', scheme: 'dark',
accent: '#88c0d0', secondary: '#81a1c1', shipped: false
}
assert.equal(model.validCustomProfiles([impostor], shippedCatalog).length, 0)
assert.equal(model.validCustomProfiles([impostor]).length, 1)
const renamed = model.validCustomProfiles([impostor], shippedCatalog)
assert.equal(renamed.length, 1)
assert.equal(renamed[0].id, 'custom-nord')
assert.equal(renamed[0].name, 'Nord 2')
assert.equal(model.validCustomProfiles([impostor])[0].name, 'Nord')
// ── createCustomProfile carries the optional fields through ─────────────────
const rich = model.createCustomProfile([], {
@@ -287,7 +292,7 @@ cleanup() {
trap cleanup EXIT
qs_for_test --daemonize >/dev/null
for _ in $(seq 1 40); do
for _ in $(seq 1 100); do
qs_for_test ipc show 2>/dev/null | rg -q '^target theme-profiles-test$' && break
sleep 0.1
done
@@ -297,8 +302,16 @@ qs_for_test ipc show 2>/dev/null | rg -q '^target theme-profiles-test$' \
status() { qs_for_test ipc call theme-profiles-test status; }
# The catalog is live here, so the profile list is the ten shipped themes, not
# the three-entry pre-load fallback.
jq -e '.active.id == "moon" and (.profiles | length) == 10' <<<"$(status)" >/dev/null
# the three-entry pre-load fallback. The catalog arrives through an async
# FileView read, so under a loaded machine (the full suite) it can land a
# beat after the IPC target does -- wait for it rather than asserting the
# race.
for _ in $(seq 1 50); do
jq -e '(.profiles | length) == 10' <<<"$(status)" >/dev/null 2>&1 && break
sleep 0.1
done
jq -e '.active.id == "moon" and (.profiles | length) == 10' <<<"$(status)" >/dev/null \
|| { printf 'theme profiles contract: catalog never loaded ten themes: %s\n' "$(status)" >&2; exit 1; }
# ── A scheme flip lands on the remembered theme for that side ───────────────
# This is the whole point of themeDark/themeLight. Before them, flipping to