Skip to content

finding(app-shell): every envelope reader on the package surfaces drops producer-marked text — fetchPackages discards the whole body, apiJson reads no userMessage #7959

Description

@os-sam

Observation

Found while implementing objectui#7938 (fetchFullPackage dropping the producer-marked
error.userMessage), while establishing which of that endpoint's readers actually parse
the envelope. Deliberately not fixed there: that card's file surface is fetchFullPackage
inside StudioDesignSurface.tsx, and this sits in a different module.

fetchPackages in packages/app-shell/src/views/studio-design/packages-io.ts reads a
failure like this:

export async function fetchPackages(): Promise<PkgEntry[]> {
  const res = await fetch('/api/v1/packages', { /* … */ });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return parsePackages(await res.json());
}

It never opens the body. Not error.message, not error.code, not error.userMessage
the response is discarded and the status becomes the whole report.

Why that matters, measured

GET /api/v1/packages has FOUR readers on the Studio design surface. The
openManage docblock in StudioDesignSurface.tsx names them, and they split two ways:

reader goes through reads the envelope?
switcher list (mount effect + onManageChanged head) fetchPackages no
writability courtesy gate (ADR-0124 D1) fetchPackages no
namespace lookup (framework#2694) fetchPackages no
fetchFullPackage (manage sheet + snapshot refresh) its own reader yes

Only the fourth parses the body. So three of the four surface a 403 FORBIDDEN whose
message names the very capability to grant — Reading packages requires the studio.accessorsetup.access capability. — as the four characters 403.

All three report through formatMetadataError on the shared studio-package-list
sonner id (objectui#7368's posture), so the plumbing to display words is already there
and already wired. What is missing is words to put in it: formatMetadataError returns
err.message, and the message it is handed is HTTP 403.

This is a strictly larger loss than objectui#7938's. That card was about ONE optional
field being dropped from a body that was otherwise read; this is the body never being
read at all — message, code and userMessage alike.

Why it is a separate card and not a rider

Three reasons, all of them boundary rather than size:

  1. Different file. objectui#7938's declared file surface is fetchFullPackage plus one
    pin test in the same package; packages-io.ts is neither.
  2. Different blast radius. packages-io.ts is shared with the builder landing page
    (parsePackages's module doc says so), so its readers are not all on the Studio
    design surface and its callers were not all measured by that card.
  3. Different question underneath. fetchFullPackage and fetchPackages now hold two
    independent implementations of "read the ADR-0112 failure envelope", and the real
    decision is probably whether that ladder should be ONE shared helper rather than
    whether to copy it a second time — see below.

Worth deciding

  1. Give fetchPackages the same ladder fetchFullPackage now has (marked text, then
    diagnostic, then code, falling back to the status). Smallest change; leaves two copies
    of one rule free to drift, which is the shape that produced this card.
  2. Extract the envelope read into one exported helper and have both call it. Fixes the
    drift as well as the loss; touches both modules and wants its own pin.
  3. Leave fetchPackages bare and record why — e.g. if the three degradation-only readers
    are judged to want a short status rather than a server sentence in their toast. That
    is a defensible answer, but it should be the recorded one rather than the default.

Not measured in this card: whether the sibling apiJson helper in
packages/app-shell/src/views/metadata-admin/PackagesPage.tsx (flagged in objectui#7938's
own body as part of the same question) should be folded into option 2. It has the
identical payload?.error?.message ladder and also serves lifecycle actions.

Re-check

sed -n '/export async function fetchPackages/,/^}/p' packages/app-shell/src/views/studio-design/packages-io.ts
grep -n "fetchPackages()" packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx
grep -rn "userMessage" packages/app-shell/src/views/

Related, not duplicates: objectui#7938 (the fourth reader, fixed), objectui#7368 (the
report channel these three already share), objectui#7821, objectui#7881, objectui#7907 —
the same family of "a read that could not happen is reported as something else".

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