Skip to content

refactor(ui-types): one source for the filter-builder field-type list, read by the schema, the interface and the renderer; close the three K4 review should-fixes #27369

Closed

Description

@objectstack-fleet

Filing gate ③ (maintainer-directed). This is the follow-up to K4 (#27145, PR #27329, merged 2026-10-29 03:51Z) of the objectui.org docs fold. In the "Restore objectui.org docs deploy" project thread on 2026-10-29, Tesla asked 「k4 从长远考虑应该怎么处理」. The dispatching seat answered: merge K4 as it is, then file one card that gives the filter-builder field-type list a single source and also takes the K4 review's three should-fixes. Tesla confirmed with 「K4 先合并,然后再单独派卡是吗」.

维护者速读

filter-builder 能接受的 14 种字段类型,现在由三处手写列表共同决定:校验 schema、TS 接口、K4 测试里冻结的那份列表。另外,渲染器里还有一份按行为划分的分组表。objectui#6939、#7562、#8774 修的都是这几份列表对不上的问题。本卡把渲染器的分组表搬到 @object-ui/types,作为唯一来源。schema、接口和渲染器都从这里引用,测试只校验两点:每个类型都有渲染分支,除 status(spec 里没有这个类型,单独列出豁免)外,每个类型都是 spec 的 FieldType。K4 合约评审的三条建议改项也一并处理。

Wanted

  1. One source. Move the renderer's behaviour buckets out of ui/packages/components/src/custom/filter-builder.tsx: numberLikeTypes (number, currency, percent, rating), dateLikeTypes (date, datetime, time), selectLikeTypes (select, status) and lookupLikeTypes (lookup, master_detail, user). Put them in a module of @object-ui/types, which @object-ui/components already depends on. Export from there the full accepted list, which is those buckets plus text and boolean, 14 members today.
    • FilterFieldSchema.type in ui/packages/types/src/zod/complex.zod.ts builds its z.enum from that list, and its .describe() stops citing "the published doc".
    • FilterField.type in ui/packages/types/src/complex.ts is typed from the same as const list, not restated as a union.
    • filter-builder.tsx imports the buckets and declares none of its own.
  2. The pin moves. ui/packages/types/src/__tests__/filter-builder-mirror-6939.test.ts drops the frozen LAST_PUBLISHED_TYPES list, which K4 added because its doc authority had gone. In its place it asserts that:
    • every member of the list has a branch in the renderer, using the existing per-member render measurement in examples/schema-catalog/test/filter-builder-mirror-6939.test.tsx;
    • every member is a member of FieldType in packages/spec/src/data/field.zod.ts, except an explicitly named exemption list. On main c4c515ad exactly one member needs an exemption: status is not a spec FieldType. Exempt it with a one-line reason, and do not drop it, because the accepted set must not narrow.
      Rewrite the header's objectstack#27145 section to say where the authority now lives. The accepted set must not change: still 14 members, type still optional, text still the default.
  3. K4 should-fix (1). The skill pointers in skills/objectui/guides/app-composition.md:62 and skills/objectui/rules/styling.md:318 are prose URLs, and no gate checks them. Either turn them into a form that check-skills-paths.mjs or check-doc-links.mjs already judges, or add skills to a gate's scan roots. State which in the PR.
  4. K4 should-fix (2). At .github/workflows/ci.yml:454 the comment says "four roots outside ui/", but the list under it has five globs. Correct the comment.
  5. K4 should-fix (3). ui/AGENTS.md:106 still tells contributors to update content/docs/guide/*.md, which no longer exists. Point it at content/docs/frontend/.

These should-fixes are recorded in triage's PASS records on #27329 (6485237613 on 6a7c7794, 6486708135 on df07a80e).

Who acts

A domain:devx card thread. The file surface is:

  • ui/packages/types/src/**, the new module plus the zod and interface lines;
  • ui/packages/components/src/custom/filter-builder.tsx;
  • the two filter-builder-mirror-6939 tests;
  • skills/objectui/{guides/app-composition.md,rules/styling.md};
  • ui/scripts/check-doc-links.mjs or ui/scripts/check-skills-paths.mjs and their tests, only if item 3 needs them;
  • .github/workflows/ci.yml, one comment line;
  • ui/AGENTS.md;
  • a changeset.

Item 4 makes the PR Tier H by path: it stays a draft until green, the triage seat writes the contract review, and the maintainer merges.

Business reason. A metadata author who puts a filter-builder in a page relies on two things agreeing: the types that validation accepts and the types the renderer draws. Today a third hand-kept list sits between them. Three past cards (objectui#6939, #7562, #8774) each fixed a case where these lists had drifted apart, and validation either refused a column the renderer could draw or accepted a spelling it drew as plain text. A single source removes that class of bug. The three should-fixes leave a stale pointer for contributors and two links that no gate checks.

Acceptance

  • git grep -n "LAST_PUBLISHED_TYPES\|published doc's fourteen" prints nothing.
  • Adding a fifteenth member to the shared list, without a renderer branch, makes the mirror test red. Removing one member from a bucket narrows the schema, the interface and the renderer together. Record both as one-time ablations in the PR.
  • pnpm --dir ui exec vitest run packages/types examples/schema-catalog is green, and the Lint UI steps are green.
  • The four components-complex-filter-builder/* catalog entries and the nested search-interface entry still validate.

Duplicate search. I ran a semantic issue search for "filter-builder FilterField type vocabulary single source list" on objectstack-ai/objectstack. Its one hit, #24640 (closed, about filterableFields), is a different surface. New.

Size: S–M. Clause-②: no. Metadata-protocol: none.

Activity

  1. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:devx#1 · os-tesla · session_01L9qibyAYPFxpNP4BCr7Z82

    Claim: card thread "Fold objectui.org into objectstack docs", dispatch of #27369 (maintainer-directed: 「K4 先合并,然后再单独派卡是吗」, 2026-10-29 02:09Z, answering the seat's long-term proposal for the frozen filter-builder list)
    Session: session_01L9qibyAYPFxpNP4BCr7Z82 (dispatching thread) · dev: a new card thread the project coordinator opens for this card; it names its own session in its os-dev-report
    Account: os-tesla
    Branch: the dev card thread's platform-assigned claude/project-thread-* branch (mode:thread; the only branch it pushes)
    Worktree: the dev card thread's own checkout
    Domain: domain:devx
    Seat: domain:devx#1 (seat 1 by default; dispatched on the maintainer's instruction from a card thread, not from a lane seat)
    File surface: ui/packages/types/src/** (new shared module, zod/complex.zod.ts FilterFieldSchema.type, complex.ts FilterField.type, __tests__/filter-builder-mirror-6939.test.ts), ui/packages/components/src/custom/filter-builder.tsx (the four bucket declarations become imports), ui/examples/schema-catalog/test/filter-builder-mirror-6939.test.tsx, skills/objectui/guides/app-composition.md, skills/objectui/rules/styling.md, ui/scripts/{check-doc-links,check-skills-paths}.mjs and their tests (only if item 3 needs a scan-root row), .github/workflows/ci.yml (the one comment line at ~454), ui/AGENTS.md (line 106), one .changeset/*.md; ⛔ the accepted set does not change (14 members, type optional, text default; stop on breach)
    Container & model: M, mode:thread, model: opus, effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: n/a — not a defect card
    Thread-read: none
    Premise: holds (re-read on main c4c515ad: K4 #27329 merged as 7587fd4; LAST_PUBLISHED_TYPES is in ui/packages/types/src/__tests__/filter-builder-mirror-6939.test.ts; the four buckets are at filter-builder.tsx:1207–1223; FilterFieldSchema at zod/complex.zod.ts:582; status is the one member outside spec FieldType)
    Serial constraints cleared: none. Tier H by path (.github/workflows/ci.yml): draft until green, the triage seat renders the contract review, GOVERNED_APPROVERS review, the maintainer merges, and the seat never enqueues it.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:devx#1 · os-tesla · session_01L9qibxvBS38kVpxSqdV8T4

    os-dev-report

    {
     "issue": 27369,
     "status": "done",
     "branch": "claude/project-thread-jq1yxo",
     "pr": "https://github.com/objectstack-ai/objectstack/pull/27400",
     "session": "session_01L9qibxvBS38kVpxSqdV8T4",
     "premise_still_valid": true,
     "summary": "FILTER_FIELD_TYPES and its four behaviour buckets now live in @object-ui/types (filter-field-types.ts); FilterFieldSchema.type, FilterField['type'] and filter-builder.tsx all read them. The mirror test drops LAST_PUBLISHED_TYPES and pins spec FieldType membership (status exempted by name) plus, in the render half, a branch per member. K4 should-fixes: check-doc-links scans skills/objectui (new per-row diskRoot; the two prose URLs became links; heading scan now reads blockquoted headings), ci.yml comment says five paths, ui/AGENTS.md #2 points at content/docs/frontend/. Accepted set unchanged.",
     "tests": "head 796bf3a3 (parent 7dc5d3f6 differs only in styling.md): pnpm --dir ui exec vitest run packages/types examples/schema-catalog -> Test Files 429/429, Tests 12850/12850; check-doc-links.test.ts 123/123; type-check exit 0 for @object-ui/types, @object-ui/components, @object-ui/example-schema-catalog. Ablations (src-aliased, restored from HEAD, status clean): +'email' without bucket -> render half 1 red; +'zz_not_spec' -> spec check 1 red; -'rating' from number bucket -> schema pin red, FilterField TS2322, render probe red.",
     "gates": "dispatch-gates --commands: 88 derived; 87 run exit 0 (token ratchet exit 1 on 7dc5d3f6 fixed to 0 on 796bf3a3; check:skill-examples exit 0 after client-react build); check:dual-build-cjs-loads exit 3 NOT MEASURED (needs full dist; CI runs it). --ran: 88 accounted, 87 run, 1 NOT-MEASURED. Lint UI lint:root + ui package lint: 0 errors. List: /mnt/project-files/d1-merge/out/27369-gates-ran-796bf3a3.list. CI: in_progress at report time.",
     "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
     "mcp_calls": "3 — issue_read x2, subscribe_pr_activity; no MCP write",
     "api_writes": "2 — relay pr_create (repository_dispatch, run 40821293906), this os-dev-report comment",
     "open_questions": [],
     "out_of_scope_findings": []
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

domain:devxDomain lane — seat card indexed by label:pm:seatpm:dispatchedDispatched to a dev agent by /pm-dispatchtech-debt

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions