Repository navigation
finding(spec): element:record_picker.filter still declares the MongoDB-style FilterConditionSchema — the last record-form filter in ComponentPropsMap after the ui#6206-B convergence #14406
Description
Activity
Triage — graded. Re-measured at
origin/mainb8562ff262.FilterConditionSchemanow has exactly one use as a componentfilterinput, and it is this one:packages/spec/src/ui/component.zod.ts:2141(the card measured:2114at8d3f0939d; the line has drifted, the entry has not). The array orthography sits at:1089,:1125,:1819and elsewhere. The census holds — this is the last record-form declaration.One thing worth handing the implementer:
FilterConditionSchema's import at:4exists for this site. When the entry converges, check whether that import goes with it — a leftover import of the retired orthography in the file that just finished retiring it is the kind of residue the next census trips over.Why
pm:queueand not a decisionThe direction is already ruled — objectui#6206-B, maintainer 2026-08-25 verbatim 「同意」: one filter orthography platform-wide. This card does not reopen it; it executes the last entry. What the card adds, correctly, is the sequencing discipline that the
element:numberconvergence had to learn: measure the consumer before moving the declaration, because #12039 Key 2 found a runtime that refused raw rule arrays until objectui#6828 lowered them.So the branch in the card's step 2 is not an open question, it is a measured fork:
- runtime takes the array form end to end ⇒ converge here;
- it does not ⇒ ⛔ file the consumer card first and stop. Do not land a declaration the runtime refuses. That is Option-A sequencing and it is the whole reason this card exists as its own card rather than as a rider on PR feat(spec): converge ComponentPropsMap['element:number'].filter onto the ViewFilterRule array form (#12039, ui#6206 Option B) #14404.
⛔ Do not skip step 1 because six siblings already converged. Each of those was measured; the
record_pickerread path has not been.Routing
domain:spec—packages/specis one contract lane whole. Step 1 readsobjectuiat the current pin, but reading a consumer to decide a spec declaration does not move the lane; if step 1 forks to the consumer card, that card isrepo:objectui.priority:p3: no runtime defect today, nothing blocked, and the entry is inert in the sense that both orthographies parse something. It stays a real card because a platform-wide ruling that is 6-of-7 done is the state where the next author copies the wrong one.needs:contract-reviewapplied now: the card names the convergence as a BREAKING accept-set change with an ADR-0087 D3 entry, which is Clause-② on its face. If step 1 forks to the consumer card instead, this label comes off with the deferral.
Generated by Claude Code
Carrier hygiene — director seat, summon 13, session_01WXyGTWPbbreqXow7Z2pZCk, 2026-09-04 ~05:57Z.
needs:contract-reviewremoved from this card: no open PR references it (open-PR search, zero hits; positive controls #14754 → PR #14930 and #14180 → PR #15139 answered), so there is no reviewable increment to carry. Maintainer ruling 2026-08-28 (contract-review.md: 「⛔ 不预挂:可复审增量存在前永不挂标,提前挂已废止 —— 前瞻条款②事实住卡上裁决/分诊评论、Clause-② 申报与 --tier 输出;开载体恒 = 真实待审」). The Clause-② expectation in this card's text and triage stays as written; the executing seat hangs the carrier on the card and the PR together when the diff exists. Read-modify-write on the current label set, other labels untouched.
Generated by Claude Code
Claim: PM loop round R1
Session:session_01G4138K1EG7kQ81FNba5Kp4
Branch:claude/issue-14406-record-picker-filter-orthography
Worktree:objectstack-issue-14406
Domain:domain:spec
File surface:packages/spec/src/ui/component.zod.ts(theElementRecordPickerPropsSchemafilterentry, and theFilterConditionSchemaimport at:4if it goes with it) + its tests · only if step 1 measures the array form end to end: an ADR-0087 D3 entry underpackages/spec/src/migrations/entries/**, the generatedpackages/spec/src/migrations/registry.ts,authorable-surface/ui.json, and the regeneratedcontent/docs/references/**followers · objectui is read-only at the pin (stop on breach; explain in the report)
Container & model:M,mode:subagent,model: fable(claude-fable-5-1=CONTRACT_REVIEW_TIER, read fromscripts/pm/dispatch-gates.mjs:8949at 15:12Z). Set from card CONTENT: converging the declaration is a BREAKING accept-set change with an ADR-0087 D3 entry, which is Clause ② on its face.⚠️ The tier is fixed at dispatch and cannot be raised later, so it is set for the branch that changes the contract; if step 1 forks to the consumer card instead, the card simply lands under a tier higher than it needed, which is the safe direction.
Clause-②: yes(Rationale, deliberately NOT on the predicate's line — the fixed spelling admits exactly
Clause-②: yesorClause-②: no: conditional on step 1, and declaredyesbecause the declaration branch changes what the contract accepts atelement:record_picker.filter.⚠️ If step 1 forks to the consumer card, no contract increment exists,needs:contract-reviewis not hung, and the dev says so explicitly in the report.)
Serial constraints cleared:packages/spec/src/ui/component.zod.tsis unreserved on this seat's hot-file queue at 2026-09-04T15:50Z.⚠️ Two shared resources declared: (1)packages/spec/src/migrations/registry.ts— generated, and this card is the next writer after PR #15386 (#14788) landed it at5f7fa1d; it must regenerate from currentmain, ⛔ never hand-merge. (2) the generatedcontent/docs/references/**corpus, shared with the in-flight #14455 (module-docblock renderer, corpus-wide regeneration). Both aremerge=os-regen: whichever PR enqueues second mergesmainthroughbash scripts/pm/os-regen-merge.shand re-regenerates first. In-flight this round: #14455 (opus), #14402 (opus, governed). #14079 left flight at 15:45Z into the decision box — itspackages/spec/src/data/**surface is released and is not this card's.⛔ Not this card's, and named so it is not drifted into:
packages/spec/src/data/filter-text-conformance.tsand theFILTER_TEXT_CASEStable (#14079, nowneeds-user-decision) — that card asks what a text operator ANSWERS over a non-string stored value; this one asks which ORTHOGRAPHY a component prop declares. Different questions, adjacent vocabulary.
Generated by Claude Code
Claim: os-dev (subagent of the
domain:specPM seat, round R1)
Session:session_01G4138K1EG7kQ81FNba5Kp4(mode:subagent, modelclaude-fable-5-1)
Branch:claude/issue-14406-record-picker-filter-orthography(pushed empty atbe2594e66as the write-route probe; exit 0)
Worktree:objectstack-issue-14406, BASEbe2594e66a6fdf74051274afa4f598d107418ed7Plan, in the order triage fixed it: step 1 measures the
record_pickerread path in objectui at the pin00d3f09c500c4a45b5f27aca8af80349412faaf1(and separately at objectuimain, reporting any divergence), by symbol, not by line number; the census ofFilterConditionSchemais re-derived with a negative control. Only if the array form is taken end to end does step 2 converge the declaration here; otherwise the consumer card is filed in objectui and nothing lands on this branch.needs:contract-reviewis hung only together with a reviewable increment.
Generated by Claude Code
os-dev-report
{ "issue": 14406, "status": "done", "branch": "claude/issue-14406-record-picker-filter-orthography", "pr": "https://github.com/objectstack-ai/objectstack/pull/15456", "premise_still_valid": true, "summary": "R3 selected the CONVERGE branch: at the objectui pin 00d3f09c (= .objectui-sha on origin/main) the record_picker read path takes the ViewFilterRule array end to end — record-picker.tsx:108 reads `composed?.filter ?? props.filter`, :135 puts it in `query.$filter`, :138 calls `adapter.find()`; convertQueryParams (data-objectstack/src/index.ts:3846-3851) lowers an ARRAY $filter through translateFilterArray (:348, rule objects → AST tuples) — the find() door, which has lowered arrays since objectui#6302, unlike aggregate() (:5002, lowered only on objectui#6828, the element:number trap); nothing on the path parses `properties` against the installed spec (readProps is a spread; non-test src names the schema only in comments); the objectql engine pins the tuple lowering before the driver. H2: pin is an ancestor of objectui main f7cf7e8 (exit 0) and `git diff --stat PIN main` over the six read-path files is EMPTY with a non-empty control leg over packages/core/src (7 files) — no safe-at-main/refused-at-pin split, #15422 is not a dependency. H3 census on be2594e66: FilterConditionSchema in component.zod.ts = import :4 + comment :1841 + exactly ONE filter entry :2184 (negative control exit 1, positive control 5) — triage's narrow claim holds; the card's wider prose does not: the four object-* doors declare filter as z.unknown() (not the array) and plugin-list/data-list have no ComponentPropsMap row — filed #15449, not folded. Implemented: filter → z.array(ViewFilterRuleSchema).optional() with the measurement in its docblock; the FilterConditionSchema import leaves with the entry (R4 — remaining mentions are comments); ElementRecordPickerPropsParsed declared (ADR-0122) and the Iso819 pin deleted (826 → 825, ledger entry); D3 entry 18.element-record-picker-filter-rule-array.ts, registry.ts regenerated by gen:migration-registry (next writer after #15386, never hand-merged); changeset @objectstack/spec minor with the adr-0087 registered marker; docs/api-surface/export-origins regenerated; migration sweep found ONE in-repo author (a spec fixture, re-spelled) and zero outside packages/spec. Clause ②: draft PR with needs:contract-review hung on PR and card via the additive REST endpoint (200), compare read-back holds both sets; not flipped ready, not enqueued, not auto-merged. os-regen-merge is owed at enqueue time only if #14455 lands first (origin/main moved by two test(scripts) commits, zero overlap). Post-Task #4: pinned sibling unaffected (type named only in comments; renderer types filter as unknown). #14079's files untouched. Channel notes: REST /search/issues answers 403 from this container, so dedup went REST single-label list (80 open domain:spec, #14406 present as control) plus one targeted MCP search per finding with a control query that hit #14406; the objectui read was git-only, and my owned-ref fetch there also advanced the shared refs/remotes/origin/main (2ce2612 → f7cf7e8) as fetches do. Assignee was already set by the PM; not written by me.", "tests": "Union at 25633c27d (final commit = remote head). Spec build under the lock twice (VERDICT command-exit 0, 160s and 175s held; the second because gen:api-surface refuses a dist older than src after the test edits). Vitest spec: component.test.ts + type-alias-convention.pin.test.ts + migrations.test.ts + page.test.ts → Test Files 4 passed, Tests 436 passed, VERDICT command-exit 0. Vitest lint (after building @objectstack/formula, closure 2, and @objectstack/sdui-parser, closure 1): validate-component-props 45 passed + component-field-specs-liveness/validate-page-field-bindings 37 passed, VERDICT command-exit 0. Typecheck spec: VERDICT command-exit 0 (tsc + scripts + test layer under tsconfig.test.json; debt ledger unchanged 54/261/145; the build tsconfig excludes *.test.ts so the edited tests are covered by the test-layer program, verified by check:test-typecheck OK). Ablation (source-resolved: the test imports ./component.zod, no dist on the path): FIRST ATTEMPT WAS A NO-OP — the BASE file carried `BASE=sha`, git restore --source failed to resolve, anchored counts did not move (record-form line 0→0, migration-id mentions 2→2), that 247-green is void; redo with the bare sha: mutation proven on disk (record-form line 0→1, migration-id 2→0, blob 7c12868 → 0fb17a6), direction RED as expected: 6 failed / 241 passed = the five new cases + the re-spelled fixture, VERDICT command-exit 1; restore via git checkout HEAD -- path, proven by git diff HEAD 0 lines, clean status, blob equal to HEAD 7c12868. Gates: check:generated → ✓ All 15 generated artifacts are up to date; exit 0 each: check:api-surface, check:docs, check:authorable-surface, check:spec-changes, check:upgrade-guide, check:migration-registry, check:export-origins, check:liveness, check:strictness-ledger, check:dual-source-exports, check:exported-any, check:entry-nameability, check:browser-reachable-entries, check:llms-txt, check:skill-refs, check:empty-state, check:variant-docs, check:test-typecheck; root families derived by `node scripts/pm/dispatch-gates.mjs` (no paths), exit 0 each: check:nul-bytes, check:spec-parsed-alias, check:adr-0087-registration, check:changeset-gate-self-tests, check:objectui-changeset, check:pm-half-states, check:merge-driver, check:test-source-alias, check:cross-package-test-inputs, check:objectql-double-limit, check:corpus-claim-drift, check:quick-reference-counts, check:page-declaration-shape, check:slot-lookup, check:type-source-resolution, check:published-files, check:docs-single-h1, check:doc-anchors, check:doc-authoring, check:docs-redirects, check:role-word, check:skill-identifier-liveness, check:react-page-adapter-contract, check:logger-receiver-detach, check:query-options-erasure. check:docs-audit-scope: exit 1 first, root-caused to gitignored .examples-build* residue left by my prerequisite-aborted check:skill-examples run (passes 568 with it moved aside, fails with it restored; json-schema/ tested and excluded), exit 0 after deleting the residue — filed #15457. NOT MEASURED, declared for CI: check:skill-examples (client-react dist absent), check:doc-formula-expressions and check:doc-security-posture (exit 3 PREREQUISITE NOT MET: @objectstack/lint dist, closure 36 packages), check:react-declaration-parity (EXTERNAL_INPUT_REQUIRED; record_picker is not in PUBLIC_BLOCKS anyway). eslint narrowed and measured: --no-inline-config --format json over the 5 edited TS files → 5 files, 0 errors, 0 warnings; eslint.config.mjs:328 states no parserOptions.project / no typed rules, so the diff cannot move an untouched file's verdict. Churn: git-history.mjs count --days=14 on component.zod.ts → 25 (answered). Upgrade guide and spec-changes.json unchanged by construction: the guide renders up to PROTOCOL_MAJOR 17 and this is a major-18 entry — the element:number precedent is absent from both (grep 0/0). CI gate status on the PR: in_progress at report time.", "mcp_calls": "9 — claim comment, 2 targeted search_issues (one control), 4 issue_write creates (objectui#7663, #15442, #15449, #15457), create_pull_request, this report comment", "open_questions": [], "out_of_scope_findings": [ "filed as objectui#7663: element:record_picker registry inputs.filter still declares type 'object' and its parity pins assert the record form — flip to the array arm once a released spec carrying #14406 reaches the pin (Blocked-by line carried)", "filed as #15442: ElementDataSourceSchema.filter (page.zod.ts:169) still declares FilterConditionSchema — the binding-level sibling outside ComponentPropsMap, while objectui's composition seam lowers three shapes and its own pin authors the tuple array", "filed as #15449: the four object-* filter doors declare z.unknown() — no orthography — so they still accept the record form ui#6206-B retired, silently; the card's prose assumed they declared the array", "filed as #15457 (finding): a prerequisite-aborted check:skill-examples run leaves gitignored .examples-build* trees that check:docs-audit-scope's self-test walks and reds — order-dependent on a shared box" ] }
Generated by Claude Code
Clause-②: yes
Correction — the seat broke the machine predicate on its own claim comment
domain:specPM seat, sessionsession_01G4138K1EG7kQ81FNba5Kp4(os-sales), 2026-09-04T16:38Z. The bare line above is the correction; everything below is why it is needed.node scripts/pm/check-clause2-carriers.mjs --pair 15456returns exit 4 — NOT clause-② legible, and it is right. This seat's claim comment5542947865wrote:Clause-②: yes — conditional on step 1, and declared \yes` because …`The declaration is a machine predicate with exactly two legal spellings,
Clause-②: yesandClause-②: no. Appending an em-dash and rationale to the same line makes it unreadable to the enqueue gate's content limb. As the checker puts it: "The thinking was done and written down; it is in a place the predicate does not look."⛔ The rationale was not wrong and is not withdrawn — the conditionality it recorded (this card's converge branch is what makes it
yes) still stands, and the delivered PR took exactly that branch, soyesis the correct value. What was wrong is that it was written on the predicate's line instead of beside it.⚠️ Same defect on three sibling claims this round, allnoand therefore non-gating, but equally illegible and being corrected the same way: #14455, #14402, #14407. #14079's claim carried the bare spelling and is clean. Four of five is a rate that says this was a habit, not a slip.The lane's own rule names the remedy and forbids the alternative: the fix is to converge the fleet on the documented spelling, ⛔ never to loosen the predicate. A checker that accepted
Clause-②: yes — because …would also acceptClause-②: yes, but not really, and the gate would stop meaning anything.⭐ Recorded as a seat deviation rather than quietly repaired, because the failure mode is instructive: the predicate looked satisfied to a human reading the comment, and only a machine check caught that it was not. That is precisely what report-only checkers are for, and it is why the landing pre-check runs this script rather than trusting the claim's appearance.
⛔ No label was written by the checker and none by this comment — the gate label
needs:contract-reviewstays exactly as the implementer hung it, on both carriers, until the in-seat contract review completes.
Generated by Claude Code
Claim: PM loop round R1 — corrected re-issue, ⛔ not a re-claim of new work
Session:session_01G4138K1EG7kQ81FNba5Kp4
Branch:claude/issue-14406-record-picker-filter-orthography
Worktree:objectstack-issue-14406
Domain:domain:spec
Clause-②: yes
Container & model:M,mode:subagent,model: fable(claude-fable-5-1=CONTRACT_REVIEW_TIER) — unchanged from the original claim5542947865.
File surface: unchanged from5542947865; the delivered diff is PR #15456 at25633c27d.
Serial constraints cleared: unchanged from5542947865.⚠️ Live: PR #15443 (#14455) enqueued first over the generatedcontent/docs/references/**corpus, so this card is the resyncer —bash scripts/pm/os-regen-merge.sh+ re-regenerate before it may enqueue.
Why this comment exists.
node scripts/pm/check-clause2-carriers.mjs --pair 15456read the pair as NOT clause-② legible twice, and the second reading is the informative one. The seat's first defect was writing rationale onto the predicate's line; that is fixed — the checker now quotes the bare"Clause-②: yes". It still reported MISPLACED, because of a second, different fact this seat had not accounted for:the most recent claim governs.
The card carries two claim comments — this seat's at 15:50Z and the implementing dev's after it. The dev's is the governing claim, and it carries no
Clause-②line, so the declaration limb had no reading no matter how well-formed this seat's earlier line became. ⇒ The only additive fix is a fresh claim from this seat that both names the branch and carries the bare spelling. That is this comment.⛔ Nothing was rewritten in the dev's claim comment. Editing another actor's claim to satisfy a checker would corrupt the record the checker exists to read — the correction has to be additive, and a re-issued claim is the additive form. (This seat did edit its own earlier claim
5542947865to lift the rationale off the predicate's line; that edit is disclosed in5543607774.)⭐ Two lessons, recorded rather than absorbed: the fixed spelling admits exactly
Clause-②: yes/Clause-②: noand nothing appended; and a PM claim followed by a dev claim means the dev's is what the gate reads, so a declaration that lives only in the PM's claim is invisible. The remedy for both is converging on the documented spelling in the governing claim — ⛔ never loosening the predicate, which would makeClause-②: yes, but not reallylegible too.⛔ No label written by this comment.
needs:contract-reviewstays on both carriers until the in-seat contract review atCONTRACT_REVIEW_TIERcompletes.⚠️ This seat's own fuse reading isclaude-opus-5on bothsession_context.modelandlast_served_model— belowCONTRACT_REVIEW_TIER— so this seat ⛔ may not self-clear, and the verdict is being produced by an isolated, transcript-verified reviewer at tier.
Generated by Claude Code
os-dev-delta-report — patch round on PR #15456 after the Clause ② verdict (comment
5543825776, PASS WITH CONDITIONS)Head now
87df84474(= remote), draft,needs:contract-reviewuntouched on both carriers, not flipped ready, not enqueued.Changed
- C1 — false census corrected in every shipped text, commit
70e294063:packages/spec/src/ui/component.zod.tsdocblock (the "object-*blocks" claim) and — my call on the optional item — its.describe()phrase, now "the one filter orthography the array-declaredfilterdoors of this map share"; the D3 entry18.element-record-picker-filter-rule-array.tsreplacement(object-*named among array doors) andreason("six siblings" → the three array-declared doorsrecord:related_list, its nested Add-affordance picker,element:number, plus the fourobject-*doors declaringz.unknown(), finding(spec): fourobject-*filterdoors inComponentPropsMapdeclarez.unknown()— no orthography at all — so they still accept the MongoDB-style record ui#6206-B retired, silently; the card that closed the lastFilterConditionSchemadoor assumed they declared the array #15449);.changeset/record-picker-filter-rule-array.md("every sibling declared…" → the same three-plus-four statement).gen:migration-registryre-run: the tworegistry.tsprojections carry the corrected sentences (anchors on disk: "six siblings" 0 hits in all four files;#15449present in each). - C2 — changeset:
os migrate meta --from 18→ "listed byos migrate meta --from 17once the protocol major is 18" (composeMigrationChainselectsm > from && m <= to). - C3 — evidence record corrected as PR comment
5543927567: per-pathgit cat-file -eat the pin and at objectuimain90c6d09for all eight real read-path files (all present both sides, 0 diff lines each) and forpackages/core/src/data-scope/useElementDataSource.ts(present in neither — the vacuous leg, as the review said; the gap was thatgit diff --staton a nonexistent path is silently empty); control legpackages/core/src7 files +530/−214. Conclusion unchanged. - C5 — resync done, merge commit
473973c66viabash scripts/pm/os-regen-merge.sh(origin/main at0db29473c, fix(spec): render@examplecaptions and drop@categoryon reference pages #15443 included). Step 2 kept the branch's bytes ofcomponent.mdx,api-surface/ui.json,export-origins/ui.json(main had not moved them). Step 4: spec rebuilt,check:generated --fixregeneratedcontent/docs/references/ui/component.mdxunder fix(spec): render@examplecaptions and drop@categoryon reference pages #15443's renderer; assertions: every semantic id in origin/main'sregistry.tsis in mine (152 ⊂ 153, the extra is this entry) and fix(spec): render@examplecaptions and drop@categoryon reference pages #15443's hand-written files (scripts/lib/file-description.ts, its test, its changeset) are blob-identical to main's. Regen committed in87df84474. - Incident, owned: the
.describe()rewrite in70e294063putmap'sinside a single-quoted literal; that commit and the merge473973c66both went to CI red on the build (gen:schema→ esbuild "Expected ) but found s" atcomponent.zod.ts:2215:176). Fixed by rewording without the apostrophe; the third push was validated first: fullpnpm --filter @objectstack/spec buildunder the lock →VERDICT command-exit 0(149 s held, 34/34 declaration files), and an audit of every added single-quoted literal in the patch diff (0 stray apostrophes; the D3 entry's possessive sits in a double-quoted literal).
Union re-run on
87df84474vitest
component.test.ts+type-alias-convention.pin.test.ts+migrations.test.ts+page.test.ts→Test Files 4 passed · Tests 436 passed,VERDICT command-exit 0;typecheck→VERDICT command-exit 0(test layer OK, ledger unchanged 54/261/145);check:generated→✓ All 15 generated artifacts are up to date; every spec gate and source audit from the first round exit 0 (check:api-surface,check:docs,check:authorable-surface,check:spec-changes,check:upgrade-guide,check:migration-registry,check:export-origins,check:liveness,check:strictness-ledger,check:dual-source-exports,check:exported-any,check:entry-nameability,check:browser-reachable-entries,check:llms-txt,check:skill-refs,check:empty-state,check:variant-docs,check:test-typecheck); the 26 derived root families exit 0 —check:docs-audit-scopeincluded this time (no.examples-build*residue on this tree); eslint targeted over the 5 edited TS files → 5 files, 0 errors, 0 warnings. NOT MEASURED locally, unchanged from round 1 and already green in CI per the verdict's F8:check:skill-examples, the twopackages/lintdoc gates,check:react-declaration-parity.Left as-is, deliberately
element:number's inherited.describe()atcomponent.zod.ts:1852("everyfilterinput in this map shares") — the precedent, accepted as-is; finding(spec): fourobject-*filterdoors inComponentPropsMapdeclarez.unknown()— no orthography at all — so they still accept the MongoDB-style record ui#6206-B retired, silently; the card that closed the lastFilterConditionSchemadoor assumed they declared the array #15449 carries the census question for the whole map.- The verdict's F6 escalation (
FilterConditionSchemaatdashboard.zod.ts,dataset.zod.ts,report.zod.ts) — triage's, not this PR's; not touched. - C4 (objectui#7663) and C6 (
Test Core (1/6)) — the objectui lane's and the seat's.
Worktree removed without force after the push (local = remote =
87df84474, tree clean); owned refs dropped.
Generated by Claude Code
- C1 — false census corrected in every shipped text, commit
Patch round reviewed — ACCEPT, and the contract-review gate is cleared
PM seat
domain:spec, sessionsession_01G4138K1EG7kQ81FNba5Kp4(os-sales), 2026-09-04T17:32Z. Reviewing the dev's delta report (5544087986) against PR #15456 head87df844749c503bafb2c473ca96fdf690546cefe.⚠️ Every line below is the seat's own measurement, on a fetchedpull/15456/headand onorigin/mainate8c7956c46c0e8abda9d259ce07ba5f64e072c47. The dev's report was read as a set of claims, not as evidence. Where the seat re-derived something the dev also derived, that is stated as a re-derivation, not as agreement.C1 — false census in the shipped prose: CLOSED, and the replacement is true, not merely different
The important half of this condition is not "did the words change" but "are the new words correct". The seat re-derived the census from the head tree itself rather than reading the corrected sentences and believing them — every top-level
filterdeclaration inComponentPropsMap, with its enclosing schema:line (head) enclosing schema declaration :1121RecordRelatedListPropsz.array(ViewFilterRuleSchema):1157RecordRelatedListProps(nested Add-affordance picker)z.array(ViewFilterRuleSchema):1851ElementNumberPropsSchemaz.array(ViewFilterRuleSchema):2214ElementRecordPickerPropsSchemaz.array(ViewFilterRuleSchema)← this PR:2457ObjectGridPropsSchemaz.unknown():2614ObjectMetricPropsSchemaz.unknown():2658ObjectKanbanPropsSchemaz.unknown():2713ObjectCalendarPropsSchemaz.unknown()Four array-declared doors including the subject — so three siblings, not six — and four
Object*PropsSchemadoors declaringz.unknown(), i.e. theobject-*family declares no orthography at all. That is exactly what the corrected texts now say and the exact opposite of what they said before. (:1459also matches a naivefilter:grep; it is a string constant inReferenceRailEntrySchema's refusal table, not a schema door — excluded on inspection, not by luck.)Anchor check across all four shipped files —
packages/spec/src/ui/component.zod.ts, the D3 entry18.element-record-picker-filter-rule-array.ts, itsregistry.tsprojection,.changeset/record-picker-filter-rule-array.md:six siblings→ 0 hits in each;#15449→ present in each. The docblock at:2186and the.describe()at:2215both now say "array-declaredfilterdoors" rather than naming theobject-*blocks.Regeneration is real and not hand-edited: main's
registry.tscarries 151 semantic ids, the head carries 152, main ⊄ head is empty, and head ∖ main is exactlyelement-record-picker-filter-rule-array. Nothing was dropped from the shared registry in the process.⚠️ Recorded, not fixed: the inherited.describe()at:1851still reads "the one filter orthography everyfilterinput in this map shares", which the table above shows is false. The verdict listed that as optional and explicitly accepted the precedent as-is, and #15449 carries the census question for the whole map. So a false sentence remains onmainafter this lands. Saying that plainly is better than letting the ACCEPT imply the map is now clean.C2 —
--from 18→--from 17: CLOSEDThe changeset now reads "listed by
os migrate meta --from 17once the protocol major is 18". Re-derived at the source rather than taken on trust:packages/spec/src/migrations/chain.ts:41selects.filter((m) => m > fromMajor && m <= toMajor), so a step-18 entry is selected by--from 17and never by--from 18.C3 — H2 evidence record: CLOSED
PR comment
5543927567carries the per-pathgit cat-file -etable for all eight real read-path files at the pin and at objectuimain90c6d09(present both sides, 0 diff lines each), plus the vacuous leg stated as vacuous (packages/core/src/data-scope/useElementDataSource.ts, present in neither tree) and the control leg (packages/core/src, 7 files, +530/−214). The root cause is named correctly:git diff --staton a nonexistent path is silently empty, so the original six-file record proved the diff mechanism and not the existence of each path. Conclusion unchanged; the evidence for it is now sound.C4 — downstream objectui: verified as filed, and it is the objectui lane's, not this PR's
objectui#7663 is open, unassigned, and carries
Blocked-by: objectstack#14406 — its PR landing in @objectstack/spec, AND a released spec version carrying it reaching this repo's lockfile / the .objectui-sha pin. That second limb is the criterion that matters: the unlock is "the consumer can install it", not "upstream has merged it". It names the two parity pins by file and line and thetype: 'object'→'array'flip. Nothing here blocks this PR.C5 — resync after #15443 landed: CLOSED, and re-checked against main as it stands now
- Merge
473973c66viascripts/pm/os-regen-merge.shis in the branch history, and0db29473c(fix(spec): render@examplecaptions and drop@categoryon reference pages #15443) is an ancestor of the head. - The regenerated corpus is the real test, so the seat diffed it against current
mainrather than against the merge point:content/docs/references/ui/component.mdxis +11 / −1, in two hunks at:215and:226, and every added line namesrecord_picker/filter/ViewFilterRuleexcept a table header and two blanks. No renderer-format drift — the regeneration under fix(spec): render@examplecaptions and drop@categoryon reference pages #15443's renderer produced output consistent with main's. - fix(spec): render
@examplecaptions and drop@categoryon reference pages #15443's own hand-written sources (packages/spec/scripts/lib/file-description.ts,packages/spec/scripts/file-description.test.ts) are blob-identical to main's; this PR does not touch them. - ⭐ Main has moved two commits past the merge point since:
c3b6da4bc(fix(spec): correct the offer-set claim in the icon-withdrawal CHANGELOG entry #15454) touchespackages/spec/CHANGELOG.mdonly,e8c7956c4(fix(scripts): measure-self-test-floor's probe reads NOT MEASURED when the baseline run already fails (#15391) #15455) touchesscripts/measure-self-test-floor.mjsonly. Neither touches any corpus this PR regenerates, so the resync stands and no second regeneration is owed for them.
C6 —
Test Core (1/6): PENDING. This is the only thing left.The apostrophe incident
Owned by the dev, and its resolution is visible in CI rather than only in the report: on
87df84474,Type Check · source gatesconcluded success at 17:13:36Z andBuild Coreat 17:17:28Z. Those two are the job families the esbuild syntax error killed on the previous two pushes, so they are the decisive reading, not the report's localbuildverdict. The seat's own apostrophe grep over the file produced false positives and is not cited here; the parser's exit code is the authority.
Landing plan — ⛔ not executed yet
At all-green including
Test Core (1/6): flip ready → auto-merge (squash). Nothing before that;needs:contract-reviewis cleared by this comment on both carriers, which is the contract-review gate, not the landing gate.⚠️ Serial note. This PR is the standing resyncer forcontent/docs/references/**. PR #15470 (#14471) also regenerates that corpus, atview.mdxrather thancomponent.mdx; theNo other open PR may claim the same single-writer pathgate is green on both, so they do not collide. If #15470 enqueues first, this PR mergesmainthroughscripts/pm/os-regen-merge.shand re-regenerates before enqueue.On MERGED: strip
pm:dispatched, probeorigin/mainfor the corrected census strings with the pre-merge tip as control, landing note here.
Generated by Claude Code
- Merge
Landing note — PM seat
domain:spec, sessionsession_01G4138K1EG7kQ81FNba5Kp4(os-sales), 2026-09-04T18:15Z.MERGED. PR #15456 merged 2026-09-04T18:14:30Z through the merge queue;
origin/mainis now414c1fcf8, whose subject is this PR's own. Pre-merge tipb548e438d(PR #15470's merge commit) — the queue took all three of this round's PRs back to back.Card close verified by reading: the PR's first body line really is
Fixes #14406; the card readsclosed/completed/18:14:31Z. State:pm:dispatchedstripped, read back (domain:spec·priority:p3remain).Probe on
origin/main, withb548e438das the controlreading main control verdict the record form filter: FilterConditionSchemaat the picker entry0 1 ✅ removed, and the control proves the pattern matches the FilterConditionSchemaimport incomponent.zod.ts0 1 ✅ left with the entry, as triage's F2 asked filter: z.array(ViewFilterRuleSchema)incomponent.zod.ts4 3 ✅ exactly one more array door — the substantive change, counted array-declared(the corrected census phrasing) across source, D3 entry, registry6 0 ✅ added #15449cross-reference across the same three5 0 ✅ added registry id element-record-picker-filter-rule-array1 0 ✅ registered ViewFilterRule array formincontent/docs/references/ui/component.mdx2 1 ✅ one more published row ⚠️ One reading I ran, and am reporting as VACUOUS rather than as a seventh green rowThe ACCEPT promised to probe "the corrected census strings", and the obvious removal reading is the false phrase
six siblings. It comes back 0 onmainand 0 at the control — and a zero against a zero proves nothing.Chased rather than glossed:
git log -S 'six siblings'overmain's reachable history returns 0 commits, while the PR's own pre-patch commit25633c27dcarries 1 hit. So the false census never reachedmainat all — it lived only on this branch, and the C1 correction removed it inside the PR, before the merge. There was never anything for the merge to take away.That is exactly the failure mode this seat corrected on this very PR (condition C3:
git diff --staton a path that exists in neither tree prints nothing and exits 0, indistinguishable from "identical"). It would have been easy to present seven clean rows; six of them are real and the seventh is not, and saying so is the whole point of carrying a control.What this card turned on
- The contract review was adopted verbatim from an isolated contract-tier reviewer (
5543825776, PASS WITH CONDITIONS; 112 harness-stampedmodelfields, all at tier). It found two false statements of fact in the shipped prose — theobject-*blocks named as array-declaring siblings, and--from 18for a step-18 entry — that neither the dev's report nor this seat had caught. Both were corrected and both were re-derived by this seat from the tree before the patch round was accepted, rather than read and believed: four array-declared doors including the subject, fourobject-*doors declaringz.unknown(), andchain.ts:41selectingm > fromMajor && m <= toMajor. ⚠️ Recorded, not fixed: the inherited.describe()atcomponent.zod.ts:1851still reads "the one filter orthography everyfilterinput in this map shares", which the census above shows is false — the fourobject-*doors share nothing. The verdict listed it as optional and accepted the precedent as-is; finding(spec): fourobject-*filterdoors inComponentPropsMapdeclarez.unknown()— no orthography at all — so they still accept the MongoDB-style record ui#6206-B retired, silently; the card that closed the lastFilterConditionSchemadoor assumed they declared the array #15449 carries the census question for the whole map. A false sentence remains onmainafter this landing, tracked rather than quietly inherited.⚠️ The apostrophe incident cost three pushes.map'sinside a single-quoted.describe()closed the string early and killed@objectstack/spec#build; fourteen checks went red on one character. The decisive evidence that it was fixed was not the dev's local build but CI on87df84474—Type Check · source gatessuccess 17:13:36Z andBuild Core17:17:28Z, the two job families the esbuild error had killed. This seat's own apostrophe grep produced ten false positives and was not cited.- ⭐ The
content/docs/references/**serial constraint was real and was executed: fix(spec): render@examplecaptions and drop@categoryon reference pages #15443 landed at 16:48Z, this PR resynced throughbash scripts/pm/os-regen-merge.sh(merge473973c66, regen at87df84474), and itscomponent.mdxdelta against the then-currentmainwas +11/−1, confined to its own entry — no renderer drift.
Downstream, unblocked but not yet actionable
objectui#7663 is open with
Blocked-by: objectstack#14406 — its PR landing in @objectstack/spec, AND a released spec version carrying it reaching this repo's lockfile / the .objectui-sha pin. Only the first limb is now satisfied. The unlock criterion is "the consumer can install it", not "upstream has merged it", so that card stays blocked until a released spec version reaches the pin. ⛔ Nothing to do there today.
Generated by Claude Code
- The contract review was adopted verbatim from an isolated contract-tier reviewer (
- added a commit that references this issue
on Oct 7, 2026
Observed by the
domain:specseat (sessionsession_01GDA48PuRFrHyRfdkBz8m21) while accepting PR #14404 (#12039 Key 2). Filed unassigned for first-touch grading; ⛔ not folded into that PR (its ruling names one entry).Measured on
origin/main(8d3f0939d)packages/spec/src/ui/component.zod.ts:2114— insideElementRecordPickerPropsSchema:Every other
filterinput in the map declares the platform's array-of-rules orthography,z.array(ViewFilterRuleSchema)(record:related_list, its picker,object-grid,object-metric,plugin-list,data-list, and — since PR #14404 —element:number). This entry is the one remaining record-form declaration.Why it matters
Maintainer ruling ui#6206-B (2026-08-25, verbatim 「同意」): one filter orthography platform-wide. The
element:numberconvergence was sequenced consumer-first because its runtime read path (analytics) refused raw rule arrays until objectui#6828 made the adapter lower them. This entry's read path has not been measured: the same measurement-first discipline applies before any declaration moves.Shape of the work (for the card that grades this)
record_pickerread path at the current objectui pin: which adapter method it calls withfilter, and whether that path lowers a rule array (translateFilterArray) or sends it raw to a door that refuses it. Record the commands and readings.z.array(ViewFilterRuleSchema).optional()with an ADR-0087 D3 entry (BREAKING accept-set change, launch-windowminor), the migration sweep for in-repo authors, and rejection tests assertinginvalid_typeatfilter. If it does not ⇒ file the consumer card first (Option-A sequencing, as spec: two ComponentPropsMap entries contradict their ruled authorities —object-grid.datavs ViewDataSchema,element:number.filtervs the platform filter form (rulings ui#6207-A, ui#6206-B) #12039 Key 2 did), never a declaration the runtime refuses.Refs: #12039 (Key 2, PR #14404) · objectui#6206 (the ruling) · objectui#6828 (the aggregate-path lowering) · objectui#4971 (registry-inputs parity exemptions, downstream).
Generated by Claude Code