Found while measuring objectui#7265's @object-ui/core slice (PR #9127). Not fixed there, and not a regression from it: the behaviour is byte-identical before and after that change, which is exactly why it fell outside that card's fence.
What happens
resolveContextTokens in packages/core/src/utils/filter-tokens.ts looks a near-miss spelling up in the suggestion map with a plain bracket index:
const suggestion = CONTEXT_TOKEN_SUGGESTIONS[token.toLowerCase()];
if (suggestion) {
warn(
`Filter placeholder "{${token}}" is not a recognised token — did you mean ` +
`"{${suggestion}}"? …`,
);
}
The map is a plain object literal, so the index reaches Object.prototype for any token whose lower-cased spelling is an inherited member. Two spellings get through the WHOLE_TOKEN_RE character class ([a-zA-Z0-9_]+) and land on one:
constructor => "Filter placeholder \"{constructor}\" is not a recognised token — did you mean
\"{function Object() { [native code] }}\"? It is sent to the server as a literal
string and will match no records."
__proto__ => "Filter placeholder \"{__proto__}\" is not a recognised token — did you mean
\"{[object Object]}\"? …"
valueOf => (no warning)
hasOwnProperty => (no warning)
toString => (no warning)
Measured on @objectstack/spec@17.4.0 by driving the real resolver. The three that stay quiet do so only by luck of case-folding: toString lower-cases to tostring, valueOf to valueof, hasOwnProperty to hasownproperty — none of which is a prototype member. constructor and __proto__ are already lower-case, so they are the whole hit set today. That also means the quiet three are quiet for a reason nobody chose, and a future member whose name is already lower-case would join the noisy set silently.
Why it is worth a card rather than a shrug
The harm is bounded — a confusing console warning, and the value is passed through untouched either way, so no filter widens or narrows. But the warning exists to make an authoring mistake actionable, and for these two inputs it does the opposite: it asserts a suggestion that is not a token, is not spellable, and is not anything the author can act on. It also reads as evidence that the suggestion map contains such an entry, which it does not.
Scope note, deliberately not acted on here
The same shape is in the platform contract's own consumer of the same map. classifyFilterToken in the installed @objectstack/spec@17.4.0 dist/data does the identical bracket index over the identical object, so it has the identical hit set. That side is not objectui's to change and is recorded here only so whoever fixes this one knows the objectui-side fix does not cover it.
Fix sketch (not prescriptive)
Guard the read on own-property membership, or build the lookup over a null-prototype object. Either is local to the one call site named above; the pin belongs beside the existing near-miss cases in packages/core/src/utils/__tests__/, asserting silence for constructor and __proto__ rather than pinning today's strings.
Refs: objectui#7265 (the card this was found under) · PR #9127 (which deliberately left it alone).
Filed by the dev seat on PR #9127, generated with Claude Code, session session_01UzHd6hDYatoDn17BuwKxnZ. Unassigned, for triage to grade and route.
Found while measuring objectui#7265's
@object-ui/coreslice (PR #9127). Not fixed there, and not a regression from it: the behaviour is byte-identical before and after that change, which is exactly why it fell outside that card's fence.What happens
resolveContextTokensinpackages/core/src/utils/filter-tokens.tslooks a near-miss spelling up in the suggestion map with a plain bracket index:The map is a plain object literal, so the index reaches
Object.prototypefor any token whose lower-cased spelling is an inherited member. Two spellings get through theWHOLE_TOKEN_REcharacter class ([a-zA-Z0-9_]+) and land on one:Measured on
@objectstack/spec@17.4.0by driving the real resolver. The three that stay quiet do so only by luck of case-folding:toStringlower-cases totostring,valueOftovalueof,hasOwnPropertytohasownproperty— none of which is a prototype member.constructorand__proto__are already lower-case, so they are the whole hit set today. That also means the quiet three are quiet for a reason nobody chose, and a future member whose name is already lower-case would join the noisy set silently.Why it is worth a card rather than a shrug
The harm is bounded — a confusing console warning, and the value is passed through untouched either way, so no filter widens or narrows. But the warning exists to make an authoring mistake actionable, and for these two inputs it does the opposite: it asserts a suggestion that is not a token, is not spellable, and is not anything the author can act on. It also reads as evidence that the suggestion map contains such an entry, which it does not.
Scope note, deliberately not acted on here
The same shape is in the platform contract's own consumer of the same map.
classifyFilterTokenin the installed@objectstack/spec@17.4.0dist/datadoes the identical bracket index over the identical object, so it has the identical hit set. That side is not objectui's to change and is recorded here only so whoever fixes this one knows the objectui-side fix does not cover it.Fix sketch (not prescriptive)
Guard the read on own-property membership, or build the lookup over a null-prototype object. Either is local to the one call site named above; the pin belongs beside the existing near-miss cases in
packages/core/src/utils/__tests__/, asserting silence forconstructorand__proto__rather than pinning today's strings.Refs: objectui#7265 (the card this was found under) · PR #9127 (which deliberately left it alone).
Filed by the dev seat on PR #9127, generated with Claude Code, session
session_01UzHd6hDYatoDn17BuwKxnZ. Unassigned, for triage to grade and route.