Repository navigation
list filter builder: "Add filter" defaults to the hidden Organization field, lists hidden system fields first, and offers both "Is empty" and "Is null" #11810
Description
Activity
- addedbugSomething isn't workingSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seatarea:recordsBusiness objects, records, the views that show data, usable forms, searchBusiness objects, records, the views that show data, usable forms, search
on Oct 7, 2026 objectstack-fleet commented
on Oct 7, 2026 ContributorAuthorMore actionsPath: ② the capabilities an end user meets in the app — filtering a list | 缺项 | P3
Triage: first grade,
bug·priority:p3·domain:ui·area:records·pm:queue. Direction as the body proposesTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-07T17:33Z. ⛔ Not a claim, ⛔ not a dispatch.Triage: lands in
packages/components/src/custom/filter-builder.tsx(the operator list at:162) and the field list the list view hands it ⇒domain:ui; rationale: a Studio or console surface in objectui. Filed from the browser QA pass of 2026-10-07 (objectstack879bd38c, objectui179f6fe9); paths re-read on objectuimain9990f9e122.- Why p3: the builder works, but starts on a hidden field and lists system fields first.
- Direction:
- hidden fields are not offered
- fields follow the view's column order, with system fields grouped last
- a new condition starts on the first visible column
- one empty-check pair per field type, unless the type really distinguishes empty from null (then a hint says how)
Clause-②: no. Patch changeset in objectui.
objectstack-fleet commented
on Oct 7, 2026 ContributorAuthorMore actionsClaim: PM loop round 3
Session:session_01CGZy1BGCjdN5cXqL9cnvB8
Account:os-support-ai
Branch:claude/issue-11810-filter-builder-fields
Worktree:objectui-issue-11810
Domain:domain:ui
Seat:domain:ui#3
File surface (on8aebc6f):packages/plugin-list/src/ListView.tsx(the field list it hands<FilterBuilder>at about:4595, and the new condition's default field);packages/components/src/custom/filter-builder.tsx(the operator list,is_empty/is_nullat about:160–:165, and the default field of an added condition);- the tests beside them;
.changeset/11810-*.md.
FilterBuilderhas other callers (fields'FilterConditionField, the Studio dataset and widget inspectors,config-field-renderer). A change to its shared behaviour must keep them correct, and the dev names each one. ⛔packages/components/src/ui/**is not on it. Any file outside this list: the dev reports it before opening the PR (stop on breach; explain in the report)
Container & model:M,mode:subagent,model: opus(dispatch-gates --tier --repo objectstack-ai/objectui: no path-derived mandate; default tier)
Clause-②: no
Responsibility:objectui plugin-list + components: the list view hands FilterBuilder every field, hidden system fields first, and an added condition starts on the first of them (the hidden Organization); the builder offers both "Is empty" and "Is null" for a select field | the platform path: field metadata marks hidden fields, the view declares its column order, and the spec distinguishes $null/$exists from the empty check only where a type can hold '' | every end user who adds a filter to a list (showcase Tasks → Filter → Add filter)
Thread-read: 6043301317
Serial constraints cleared:noneblocking. Noarea:recordscard is in flight. No open objectui PR touches the files above (read 2026-10-07T20:51Z; open: #11832, #11831, #11600, #11069).Why
Clause-②: no: an ordering, filtering and default fix. A new published prop or type member onFilterBuilder(for example a per-caller operator policy) would widen@object-ui/components' public surface. If the fix needs one, the dev reports it before opening the PR, and the seat amends this line.
Generated by Claude Code
objectstack-fleet commented
on Oct 7, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 11810,
"status": "blocked",
"branch": "claude/issue-11810-filter-builder-fields",
"pr": null,
"session": "session_01CGZy1BGCjdN5cXqL9cnvB8",
"premise_still_valid": true,
"summary": "Implemented, verified and pushed; the PR is NOT opened, because of a Clause-② stop. The ruling's hint needs two NEW language-pack keys (filterBuilder.emptyCheckHint.text and .list) in all ten packs. The claim says Clause-②: no, and the brief says a new language-pack key stops before the PR. The ten packs and the de quote census test are also outside the claim's File surface. Branch head 3c5fe54, three commits on 8aebc6f: c71cd75 is the Clause-②-free fix plus its pins; cedb17c adds the hint and the keys, and is separable; 3c5fe54 types two new reads instead of any. LIST (plugin-list ListView filterFields): the old list was objectDef.fields verbatim (served with injected system columns first) plus the filterableFields whitelist. It never read hidden or the column order, and the default field is the builder's addCondition seeding on the first entry of fields. Now: a field with hidden: true is not offered, unless filterableFields names it or a held condition filters on it (a restored filter would otherwise draw a blank field trigger). Order: the view's columns as the grid shows them (effectiveFields, after FLS, hidden columns and fieldOrder), then other business fields, then system fields (the existing isSystemManagedField from @object-ui/types, which reads the spec system flag), then a kept hidden field. So Add filter starts on the first visible column. BUILDER (components FilterBuilder): the operator dropdown mounts a module-private offeredOperatorsForRow. It is operatorsForFieldType minus is_null and is_not_null where the spec's expandEmptyOperator rates the type null_only. There is_empty matches exactly what is_null matches, and every dialect the builder writes lowers is_empty to $empty. The text arm (null or blank) and the multi_value arm (null or empty list) keep both pairs. The row's own operator is always mounted, so a stored is_null loads as Is null. operatorsForFieldType, what a row can HOLD, is unchanged: the app-shell dataset read-back (builderHolds, readBackOperator) and the plugin-list parity pin read it, and their suites pass unchanged. The hint ends the operator list on the two-pair arms, with the operator labels interpolated. Zone 2: H1 confirmed (list built verbatim; default = the first entry of fields). H2 measured from the spec: select, lookup, number and date are null_only. A multiple:true lookup, user or select is multi_value on the server, but the descriptor has no multiple, so it is judged null_only; see the PR draft's Acceptance notes. H3: the list view owns field list, order and default; the builder owns the operator offer. Author-facing callers lose no predicate, and a stored is_null is pinned. H4: reused isSystemManagedField. No export, prop or type member is added. The PR body draft is ready at the scratchpad path issue-11810/pr-body-draft-11810.md. Worktree removed after the push.",
"tests": "All at final HEAD 3c5fe54, from the worktree root, through os-verify-lock. UNION: vitest run --maxWorkers=2 packages/components/ packages/plugin-list/ packages/i18n/, plus the cross-package filter suites (FilterConditionField*, datasetFilterCondition*, filter-builder-protocol-ids-census-9306, drillDialect, drillEmptyBucketEscapeHatch-9159, view-operator-builder-parity, filter-builder-mirror-6939): Test Files 577 passed | 1 skipped (578); Tests 6746 passed | 37 skipped (6783); VERDICT command-exit 0. TYPE-CHECK, after turbo run build --filter=@object-ui/plugin-list^... (12 tasks successful): pnpm --filter components, i18n and plugin-list run type-check echoed tsc --noEmit && tsc -p tsconfig.test.json for all three; exit 0. ESLINT on the 16 touched TS files: 0 errors. ListView.tsx 188 warnings = base 188; filter-builder.tsx 19 = base 19; the new test files 0. PINS: ListView.filterFieldList-11810 (6) and filter-builder-empty-null-pair-11810 (19). Updated: filter-builder-operator-alias-trigger-7561 (the number list loses the null pair) and de-quote-pairing-3876 (census 71 to 75 for the hint's four quoted spans). ABLATIONS on the committed tree (no dist involved: the tests resolve @object-ui/* to src through vitest aliases). Each was landed by a node anchor replace, proven by a marker count 0 to 1 and the blob differing from HEAD, run, then restored by git checkout HEAD --; the restore is proven by the blob hash equal to HEAD and an empty git diff HEAD. Predicted direction: red. (1) filterFields returns candidateFields unfiltered: 5 of 6 red, the fixture control green; Add filter read Organization instead of Title. (2) offeredOperatorsForRow returns the full bucket: 11 red (nine null_only types, the stored-is_null partner, the 7561 list), 52 green. (3) the row-own clause removed: the 3 stored/held controls red, each a BLANK trigger (expected Is null, received empty). The first attempt at (1) was a no-op: grep -cF with a multi-line anchor refused the landing before any test ran; it was re-run with a single-line anchor.",
"mcp_calls": "0",
"api_writes": "1 — POST /repos//issues/11810/comments (this os-dev-report, via scripts/pm/post-stamped.mjs on the fleet relay). Not REST: git push of the branch (3 pushes: the empty probe, cedb17c, 3c5fe54). No pr_create and no label-write, because no PR was opened.",
"open_questions": [
{
"question": "Clause-② stop: the ruling's hint ('one empty-check pair per field type unless the type genuinely distinguishes them, with a hint') needs two new language-pack keys, filterBuilder.emptyCheckHint.text and .list, in the ten packs, plus the de quote census pin. The claim says Clause-②: no, and its File surface lacks packages/i18n. How should it land?",
"options": [
"A: amend the claim to a Clause-② yes line and widen its File surface to packages/i18n/src/locales/*.ts and packages/i18n/src/tests/de-quote-pairing-3876.test.ts; open the draft PR from the branch as is (Fixes #11810, body draft ready).",
"B: drop commit cedb17c (the hint and keys), open the PR as Part of #11810 with the Clause-②-free fix (field list, default, one pair on null_only types), and carry the hint as a follow-up card."
],
"recommendation": "A. Real business need: the card's Expected and the triage direction both name the hint, and B leaves text columns with two unexplained pairs, the exact confusion the card reports. Long-term soundness: the keys are copy, not a new capability; the arm comes from the spec's own expandEmptyOperator, with no local type list. Guarding against AI mistakes: no authorable metadata surface changes, nothing becomes tolerant, and the stored is_null stays explicit. Startup scope: two strings in the existing filterBuilder namespace, no new prop or export. B costs a second card and a second release note for one sentence."
}
],
"out_of_scope_findings": [
"carrier: 承接者:无 · noted, not filed — the list Sort picker reads the same candidateFields (relational fields excluded, platform sortability applied). Whether it offers the hidden __search text column on a served deployment was NOT measured: a read-only inference, so it goes in Acceptance notes only. Dedupe words: sort picker hidden field · search index sort field · hidden system field sort builder"
],
"gates": [
{
"command": "pnpm exec vitest run (union, see tests)",
"exit": 0,
"verdict": "Test Files 577 passed | 1 skipped (578); Tests 6746 passed | 37 skipped (6783); os-verify-lock VERDICT command-exit 0"
},
{
"command": "pnpm --filter @object-ui/components --filter @object-ui/i18n --filter @object-ui/plugin-list run type-check",
"exit": 0,
"verdict": "os-verify-lock VERDICT command-exit 0 (three tsc echoes, no error TS)"
},
{
"command": "pnpm turbo run build --filter=@object-ui/plugin-list^... --concurrency=2",
"exit": 0,
"verdict": "Tasks: 12 successful, 12 total"
},
{
"command": "pnpm exec eslint (16 touched TS files)",
"exit": 0,
"verdict": "0 errors; warnings equal to base per file"
},
{
"command": "pnpm check:control-bytes",
"exit": 0,
"verdict": "check-control-bytes: OK (scanned 7801 tracked text file(s); skipped 85 binary)."
},
{
"command": "pnpm check:test-path-roots",
"exit": 0,
"verdict": "check-test-path-roots: OK"
},
{
"command": "pnpm check:changeset-claims",
"exit": 0,
"verdict": "Every package declared across those 1 body(ies) is either not negated"
},
{
"command": "pnpm check:pending-changeset-literals",
"exit": 0,
"verdict": "No test source names a pending changeset."
},
{
"command": "pnpm check:i18n-keys",
"exit": 0,
"verdict": "Every in-scope call-site key resolves against the en pack (3299 keys) ..."
},
{
"command": "pnpm check:i18n-drift",
"exit": 0,
"verdict": "No en value changed in this range."
},
{
"command": "pnpm check:i18n-dead-keys",
"exit": 0,
"verdict": "report-only; 343 pre-existing candidates, 0 of them emptyCheckHint"
},
{
"command": "pnpm check:i18n-designer-parity",
"exit": 0,
"verdict": "Every en row has a zh row, and every shared row carries the same placeholders."
},
{
"command": "pnpm check:vi-mock-specifiers",
"exit": 0,
"verdict": "check-vi-mock-specifiers: OK"
},
{
"command": "pnpm check:vi-mock-inherit",
"exit": 0,
"verdict": "check-vi-mock-inherit: OK"
},
{
"command": "pnpm check:vi-mock-override-shape",
"exit": 0,
"verdict": "check-vi-mock-override-shape: OK"
},
{
"command": "pnpm check:new-line-citations",
"exit": 0,
"verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only, exit 0"
},
{
"command": "pnpm check:phantom-deps",
"exit": 0,
"verdict": "Every in-scope import is declared by the package that publishes it."
},
{
"command": "pnpm check:esm-specifiers",
"exit": 0,
"verdict": "Specifier leg: no un-ledgered package emits an extensionless relative specifier."
},
{
"command": "node scripts/check-changeset-presence.mjs",
"exit": 0,
"verdict": "16 source file(s) of 3 released package(s) changed, and this change declares 1 changeset(s)"
},
{
"command": "node scripts/check-changeset-no-major.mjs",
"exit": 0,
"verdict": "No changeset declares a major bump."
},
{
"command": "pnpm check:eager-closure / check:eager-locale-catalogues",
"exit": 2,
"verdict": "NOT MEASURED: PREREQUISITE NOT MET (reads a built console bundle; declared to CI). Marginal: spec/data is already eager through containers.tsx; an esbuild probe adds +216 B min / +94 B gzip for expandEmptyOperator"
}
],
"deviations": [
"Clause-② stop: PR not opened (new language-pack keys); see open_questions.",
"Files outside the claim's File surface: packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts and packages/i18n/src/tests/de-quote-pairing-3876.test.ts, all in commit cedb17c.",
"Zone 2 asked to measure on the showcase Tasks metadata: not booted live. The shared objectstack checkout is not built or installed, and building it would mean writing to it. The fixture is rebuilt from the spec's injectedSystemColumnDefs, task.object.ts and the __search companion definition; its size matches the card's 25.",
"check:eager-closure and check:eager-locale-catalogues NOT MEASURED (console build prerequisite).",
"The first ablation attempt was a guarded no-op (see tests)."
],
"files_changed": [
".changeset/11810-filter-builder-fields.md",
"packages/components/src/custom/filter-builder.tsx",
"packages/components/src/tests/filter-builder-empty-null-pair-11810.test.tsx",
"packages/components/src/tests/filter-builder-operator-alias-trigger-7561.test.tsx",
"packages/plugin-list/src/ListView.tsx",
"packages/plugin-list/src/tests/ListView.filterFieldList-11810.test.tsx",
"packages/i18n/src/locales/ar.ts",
"packages/i18n/src/locales/de.ts",
"packages/i18n/src/locales/en.ts",
"packages/i18n/src/locales/es.ts",
"packages/i18n/src/locales/fr.ts",
"packages/i18n/src/locales/ja.ts",
"packages/i18n/src/locales/ko.ts",
"packages/i18n/src/locales/pt.ts",
"packages/i18n/src/locales/ru.ts",
"packages/i18n/src/locales/zh.ts",
"packages/i18n/src/tests/de-quote-pairing-3876.test.ts"
],
"line_budget": "not applicable (no skills/** surface)"
}
Generated by Claude Code
objectstack-fleet commented
on Oct 7, 2026 ContributorAuthorMore actionsClaim amendment —
domain:uiseat 3,session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-07T22:29Z. It amends claim6046638726after the dev'sClause-②stop (report6048143784). The claim stands otherwise.Clause-②: yes(wasno). The ruling's hint ("one empty-check pair per field type, unless the type really distinguishes empty from null (then a hint says how)", triage6043301317) needs two new keys,filterBuilder.emptyCheckHint.textand.list, in@object-ui/i18n's ten packs../localesand./locales/*are in that package'sexports, so the keys are published accept-set: an additive widening of the public surface. Everything else in the change adds no export, prop or type member.- File surface, added:
packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts(the two keys only), andpackages/i18n/src/__tests__/de-quote-pairing-3876.test.ts(its quoted-span count, 71 → 75, for the hint's four quoted labels). - The dev's open question, answered A. The hint is the ruling's own text, so dropping it (B) would ship text columns with two unexplained pairs, the confusion the card reports. The same reasoning answered objectui#11645's added keys.
- What
yesbrings:- The changeset declares at least
minor.@object-ui/i18nand@object-ui/componentsare in thefixedgroup, so oneminorlifts the group; the branch'spatchis raised in a patch round. - The PR body carries
Clause-②: yesat line start. - A contract-review-tier record (
CONTRACT_REVIEW_TIER, an isolated reviewer) is owed on the PR before it is queued. The seat runs it.
- The changeset declares at least
Generated by Claude Code
objectstack-fleet commented
on Oct 7, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 11810,
"addendum_to": 6048143784,
"status": "done",
"branch": "claude/issue-11810-filter-builder-fields",
"head": "78fb73b",
"pr": "#11836",
"session": "session_01CGZy1BGCjdN5cXqL9cnvB8",
"summary": "Round 2 under the amended claim 6048182477 (Clause-②: yes; answer A). Changeset levels raised: @object-ui/i18n minor (the two added keys, as in objectui#11645), @object-ui/components minor (it ships the hint that reads them), @object-ui/plugin-list patch (its part is a fix). All three are in the fixed group, so they version together at minor; changeset status lists the group at minor with no mixed-changeset error. One sentence now names the two keys, filterBuilder.emptyCheckHint.text and .list. Draft PR #11836 was opened from the prepared body: line 1 Fixes #11810, line 2 Clause-② yes, assigned os-support-ai. CI has not concluded (in_progress). The contract-review-tier record is the seat's.",
"gates": [
{
"command": "pnpm check:changeset-claims",
"head": "78fb73b",
"exit": 0,
"verdict": "Every package declared across those 1 body(ies) is either not negated"
},
{
"command": "pnpm check:pending-changeset-literals",
"head": "78fb73b",
"exit": 0,
"verdict": "No test source names a pending changeset."
},
{
"command": "node scripts/check-changeset-presence.mjs",
"head": "78fb73b",
"exit": 0,
"verdict": "16 source file(s) of 3 released package(s) changed, and this change declares 1 changeset(s)"
},
{
"command": "node scripts/check-changeset-no-major.mjs",
"head": "78fb73b",
"exit": 0,
"verdict": "No changeset declares a major bump."
},
{
"command": "node scripts/check-changeset-fixed.mjs (CI job Changeset Fixed Group Check)",
"head": "78fb73b",
"exit": 0,
"verdict": "All workspace packages are in the changeset fixed group. / privatePackages declared: version=true, tag=false."
},
{
"command": "pnpm changeset:check",
"head": "78fb73b",
"exit": 0,
"verdict": "fixed group + no major, both pass"
},
{
"command": "pnpm exec changeset status",
"head": "78fb73b",
"exit": 0,
"verdict": "Packages to be bumped: minor (the fixed group)"
},
{
"command": "vitest run over the 7 changeset-reading script suites (body-dialect-census, changeset-polarity-census, check-changeset-claims, check-changeset-fixed, check-changeset-no-major, check-changeset-overwrite, check-changeset-presence)",
"head": "78fb73b",
"exit": 0,
"verdict": "Test Files 7 passed (7); Tests 299 passed (299)"
},
{
"command": "code union (report 6048143784)",
"head": "3c5fe54",
"exit": 0,
"verdict": "unchanged: 78fb73b differs from 3c5fe54 only in .changeset/11810-filter-builder-fields.md"
}
],
"files_changed": [
".changeset/11810-filter-builder-fields.md (commit 78fb73b); the rest as listed in 6048143784"
],
"deviations": [
"origin/main moved 8aebc6f to 32124ac (objectui#11774, #11778, #11784). Those commits add three changesets and touch none of this branch's files, so the branch was not merged.",
"The PR body ends with the agent definition's session-URL footer form, not the harness's footer form."
],
"api_writes": "3 — pr_create POST /repos/objectstack-ai/objectui/pulls (#11836, read back identical, 11735 bytes); label-write assign POST /repos//issues/11836/assignees (read back: os-support-ai); this comment. Also 1 git push (3c5fe54 to 78fb73b).",
"mcp_calls": "0"
}
Generated by Claude Code
objectstack-fleet commented
on Oct 7, 2026 ContributorAuthorMore actionsClaim amendment 2 —
domain:uiseat 3,session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-07T23:06Z. It amends claim6046638726(already amended by6048182477) after the contract review on PR objectui#11836 (6048648388, FAIL on head78fb73b). The claim stands otherwise.- File surface, added:
packages/components/package.json(its@objectstack/specrange only), andpnpm-lock.yaml(the importer specifier the range change moves, regenerated with the repo's tooling and never edited by hand). - Why: the branch makes
@object-ui/components' published entry importexpandEmptyOperatorfrom@objectstack/spec/data. That function first ships in@objectstack/spec17.5.0 (objectstackb810ddb6; npm 17.5.0, published 2026-09-29), while the package still declares^17.0.0. The seat measured this independently while the review ran. The remedy follows the repo's precedent (@object-ui/plugin-form's floor raise besidederiveInlineGridColumns): raise the floor to^17.5.0in the same PR, and name it in the changeset. - Not filed: the dev's Sort-picker observation (the list's Sort picker may offer the hidden
__searchcolumn), which the review escalated, is inferred from reading the code, not measured. Without a measured reach the filing gate is not met, so it stays in the PR's Acceptance notes. - A fresh contract-review record is owed on the new head.
Generated by Claude Code
- File surface, added:
objectstack-fleet commented
on Oct 7, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 11810,
"addendum_to": [
6048143784,
6048273522
],
"round": "rework after contract review 6048648388 (FAIL on 78fb73b); claim amendment 6048666363",
"status": "done",
"branch": "claude/issue-11810-filter-builder-fields",
"head": "24a52a4",
"pr": "#11836",
"session": "session_01CGZy1BGCjdN5cXqL9cnvB8",
"summary": "The review's defect is reproduced and fixed. Before the raise, check-spec-range-floors.mjs on the built 78fb73b artifact reported: @object-ui/components [floor-too-low] packages/components/dist/index.js references expandEmptyOperator from @objectstack/spec/data, which @objectstack/spec@17.0.0 does not export, and suggested ^17.5.0. Commit 24a52a4 raises packages/components/package.json dependencies @objectstack/spec from ^17.0.0 to ^17.5.0. It regenerates pnpm-lock.yaml with pnpm install --lockfile-only; the lockfile diff is one line, the packages/components importer specifier. It adds the precedent-shaped floor sentence to the changeset. No source file changed. origin/main (16cda0b) touches none of the branch's files, so it was not merged. The PR body's Tests and Public surface sections now name the head and the floor line (body updated through the relay, read back identical, 13506 bytes).",
"gates": [
{
"command": "node scripts/check-spec-range-floors.mjs, after building components and plugin-list with their dependencies",
"head": "24a52a4",
"exit": 1,
"verdict": "0 floor-too-low; components and plugin-list judged clean (21 of 39 packages inspected, 304 pairs judged). Exit 1 comes only from 14 no-artifact findings for packages this branch does not touch and that were not built locally (app-shell, auth, cli, layout, plugin-chatbot, plugin-dashboard, plugin-designer, plugin-detail, plugin-form, plugin-gantt, plugin-grid, plugin-timeline, plugin-tree, plugin-view): NOT MEASURED, left to CI."
},
{
"command": "node scripts/check-spec-range-floors.mjs (control, before the raise)",
"head": "78fb73b",
"exit": 1,
"verdict": "components [floor-too-low] expandEmptyOperator vs @objectstack/spec@17.0.0; suggested ^17.5.0"
},
{
"command": "pnpm --filter @object-ui/components run type-check",
"head": "24a52a4",
"exit": 0,
"verdict": "tsc --noEmit && tsc -p tsconfig.test.json; os-verify-lock VERDICT command-exit 0"
},
{
"command": "pnpm check:changeset-claims",
"head": "24a52a4",
"exit": 0,
"verdict": "No pending changeset names a file this change touches."
},
{
"command": "pnpm check:pending-changeset-literals",
"head": "24a52a4",
"exit": 0,
"verdict": "No test source names a pending changeset."
},
{
"command": "node scripts/check-changeset-presence.mjs",
"head": "24a52a4",
"exit": 0,
"verdict": "16 source file(s) of 3 released package(s) changed, and this change declares 1 changeset(s)"
},
{
"command": "pnpm changeset:check",
"head": "24a52a4",
"exit": 0,
"verdict": "fixed group OK; privatePackages declared; no major"
},
{
"command": "pnpm check:lockfile-integrity",
"head": "24a52a4",
"exit": 0,
"verdict": "VERDICT clean — no @objectstack/* identity moved backward and no package gained a copy."
},
{
"command": "pnpm check:lockfile-dedupe",
"head": "24a52a4",
"exit": 0,
"verdict": "VERDICT deduped"
}
],
"files_changed": [
"packages/components/package.json (the @objectstack/spec range only)",
"pnpm-lock.yaml (the packages/components importer specifier line only)",
".changeset/11810-filter-builder-fields.md (one sentence)"
],
"deviations": [
"The floors check was run against artifacts I built locally for components and plugin-list only. The other 14 packages it covers are unbuilt and outside this diff, so its overall exit stays 1 for them."
],
"api_writes": "2 — issue_patch PATCH /repos//issues/11836 (PR body, read back identical); this comment. Also 1 git push (78fb73b to 24a52a4).",
"mcp_calls": "0"
}
Generated by Claude Code
objectstack-fleet commented
on Oct 7, 2026 ContributorAuthorMore actionsACCEPT —
domain:uiseat 3,session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-07T23:51Z. PR objectui#11836, head24a52a4.-
PR shape: draft against
main. First lineFixes #11810, no other closing keyword. Line 2 isClause-②: yes, matching claim amendments6048182477and6048666363. Every commit carries only the model-free trailer pair. -
The PR was opened by the dev after a
Clause-②stop. The ruling's hint needs two published keys, so the seat amended the claim toyes, answered A, and raised the changeset tominor. -
Scope: 19 files, +571/−21, on the amended surface:
plugin-listListView.tsx;componentsfilter-builder.tsxandpackage.json(the@objectstack/specrange);- the ten
i18npacks (two keys each) and the de quote-census test; pnpm-lock.yaml(one importer specifier line);- the pins;
- the changeset.
No export, prop or type member is added. No governed path.
-
Diff read (the seat's own):
ListView.filterFieldsdropshidden: truefields unless the view names them infilterableFieldsor a held condition uses them. It orders the visible columns as the grid shows them (effectiveFields), then other business fields, then system fields (the sharedisSystemManagedField). An added condition starts on the first entry, which is the first visible column.FilterBuilderoffersofferedOperatorsForRow, which is module-private: it dropsis_null/is_not_nullonly where the spec'sexpandEmptyOperatorrates the typenull_only. A row's own operator is always kept, so a storedis_nullstill loads.operatorsForFieldType, the hold set, is unchanged. The hint renders only where both pairs stay.
-
Ruling honoured (triage
6043301317):- hidden fields are not offered;
- column order, with system fields last;
- a new condition starts on the first visible column;
- one empty-check pair per type unless the type distinguishes them, with a hint.
-
One rework round: contract review
6048648388was FAIL on78fb73b.@object-ui/components' entry newly importsexpandEmptyOperator, which first ships in@objectstack/spec17.5.0, while the package declared^17.0.0. The seat measured the same thing independently.24a52a4raises the floor to^17.5.0; the lockfile moves by its one specifier line; the changeset names the raise in the precedent's shape. The dev reproduced thefloor-too-lowfinding on78fb73bwithcheck-spec-range-floors.mjsand saw it gone on24a52a4. -
Contract review:
6049175024, PASS on24a52a4(CONTRACT_REVIEW_TIER, an isolated reviewer,Local-runs: none). -
Changeset sentences checked against the head:
- the field-list bullet (hidden, order, the kept-hidden rule);
- "Add filter" starts on the first visible column;
- the empty-checks bullet, including "A stored 'Is null' condition on such a column still loads" and "what a row can hold (
operatorsForFieldType) is unchanged"; - the two keys;
- the floor raise.
plugin-listpatch,componentsandi18nminor: one fixed group atminor. -
Reverse verification (dev reports
6048143784,6048273522,6048846867):- Three ablations (the unfiltered field list, the full operator offer, the dropped hold-own-operator rule) turned their own pins red, and each was restored with the hash equal to HEAD.
- The union of
components,plugin-list,i18nand the filter suites passed 6746 tests.
-
Gates: CI on
24a52a4(head_shaequals the PR head): 45 runs, 42 success, 3 skipped (Test (coverage), its shard template,dependabot), 0 failure.LintandType Checkare success. Mergeable stateclean. The floors check is not apull_requestjob, so it is attested by the before/after run above.
Findings:
- The list's Sort picker reads the same candidate fields and may offer the hidden
__searchcolumn. That is inferred from the code, not measured, so the filing gate is not met (6048666363) →Acceptance notes - A multi-value lookup, user or select reaches the builder without
multiple, so it is treated asnull_onlyand keeps one pair. This is bounded and documented in the PR →Acceptance notes
Landing: ready + auto-merge through the queue, now.
Generated by Claude Code
-
objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsLanded —
domain:uiseat 3,session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-08T00:11Z. PR objectui#11836 merged through the queue as1e1f09eat 2026-10-08T00:09Z.- The merge:
- One parent,
87f7b6c, an ancestor oforigin/main. - The landed tree equals
git merge-treeof that parent and the accepted head24a52a4(tree808f38d2on both). - 19 files, +571/−21.
- One parent,
- Content check,
87f7b6c→1e1f09e:@object-ui/components'@objectstack/specrange went from^17.0.0to^17.5.0, the floor the first contract review asked for.offeredOperatorsForRowinfilter-builder.tsx: 0 → 4.- The
emptyCheckHintblock inen.ts: 0 → 1. - Control: the exported
operatorsForFieldTypeis 1 on both sides, so the hold set is unchanged.
- Closures: the PR's only closing keyword was
Fixes #11810. Since 23:50Z, the issues closed are objectui#11827 (its own PR) and objectui#11810.pm:dispatchedis removed.
Generated by Claude Code
- The merge:
- added a commit that references this issue
on Oct 9, 2026
Filing gate ① — product defect with a named location and a reproduction. reach: showcase Tasks list → Filter → Add filter.
Who acts on it: objectui triage → the console / records owner. ⛔ Not a claim. Found in a manual browser QA pass of the end-user console on 2026-10-07; filed one card per finding on the maintainer's word: 「你发现的问题全部提交 issue,然后继续测试前端」, and on the one-card-per-finding question 「覆盖规则,逐条立卡」.
What happens
organization_id,hidden: true).__search).Expected
Hidden fields are not offered; business fields come first (the view's columns, then the rest), system fields grouped last; one empty-check pair per field type unless the type genuinely distinguishes them, with a hint.
Suggested direction (triage to rule)
Filter the field list by
hidden, order it by the view's column order, default the first condition to the first visible column, and merge or explain the empty/null operators.Environment
objectstack
879bd38c·examples/app-showcasebooted withobjectstack dev --ui --seed-adminon an isolated port and SQLite file · objectui179f6fe9(HEAD; the framework pin.objectui-shaisa58626c8) served by the console's Vite dev server, perf numbers from avite buildof the same commit · Chromium 141 at 1440×900 · signed in as the seeded platform adminadmin@objectos.aiunless stated.Duplicate check
ListView.convertFilterGroupToASTdrops a freshIs null/Is not nullrow as incomplete, so the list filter silently applies nothing #4744 (closed) — prior Is null operator fix in the same list filter; different defect$in: [null, '']/$nin: [null, ''], a null list member every objectstack filter face refuses, so related lists and rollups built with them fail #10790 (closed) — defines what Is empty compiles to (null or empty string), which is why offering both Is empty and Is null is redundant; different defectDedupe words: filter builder default field hidden organization · system fields first filter · is empty is null duplicate operators
Filed by Claude Code (session
session_01D76mrPJrSSdaKRxR2rvrMG) from that QA pass.Generated by Claude Code