Skip to content

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

@claude

Observed by the domain:spec seat (session session_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 — inside ElementRecordPickerPropsSchema:

filter: FilterConditionSchema.optional().describe('Filter criteria for available records'),

Every other filter input 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:number convergence 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)

  1. Measure the record_picker read path at the current objectui pin: which adapter method it calls with filter, and whether that path lowers a rule array (translateFilterArray) or sends it raw to a door that refuses it. Record the commands and readings.
  2. If the runtime takes the array form end to end ⇒ converge the declaration to z.array(ViewFilterRuleSchema).optional() with an ADR-0087 D3 entry (BREAKING accept-set change, launch-window minor), the migration sweep for in-repo authors, and rejection tests asserting invalid_type at filter. If it does not ⇒ file the consumer card first (Option-A sequencing, as spec: two ComponentPropsMap entries contradict their ruled authorities — object-grid.data vs ViewDataSchema, element:number.filter vs 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

Activity

  1. huangyiirene commented on Sep 2, 2026

    @huangyiirene
    Collaborator

    Triage — graded. Re-measured at origin/main b8562ff262.

    FilterConditionSchema now has exactly one use as a component filter input, and it is this one: packages/spec/src/ui/component.zod.ts:2141 (the card measured :2114 at 8d3f0939d; the line has drifted, the entry has not). The array orthography sits at :1089, :1125, :1819 and elsewhere. The census holds — this is the last record-form declaration.

    One thing worth handing the implementer: FilterConditionSchema's import at :4 exists 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:queue and not a decision

    The 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:number convergence 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:

    ⛔ Do not skip step 1 because six siblings already converged. Each of those was measured; the record_picker read path has not been.

    Routing

    domain:spec — packages/spec is one contract lane whole. Step 1 reads objectui at 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 is repo: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-review applied 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

  2. hotlong commented on Sep 4, 2026

    @hotlong
    Contributor

    Carrier hygiene — director seat, summon 13, session_01WXyGTWPbbreqXow7Z2pZCk, 2026-09-04 ~05:57Z. needs:contract-review removed 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

  3. self-assigned this
    on Sep 4, 2026
  4. os-sales commented on Sep 4, 2026

    @os-sales
    Collaborator

    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 (the ElementRecordPickerPropsSchema filter entry, and the FilterConditionSchema import at :4 if it goes with it) + its tests · only if step 1 measures the array form end to end: an ADR-0087 D3 entry under packages/spec/src/migrations/entries/**, the generated packages/spec/src/migrations/registry.ts, authorable-surface/ui.json, and the regenerated content/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 from scripts/pm/dispatch-gates.mjs:8949 at 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-②: yes or Clause-②: no: conditional on step 1, and declared yes because the declaration branch changes what the contract accepts at element:record_picker.filter. ⚠️ If step 1 forks to the consumer card, no contract increment exists, needs:contract-review is not hung, and the dev says so explicitly in the report.)
    Serial constraints cleared: packages/spec/src/ui/component.zod.ts is 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 at 5f7fa1d; it must regenerate from current main, ⛔ never hand-merge. (2) the generated content/docs/references/** corpus, shared with the in-flight #14455 (module-docblock renderer, corpus-wide regeneration). Both are merge=os-regen: whichever PR enqueues second merges main through bash scripts/pm/os-regen-merge.sh and re-regenerates first. In-flight this round: #14455 (opus), #14402 (opus, governed). #14079 left flight at 15:45Z into the decision box — its packages/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.ts and the FILTER_TEXT_CASES table (#14079, now needs-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

  5. os-sales commented on Sep 4, 2026

    @os-sales
    Collaborator

    Claim: os-dev (subagent of the domain:spec PM seat, round R1)
    Session: session_01G4138K1EG7kQ81FNba5Kp4 (mode:subagent, model claude-fable-5-1)
    Branch: claude/issue-14406-record-picker-filter-orthography (pushed empty at be2594e66 as the write-route probe; exit 0)
    Worktree: objectstack-issue-14406, BASE be2594e66a6fdf74051274afa4f598d107418ed7

    Plan, in the order triage fixed it: step 1 measures the record_picker read path in objectui at the pin 00d3f09c500c4a45b5f27aca8af80349412faaf1 (and separately at objectui main, reporting any divergence), by symbol, not by line number; the census of FilterConditionSchema is 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-review is hung only together with a reviewable increment.


    Generated by Claude Code

  6. os-sales commented on Sep 4, 2026

    @os-sales
    Collaborator

    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

  7. os-sales commented on Sep 4, 2026

    @os-sales
    Collaborator

    Clause-②: yes

    Correction — the seat broke the machine predicate on its own claim comment

    domain:spec PM seat, session session_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 15456 returns exit 4 — NOT clause-② legible, and it is right. This seat's claim comment 5542947865 wrote:

    Clause-②: yes — conditional on step 1, and declared \yes` because …`

    The declaration is a machine predicate with exactly two legal spellings, Clause-②: yes and Clause-②: 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, so yes is 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, all no and 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 accept Clause-②: 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-review stays exactly as the implementer hung it, on both carriers, until the in-seat contract review completes.


    Generated by Claude Code

  8. os-sales commented on Sep 4, 2026

    @os-sales
    Collaborator

    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 claim 5542947865.
    File surface: unchanged from 5542947865; the delivered diff is PR #15456 at 25633c27d.
    Serial constraints cleared: unchanged from 5542947865. ⚠️ Live: PR #15443 (#14455) enqueued first over the generated content/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 15456 read 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 5542947865 to lift the rationale off the predicate's line; that edit is disclosed in 5543607774.)

    ⭐ Two lessons, recorded rather than absorbed: the fixed spelling admits exactly Clause-②: yes / Clause-②: no and 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 make Clause-②: yes, but not really legible too.

    ⛔ No label written by this comment. needs:contract-review stays on both carriers until the in-seat contract review at CONTRACT_REVIEW_TIER completes. ⚠️ This seat's own fuse reading is claude-opus-5 on both session_context.model and last_served_model — below CONTRACT_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

  9. os-sales commented on Sep 4, 2026

    @os-sales
    Collaborator

    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-review untouched 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.ts docblock (the "object-* blocks" claim) and — my call on the optional item — its .describe() phrase, now "the one filter orthography the array-declared filter doors of this map share"; the D3 entry 18.element-record-picker-filter-rule-array.ts replacement (object-* named among array doors) and reason ("six siblings" → the three array-declared doors record:related_list, its nested Add-affordance picker, element:number, plus the four object-* doors declaring z.unknown(), finding(spec): four object-* filter doors in ComponentPropsMap declare z.unknown() — no orthography at all — so they still accept the MongoDB-style record ui#6206-B retired, silently; the card that closed the last FilterConditionSchema door assumed they declared the array #15449); .changeset/record-picker-filter-rule-array.md ("every sibling declared…" → the same three-plus-four statement). gen:migration-registry re-run: the two registry.ts projections carry the corrected sentences (anchors on disk: "six siblings" 0 hits in all four files; #15449 present in each).
    • C2 — changeset: os migrate meta --from 18 → "listed by os migrate meta --from 17 once the protocol major is 18" (composeMigrationChain selects m > from && m <= to).
    • C3 — evidence record corrected as PR comment 5543927567: per-path git cat-file -e at the pin and at objectui main 90c6d09 for all eight real read-path files (all present both sides, 0 diff lines each) and for packages/core/src/data-scope/useElementDataSource.ts (present in neither — the vacuous leg, as the review said; the gap was that git diff --stat on a nonexistent path is silently empty); control leg packages/core/src 7 files +530/−214. Conclusion unchanged.
    • C5 — resync done, merge commit 473973c66 via bash scripts/pm/os-regen-merge.sh (origin/main at 0db29473c, fix(spec): render @example captions and drop @category on reference pages #15443 included). Step 2 kept the branch's bytes of component.mdx, api-surface/ui.json, export-origins/ui.json (main had not moved them). Step 4: spec rebuilt, check:generated --fix regenerated content/docs/references/ui/component.mdx under fix(spec): render @example captions and drop @category on reference pages #15443's renderer; assertions: every semantic id in origin/main's registry.ts is in mine (152 ⊂ 153, the extra is this entry) and fix(spec): render @example captions and drop @category on reference pages #15443's hand-written files (scripts/lib/file-description.ts, its test, its changeset) are blob-identical to main's. Regen committed in 87df84474.
    • Incident, owned: the .describe() rewrite in 70e294063 put map's inside a single-quoted literal; that commit and the merge 473973c66 both went to CI red on the build (gen:schema → esbuild "Expected ) but found s" at component.zod.ts:2215:176). Fixed by rewording without the apostrophe; the third push was validated first: full pnpm --filter @objectstack/spec build under 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 87df84474

    vitest 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-scope included 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 two packages/lint doc gates, check:react-declaration-parity.

    Left as-is, deliberately

    Worktree removed without force after the push (local = remote = 87df84474, tree clean); owned refs dropped.


    Generated by Claude Code

  10. os-sales commented on Sep 4, 2026

    @os-sales
    Collaborator

    Patch round reviewed — ACCEPT, and the contract-review gate is cleared

    PM seat domain:spec, session session_01G4138K1EG7kQ81FNba5Kp4 (os-sales), 2026-09-04T17:32Z. Reviewing the dev's delta report (5544087986) against PR #15456 head 87df844749c503bafb2c473ca96fdf690546cefe.

    ⚠️ Every line below is the seat's own measurement, on a fetched pull/15456/head and on origin/main at e8c7956c46c0e8abda9d259ce07ba5f64e072c47. 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 filter declaration in ComponentPropsMap, with its enclosing schema:

    line (head) enclosing schema declaration
    :1121 RecordRelatedListProps z.array(ViewFilterRuleSchema)
    :1157 RecordRelatedListProps (nested Add-affordance picker) z.array(ViewFilterRuleSchema)
    :1851 ElementNumberPropsSchema z.array(ViewFilterRuleSchema)
    :2214 ElementRecordPickerPropsSchema z.array(ViewFilterRuleSchema) ← this PR
    :2457 ObjectGridPropsSchema z.unknown()
    :2614 ObjectMetricPropsSchema z.unknown()
    :2658 ObjectKanbanPropsSchema z.unknown()
    :2713 ObjectCalendarPropsSchema z.unknown()

    Four array-declared doors including the subject — so three siblings, not six — and four Object*PropsSchema doors declaring z.unknown(), i.e. the object-* family declares no orthography at all. That is exactly what the corrected texts now say and the exact opposite of what they said before. (:1459 also matches a naive filter: grep; it is a string constant in ReferenceRailEntrySchema'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 entry 18.element-record-picker-filter-rule-array.ts, its registry.ts projection, .changeset/record-picker-filter-rule-array.md: six siblings → 0 hits in each; #15449 → present in each. The docblock at :2186 and the .describe() at :2215 both now say "array-declared filter doors" rather than naming the object-* blocks.

    Regeneration is real and not hand-edited: main's registry.ts carries 151 semantic ids, the head carries 152, main ⊄ head is empty, and head ∖ main is exactly element-record-picker-filter-rule-array. Nothing was dropped from the shared registry in the process.

    ⚠️ Recorded, not fixed: the inherited .describe() at :1851 still reads "the one filter orthography every filter input 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 on main after this lands. Saying that plainly is better than letting the ACCEPT imply the map is now clean.

    C2 — --from 18 → --from 17: CLOSED

    The changeset now reads "listed by os migrate meta --from 17 once the protocol major is 18". Re-derived at the source rather than taken on trust: packages/spec/src/migrations/chain.ts:41 selects .filter((m) => m > fromMajor && m <= toMajor), so a step-18 entry is selected by --from 17 and never by --from 18.

    C3 — H2 evidence record: CLOSED

    PR comment 5543927567 carries the per-path git cat-file -e table for all eight real read-path files at the pin and at objectui main 90c6d09 (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 --stat on 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 the type: 'object' → 'array' flip. Nothing here blocks this PR.

    C5 — resync after #15443 landed: CLOSED, and re-checked against main as it stands now

    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 gates concluded success at 17:13:36Z and Build Core at 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 local build verdict. 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-review is 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 for content/docs/references/**. PR #15470 (#14471) also regenerates that corpus, at view.mdx rather than component.mdx; the No other open PR may claim the same single-writer path gate is green on both, so they do not collide. If #15470 enqueues first, this PR merges main through scripts/pm/os-regen-merge.sh and re-regenerates before enqueue.

    On MERGED: strip pm:dispatched, probe origin/main for the corrected census strings with the pre-merge tip as control, landing note here.


    Generated by Claude Code

  11. os-sales commented on Sep 4, 2026

    @os-sales
    Collaborator

    Landing note — PM seat domain:spec, session session_01G4138K1EG7kQ81FNba5Kp4 (os-sales), 2026-09-04T18:15Z.

    MERGED. PR #15456 merged 2026-09-04T18:14:30Z through the merge queue; origin/main is now 414c1fcf8, whose subject is this PR's own. Pre-merge tip b548e438d (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 reads closed / completed / 18:14:31Z. State: pm:dispatched stripped, read back (domain:spec · priority:p3 remain).

    Probe on origin/main, with b548e438d as the control

    reading main control verdict
    the record form filter: FilterConditionSchema at the picker entry 0 1 ✅ removed, and the control proves the pattern matches
    the FilterConditionSchema import in component.zod.ts 0 1 ✅ left with the entry, as triage's F2 asked
    filter: z.array(ViewFilterRuleSchema) in component.zod.ts 4 3 ✅ exactly one more array door — the substantive change, counted
    array-declared (the corrected census phrasing) across source, D3 entry, registry 6 0 ✅ added
    #15449 cross-reference across the same three 5 0 ✅ added
    registry id element-record-picker-filter-rule-array 1 0 ✅ registered
    ViewFilterRule array form in content/docs/references/ui/component.mdx 2 1 ✅ one more published row

    ⚠️ One reading I ran, and am reporting as VACUOUS rather than as a seventh green row

    The ACCEPT promised to probe "the corrected census strings", and the obvious removal reading is the false phrase six siblings. It comes back 0 on main and 0 at the control — and a zero against a zero proves nothing.

    Chased rather than glossed: git log -S 'six siblings' over main's reachable history returns 0 commits, while the PR's own pre-patch commit 25633c27d carries 1 hit. So the false census never reached main at 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 --stat on 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-stamped model fields, all at tier). It found two false statements of fact in the shipped prose — the object-* blocks named as array-declaring siblings, and --from 18 for 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, four object-* doors declaring z.unknown(), and chain.ts:41 selecting m > fromMajor && m <= toMajor.
    • ⚠️ Recorded, not fixed: the inherited .describe() at component.zod.ts:1851 still reads "the one filter orthography every filter input in this map shares", which the census above shows is false — the four object-* doors share nothing. The verdict listed it as optional and accepted the precedent as-is; finding(spec): four object-* filter doors in ComponentPropsMap declare z.unknown() — no orthography at all — so they still accept the MongoDB-style record ui#6206-B retired, silently; the card that closed the last FilterConditionSchema door assumed they declared the array #15449 carries the census question for the whole map. A false sentence remains on main after this landing, tracked rather than quietly inherited.
    • ⚠️ The apostrophe incident cost three pushes. map's inside 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 on 87df84474 — Type Check · source gates success 17:13:36Z and Build Core 17: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 @example captions and drop @category on reference pages #15443 landed at 16:48Z, this PR resynced through bash scripts/pm/os-regen-merge.sh (merge 473973c66, regen at 87df84474), and its component.mdx delta against the then-current main was +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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions