Filed by the domain:ui PM seat (session session_013hfmP9hoMd3dJwTh85J4yB) on behalf of the
clause-② contract reviewer of PR #6884, which raised it as its third finding and correctly
scoped it out of that PR. Recording so it does not die with the thread. ⛔ Not graded here —
grading is the triage seat's.
Dedup before filing: semantic search over this repo for the guard, the wire entry, and the
over-claim returned exactly one issue — objectui#4934, the parent card itself. That hit is the
positive control: the query reaches this topic's neighbourhood, so the absence of a second hit
is a reading rather than a broken query.
What
PR #6884 (card objectui#4934) deleted the boundary's central lie: notifyDroppedFields used a
hand-written e is DroppedFieldsEvent predicate that checked only Array.isArray(fields),
asserting an entry into the spec type while never reading reason. The fix replaced it with
type WireDroppedFieldsEntry = Omit<DroppedFieldsEvent, 'reason'> & { reason?: unknown };
whose reason is honestly unknown until parsed. That is the right shape, and it is why the
PR was accepted.
But the same predicate still over-claims two smaller things, and for the same reason the
original claim was wrong — it asserts a type the runtime check does not establish:
fields element types. The filter checks Array.isArray(e.fields) && e.fields.length > 0.
It does not check that the elements are strings, yet the entry is asserted into a type whose
fields is string[]. A server sending fields: [42] or fields: [{...}] passes the filter
and reaches subscribers typed as string[].
object presence. Omit<DroppedFieldsEvent, 'reason'> carries whatever object's
declared optionality is on the spec type; nothing in the filter reads object at all.
Why it is a finding and not a bug, and why it did NOT belong in PR #6884
Stated plainly so a future triage does not re-derive it:
Not measured
Whether any server in practice emits a non-string fields element, or omits object where a
consumer reads it. That is the pull question and it is triage's. The one reader today is
packages/app-shell/src/providers/writeWarningToast.ts, which renders field names through a
label resolver — worth checking what that does with a non-string before deciding this is worth
repairing at all.
The shape a fix would take, if triage rules it worth doing
Parse rather than assert, exactly as #6884 did for reason: narrow the filter to check element
types (and object, if a reader depends on it), OR keep the filter permissive and let the
declared type say unknown for what it has not checked. ⛔ What it must not do is keep the
current split — a check that verifies one thing and a type that claims another is the defect
class this whole card family exists to remove.
Related
objectui#4934 (parent card) · PR #6884 (where the reviewer raised it) · objectui#3935 (the
exhaustive-table hazard that made reason the urgent half) · objectui#3160 (the canonical arm
that must not be widened to string)
Filed by the
domain:uiPM seat (sessionsession_013hfmP9hoMd3dJwTh85J4yB) on behalf of theclause-② contract reviewer of PR #6884, which raised it as its third finding and correctly
scoped it out of that PR. Recording so it does not die with the thread. ⛔ Not graded here —
grading is the triage seat's.
Dedup before filing: semantic search over this repo for the guard, the wire entry, and the
over-claim returned exactly one issue — objectui#4934, the parent card itself. That hit is the
positive control: the query reaches this topic's neighbourhood, so the absence of a second hit
is a reading rather than a broken query.
What
PR #6884 (card objectui#4934) deleted the boundary's central lie:
notifyDroppedFieldsused ahand-written
e is DroppedFieldsEventpredicate that checked onlyArray.isArray(fields),asserting an entry into the spec type while never reading
reason. The fix replaced it withwhose
reasonis honestlyunknownuntil parsed. That is the right shape, and it is why thePR was accepted.
But the same predicate still over-claims two smaller things, and for the same reason the
original claim was wrong — it asserts a type the runtime check does not establish:
fieldselement types. The filter checksArray.isArray(e.fields) && e.fields.length > 0.It does not check that the elements are strings, yet the entry is asserted into a type whose
fieldsisstring[]. A server sendingfields: [42]orfields: [{...}]passes the filterand reaches subscribers typed as
string[].objectpresence.Omit<DroppedFieldsEvent, 'reason'>carries whateverobject'sdeclared optionality is on the spec type; nothing in the filter reads
objectat all.Why it is a finding and not a bug, and why it did NOT belong in PR #6884
Stated plainly so a future triage does not re-derive it:
reasonwas the field a consumerbranches on — an exhaustive table over it was the demonstrated hazard (writeWarningToast branches on
DroppedFieldsEvent.reasonwith a binary ternary, so every future reason is labelled "Read-only" #3935).fieldsisrendered as text, so a non-string element degrades to a wrong label rather than to a
false-impossible branch.
reasonagainst the spec enum at the boundary #6884 — the old predicate had the same hole, hidden undera larger one.
reasonagainst the spec enum at the boundary #6884 to cover it would have been the exact move that PR's own ruling forbade.The 2026-08-22 maintainer ruling scoped the change to
reason; absorbing adjacentboundary-honesty work into it is how a bounded fix becomes an unbounded one.
Not measured
Whether any server in practice emits a non-string
fieldselement, or omitsobjectwhere aconsumer reads it. That is the pull question and it is triage's. The one reader today is
packages/app-shell/src/providers/writeWarningToast.ts, which renders field names through alabel resolver — worth checking what that does with a non-string before deciding this is worth
repairing at all.
The shape a fix would take, if triage rules it worth doing
Parse rather than assert, exactly as #6884 did for
reason: narrow the filter to check elementtypes (and
object, if a reader depends on it), OR keep the filter permissive and let thedeclared type say
unknownfor what it has not checked. ⛔ What it must not do is keep thecurrent split — a check that verifies one thing and a type that claims another is the defect
class this whole card family exists to remove.
Related
objectui#4934 (parent card) · PR #6884 (where the reviewer raised it) · objectui#3935 (the
exhaustive-table hazard that made
reasonthe urgent half) · objectui#3160 (the canonical armthat must not be widened to
string)