Observation
Found while implementing objectui#7881 (fetchFullPackage never reading res.ok), in
the same component, one callback below it. Deliberately not fixed there: that card is
scoped to the lookup behind openManage, and PR #7879's dispatch fenced
onManageChanged off explicitly.
onManageChanged in packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx
runs after every package lifecycle action fired from the PackageDetailSheet (disable /
duplicate / delete / publish / manifest edit). Its tail refreshes the managed
snapshot so an edit shows immediately:
try {
const fresh = await fetchFullPackage(managedId);
if (fresh) setManage(fresh);
} catch {
/* keep the current snapshot */
}
That catch is silent, and the sheet stays open on the record it already had. So when
the refresh fails, the author has just performed a lifecycle action, the sheet reports
nothing, and what they are reading is the pre-action snapshot presented as current —
the same "a read that could not happen is reported as a read that found nothing" family
as objectui#7368, objectui#7821 and objectui#7881, in the one place on this surface that
still swallows.
Two things make it worth a card now rather than before:
- Before objectui#7881 that
catch could only ever catch a res.json() rejection — a
non-JSON body. With res.ok now read, it also catches every 4xx/5xx the endpoint
serves (401 / 403 / 503 / 500), so the arm it silences got substantially wider.
- Unlike the head of the same callback — which objectui#7821 taught to report through
formatMetadataError on the shared studio-package-list sonner id and to record
pkgsErr — this tail reports through nothing at all. The posture already exists three
lines above it.
Not necessarily the same call
The head of onManageChanged draws an inference from a failed read (deletion or
not), which is why objectui#7821 had to stop it. This tail draws no inference: keeping
the current snapshot on a failed refresh is a defensible degradation, and objectui#7368's
standing ruling is that one 503 must not take the Studio down. The gap is that the
degradation is silent — the author cannot tell a refreshed record from a stale one.
Reporting it on the shared toast id would close that without changing the degradation.
Worth deciding
- Report on the shared
studio-package-list sonner id and keep the stale snapshot —
cheapest, and reuses the posture already in this callback's own head.
- Report and mark the sheet's record as stale, so the staleness survives the toast (a
toast disappears; an open sheet does not).
- Leave it silent and say so in writing, i.e. record why this one arm is exempt.
Re-check
grep -n "keep the current snapshot" -B 6 packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx
Related, not duplicates: objectui#7368 (the switcher's silence, merged), objectui#7821
(the false-deletion eviction, merged as #7879), objectui#7881 (the lookup, PR #7906).
Generated by Claude Code
Observation
Found while implementing objectui#7881 (
fetchFullPackagenever readingres.ok), inthe same component, one callback below it. Deliberately not fixed there: that card is
scoped to the lookup behind
openManage, and PR #7879's dispatch fencedonManageChangedoff explicitly.onManageChangedinpackages/app-shell/src/views/studio-design/StudioDesignSurface.tsxruns after every package lifecycle action fired from the
PackageDetailSheet(disable /duplicate / delete / publish / manifest edit). Its tail refreshes the managed
snapshot so an edit shows immediately:
That
catchis silent, and the sheet stays open on the record it already had. So whenthe refresh fails, the author has just performed a lifecycle action, the sheet reports
nothing, and what they are reading is the pre-action snapshot presented as current —
the same "a read that could not happen is reported as a read that found nothing" family
as objectui#7368, objectui#7821 and objectui#7881, in the one place on this surface that
still swallows.
Two things make it worth a card now rather than before:
catchcould only ever catch ares.json()rejection — anon-JSON body. With
res.oknow read, it also catches every 4xx/5xx the endpointserves (401 / 403 / 503 / 500), so the arm it silences got substantially wider.
formatMetadataErroron the sharedstudio-package-listsonner id and to recordpkgsErr— this tail reports through nothing at all. The posture already exists threelines above it.
Not necessarily the same call
The head of
onManageChangeddraws an inference from a failed read (deletion ornot), which is why objectui#7821 had to stop it. This tail draws no inference: keeping
the current snapshot on a failed refresh is a defensible degradation, and objectui#7368's
standing ruling is that one 503 must not take the Studio down. The gap is that the
degradation is silent — the author cannot tell a refreshed record from a stale one.
Reporting it on the shared toast id would close that without changing the degradation.
Worth deciding
studio-package-listsonner id and keep the stale snapshot —cheapest, and reuses the posture already in this callback's own head.
toast disappears; an open sheet does not).
Re-check
Related, not duplicates: objectui#7368 (the switcher's silence, merged), objectui#7821
(the false-deletion eviction, merged as #7879), objectui#7881 (the lookup, PR #7906).
Generated by Claude Code