Blocked-by: #16347
Filed by the domain:spec execution PM seat (session session_01T6HeZvT9wdSJD1ZxJb5Eno, seat post #6017). Both items are the advisory half of the at-tier contract review of PR #16347 (card #16106, verdict 5560556035) — it returned PASS on the delta and named these as non-blocking. Recorded rather than folded in, because #16347's scope was boundObjectOf plus its two pins and ⛔ widening a repair round is how a repair becomes a second review. ⛔ No severity asserted, no domain routing — that is triage's.
⚠️ Describes the tree once PR #16347 lands. The branch these are about arrived in its B1 repair commit 3b6ba7b409.
Background, in one paragraph
validate-preset-comparands gained a field-typed arm (maintainer ruling 1′, #16106 comment 5557019138): on a declared date/datetime field it refuses the 13 date-range preset names in every comparand position. Which object a filter is judged against comes from boundObjectOf, which walks outward to the nearest ancestor that declares one. The at-tier review found one blocking defect there — a form field's publicPicker.filter was being judged against the parent form's object rather than the referenced object, producing a false refusal on a legitimate publish — and the repair made publicPicker a claiming reader. These two items are what the review flagged about that repair without blocking it.
(1) The branch matches a property NAME, not a schema position
packages/lint/src/validate-preset-comparands.ts:396 reads:
if (key === PUBLIC_PICKER_KEY) { // PUBLIC_PICKER_KEY = 'publicPicker', :355
key is the property name each ancestor was reached under. ⇒ any node reached under a key literally named publicPicker, at any depth under any surface, enters the picker branch — which resolves through the enclosing form field's reference and, failing that, returns undefined (unjudged).
Today that is safe, and I measured it rather than taking the review's word (origin/main + the PR head, with lit controls — z.object( in view.zod.ts = 7, helpText: = 2):
publicPicker: as a SCHEMA KEY across packages/spec/src/** (non-test)
→ packages/spec/src/ui/view.zod.ts:2381 ← the one real declaration, on the form field
→ packages/spec/src/ui/view.zod.ts:2296 ← a doc example inside a TSDoc block
⇒ exactly one declaration, on FormFieldSchema. No schema-valid stack can reach the branch anywhere else, so there is no live defect.
⚠️ What makes it worth a card is what happens next, not what happens now. The day any other schema declares a key spelled publicPicker — a different surface, a different owner, no relationship to form fields — that key silently inherits this branch and its positions go unjudged, because the branch's third exit is undefined. The failure would be a missed catch that reports nothing, on a rule whose stated invariant is that a missed catch is its only permitted failure direction. Nothing would go red.
The review's suggested hardening, carried as-is and ⛔ not ruled on: "a comment or a chain[i-1].node.field guard would harden it" — i.e. require the parent node to look like a form field before treating the key as a picker. ⛔ Whether that is worth the coupling is the implementer's call; a comment alone may be the right size.
⭐ Related in shape, not in code: the same review's third ablation leg (P3) exists precisely because the branch's undefined exit is load-bearing — mutating those exits to continue outward reddened the QUIET pin on exactly the unresolvable pickers. So the exit is pinned; what is not pinned is which keys reach it.
(2) The lint follows a hop the route does not
For a picker whose field is a dotted path (account.owner) or which sits in a nested FormFieldSchema.fields, the two sides disagree:
|
how it resolves the field |
the lint (boundObjectOf → resolveFieldPath) |
follows the relation hop and binds the immediate field's reference |
the public-lookup route (packages/rest/src/rest-server.ts ≈10310) |
a top-level direct key lookup on the referenced object; a dotted key is not found, and the request would 403/500 |
⇒ the lint judges a position the route cannot serve at all.
⛔ Direction matters and it is the benign one: this can only ever produce a missed catch or a redundant catch, never a false refusal on a servable filter — a filter the route cannot serve is already broken for a different reason. So it is not the B1 class and does not gate anything.
⚠️ But it means a filter-preset-comparand finding on a dotted picker path tells an author their preset name is wrong, when the more useful thing to tell them is that the path itself will not resolve at the door. Whether that belongs here, in a *-filter-field-unknown rule, or nowhere is a judgement — ⛔ this card picks none.
Related, not duplicate
Provenance
At-tier review at claude-fable-5-1 (verified from its harness-stamped transcript: 188 stamps against a lit control of 140 assistant messages), card #16106 comment 5560556035, section Advisory. The measurement in item (1) above is mine, re-taken with lit controls rather than transcribed — ⛔ a first pass of it that counted files instead of schema declarations gave a different-looking number and was discarded before it reached anything.
Generated by Claude Code
Blocked-by: #16347
Filed by the
domain:specexecution PM seat (sessionsession_01T6HeZvT9wdSJD1ZxJb5Eno, seat post #6017). Both items are the advisory half of the at-tier contract review of PR #16347 (card #16106, verdict5560556035) — it returned PASS on the delta and named these as non-blocking. Recorded rather than folded in, because #16347's scope wasboundObjectOfplus its two pins and ⛔ widening a repair round is how a repair becomes a second review. ⛔ No severity asserted, no domain routing — that is triage's.3b6ba7b409.Background, in one paragraph
validate-preset-comparandsgained a field-typed arm (maintainer ruling 1′, #16106 comment5557019138): on a declareddate/datetimefield it refuses the 13 date-range preset names in every comparand position. Which object a filter is judged against comes fromboundObjectOf, which walks outward to the nearest ancestor that declares one. The at-tier review found one blocking defect there — a form field'spublicPicker.filterwas being judged against the parent form's object rather than the referenced object, producing a false refusal on a legitimate publish — and the repair madepublicPickera claiming reader. These two items are what the review flagged about that repair without blocking it.(1) The branch matches a property NAME, not a schema position
packages/lint/src/validate-preset-comparands.ts:396reads:keyis the property name each ancestor was reached under. ⇒ any node reached under a key literally namedpublicPicker, at any depth under any surface, enters the picker branch — which resolves through the enclosing form field'sreferenceand, failing that, returnsundefined(unjudged).Today that is safe, and I measured it rather than taking the review's word (
origin/main+ the PR head, with lit controls —z.object(inview.zod.ts= 7,helpText:= 2):⇒ exactly one declaration, on
FormFieldSchema. No schema-valid stack can reach the branch anywhere else, so there is no live defect.publicPicker— a different surface, a different owner, no relationship to form fields — that key silently inherits this branch and its positions go unjudged, because the branch's third exit isundefined. The failure would be a missed catch that reports nothing, on a rule whose stated invariant is that a missed catch is its only permitted failure direction. Nothing would go red.The review's suggested hardening, carried as-is and ⛔ not ruled on: "a comment or a
chain[i-1].node.fieldguard would harden it" — i.e. require the parent node to look like a form field before treating the key as a picker. ⛔ Whether that is worth the coupling is the implementer's call; a comment alone may be the right size.⭐ Related in shape, not in code: the same review's third ablation leg (P3) exists precisely because the branch's
undefinedexit is load-bearing — mutating those exits tocontinueoutward reddened the QUIET pin on exactly the unresolvable pickers. So the exit is pinned; what is not pinned is which keys reach it.(2) The lint follows a hop the route does not
For a picker whose
fieldis a dotted path (account.owner) or which sits in a nestedFormFieldSchema.fields, the two sides disagree:boundObjectOf→resolveFieldPath)referencepackages/rest/src/rest-server.ts≈10310)⇒ the lint judges a position the route cannot serve at all.
⛔ Direction matters and it is the benign one: this can only ever produce a missed catch or a redundant catch, never a false refusal on a servable filter — a filter the route cannot serve is already broken for a different reason. So it is not the B1 class and does not gate anything.
filter-preset-comparandfinding on a dotted picker path tells an author their preset name is wrong, when the more useful thing to tell them is that the path itself will not resolve at the door. Whether that belongs here, in a*-filter-field-unknownrule, or nowhere is a judgement — ⛔ this card picks none.Related, not duplicate
created_at/updated_at) — the object graph carries their names, not their types #16340 (filed by the same implementer): the lint object graph carries registry-injected columns (created_at/updated_at) by NAME only, so a field-typed rule cannot judge them. Also a missed catch, different mechanism.3b6ba7b409and is not re-opened here — it was a false refusal, these two are not.Provenance
At-tier review at
claude-fable-5-1(verified from its harness-stamped transcript: 188 stamps against a lit control of 140 assistant messages), card #16106 comment5560556035, section Advisory. The measurement in item (1) above is mine, re-taken with lit controls rather than transcribed — ⛔ a first pass of it that counted files instead of schema declarations gave a different-looking number and was discarded before it reached anything.Generated by Claude Code