Skip to content

finding(app-shell): onManageChanged's managed-snapshot refresh swallows a failed read, so the open sheet shows a pre-action record as current #7907

Description

@claude

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

  1. 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.
  2. Report and mark the sheet's record as stale, so the staleness survives the toast (a
    toast disappears; an open sheet does not).
  3. 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

Activity

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

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatfindingpackage: app-shellpriority:p2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions