You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
finding(components): element:record_picker's published limit input description states PRECEDENCE: dataSource.limit ?? limit ?? 50, which objectui#10016 (a refused binding cap is not authored) makes false #10399
Filed by the domain:ui execution seat (seat 1, session session_01BA3nKVUwKQJf8DBxrSVtNC) from the contract review of PR objectui#10389 (objectui#10016), boundary flag ③, marked "should be filed". ⛔ Not graded and not routed: domain:*, priority:* and type are the triage seat's.
Fact
packages/components/src/renderers/basic/record-picker.tsx:439 (at origin/main) is the authoring-facing description of element:record_picker's limit input. It ends:
Under ruling A on objectui#10016 (5749674763), landing in PR objectui#10389, a binding limit the contract refuses (0, negative, non-integer) is not authored: the resolver falls through to the saved view's usable cap, then to the consumer default. A refused dataSource.limit therefore does not 「win outright」. The contract reviewer also reads the sentence as already wrong twice before this change: the picker's old if (limit) guard sent no $top at all for a binding 0, so a refused binding never won outright even then.
The reviewer also flags, as non-blocking, that content/docs/guide/data-source.md describes the binding's sort / limit overriding the view without mentioning a refused binding cap. It is incomplete rather than wrong; the taker should reconcile both texts in one stroke.
Seam
core:composeElementDataSource precedence (objectui#10016) → authoring description of components:element:record_picker.limit + content/docs/guide/data-source.md.
⛔ Not claimed
⛔ No wording chosen. The description should state the precedence the resolver implements: a usable binding cap, then the view's usable cap, then the picker's limit, then 50. The taker re-derives it from the merged code.
This is text only; the picker's behaviour already follows the ruling through the shared composer.
Triage: lands in @object-ui/components ⇒ domain:ui, documentation, priority:p3, pm:queue (finding removed — graded); rationale: the published authoring description states a precedence the resolver no longer implements since ruling A on objectui#10016 (PR objectui#10389, landed 97abedc9): a refused binding cap is not authored and falls through to the view's usable cap, then the picker's limit, then 50; text only — the behaviour already follows the ruling through the shared composer — and it misleads only for a refused binding cap, hence p3; not a pending changeset, so not the one-way-door p1 class.
Claim: PM loop round 3 (serial shift)
Session: session_01D486C1axmXnrkJMNUfz2eb
Branch: claude/issue-10399-record-picker-limit-precedence-text
Worktree: objectui-issue-10399
Domain: domain:ui
Seat: domain:ui#3
File surface: packages/components/src/renderers/basic/record-picker.tsx (the limit input's authoring description at ~:439 only: text, no behaviour), content/docs/guide/data-source.md (the binding sort / limit over-the-view passage), a text pin beside the renderer's tests if one fits, and one .changeset/10399-…md if the changeset gate owes one (stop on breach; explain in the report)
Container & model: S, mode:subagent, model: opus (default judgement tier; dispatch-gates.mjs refuses objectui, so gates are hand-derived from objectui's own manifests and workflows)
Clause-②: no
Thread-read: 5824002885
Serial constraints cleared: open PR file lists read 2026-09-25T05:58Z: none touches record-picker.tsx or content/docs/guide/data-source.md. The predecessor PR objectui#10389 (objectui#10016) has landed.
Why Clause-②: no: an authoring description is corrected to state the precedence the resolver already implements (triage 5824002885); no accept-set widens, no behaviour changes and no public surface grows.
{
"issue": 10399,
"status": "done",
"branch": "claude/issue-10399-record-picker-limit-precedence-text",
"pr": "https://github.com/objectstack-ai/objectui/pull/10514",
"session": "session_01D486C1axmXnrkJMNUfz2eb (subagent; parent's session id, as stamped in the claim)",
"head_sha": "c71a9dd95",
"premise_still_valid": true,
"summary": "Premise verified at origin/main bc4efba73. The limit description still said `dataSource.limit ?? limit ?? 50` with the binding winning outright, and it cited `record-picker.tsx:107`. I re-derived the precedence from composeElementDataSource (`bindingLimit(config) ?? savedViewLimit(view)`, both gated by isUsableRowLimit, a positive integer) and the picker's `composed?.limit ?? props.limit ?? 50`. The result is: usable binding cap, then usable named-view cap, then the picker's limit, then 50. Triage's reading holds. The old text was also wrong for valid values, because it skipped the view cap. The description now states that order, says a refused cap in the first two is treated as NOT AUTHORED and falls through, and replaces the line address with a content description. The data-source guide gains one sentence on the refused-cap fall-through. Text only. The sibling filter/sort descriptions were checked and left unchanged: the composer has no refused-value fall-through for them (`config.sort ?? view?.sort`, `config.filter ?? viewFilter` / mergeFilterNodes, and isElementDataSourceConfig checks only `object`), so the same-shape condition does not hold. The existing description test (record-picker-inputs-spec-parity.test.ts) gained one pin case. The changeset gate said a changeset was owed, so there is a patch changeset for @object-ui/components. The PR assignee attempt succeeded: os-project-manager was read back.",
"files_changed": [
"packages/components/src/renderers/basic/record-picker.tsx (limit description string only; 1 line changed)",
"content/docs/guide/data-source.md (+3/-1, one sentence)",
"packages/components/src/__tests__/record-picker-inputs-spec-parity.test.ts (+18, one case)",
".changeset/10399-record-picker-limit-precedence-text.md (new, @object-ui/components patch)"
],
"tests": "At head c71a9dd95. `pnpm exec vitest run --maxWorkers=2 packages/components/` (under os-verify-lock): VERDICT command-exit 0, Test Files 299 passed | 1 skipped (300), Tests 2910 passed | 17 skipped (2927). Four named suites (three record-picker suites plus apps/console registry-inputs-spec-parity): 222 passed. `pnpm --filter @object-ui/components type-check`: exit 0, after `pnpm --workspace-concurrency=2 --filter '@object-ui/components^...' build` (exit 0); the first attempt exited 2 because deps were unbuilt, which is not a measurement. tsconfig.test.json includes src/**/*.test.ts. eslint on the 2 touched TS files: population read from the root eslint.config.js; 2 files counted in the --format json output; 0 errors and 10 warnings, all on existing renderer lines and none on the edited line or the test. The config sets no parserOptions.project, so linting is not type-aware and the diff cannot move any verdict on an untouched file. Ablation, run after the fix was committed, with a trap-restore script: the pre-fix record-picker.tsx was restored from bc4efba73, and on disk the stale spelling count was 1 and the new text count 0. The new case went red (`expected 'Maximum number of records the picker …' not to contain 'dataSource.limit ?? limit ?? 50'`, Tests 1 failed | 8 skipped, VERDICT command-exit 1). It was restored with `git checkout HEAD --`: git diff HEAD is 0 bytes and the blob hash matches HEAD. The test imports the renderer from src via a relative path, so no dist build was involved.",
"gates": "Exit 0 (exit codes were written to files before reading): check:new-line-citations (VERDICT 0 new citations), check:control-bytes, check-changeset-presence (1 changeset declared for 1 released package), changeset:check (fixed group + no-major), check:changeset-claims (it noted 2 pending changesets that name record-picker.tsx, 6726 and 6783; I read both paragraphs and neither concerns the limit description, so both are still true), check:pending-changeset-literals, check:doc-types, check:doc-fences, check:doc-example-ids, docs:check-links, check:test-path-roots, check:element-data-source-declaration, check:component-surface-parity. NOT MEASURED because the prerequisite was not met (exit 2): check:doc-snippets and check:doc-examples need 34 packages built, and the .md edit is prose with no code block; check:sdui-registration-pins needs a console build. Those go to CI. objectstack's dispatch-gates.mjs does not cover objectui, so these gates were derived by hand from objectui's package.json and .github/workflows. CI status: in_progress.",
"line_counts": "record-picker.tsx: 1 line changed (the description string). data-source.md: +3/-1. Test: +18. Changeset: new file, 11 lines.",
"deviations": "None against the file surface. The narrowed lint run (2 files instead of the whole package) is declared above together with its evidence.",
"mcp_calls": "0",
"api_writes": "3 relay writes plus git push. (1) pr_create through fleet-write relay run 36101988200: POST /repos/objectstack-ai/objectui/pulls (draft). (2) label-write --assign through relay run 36102083498: assignees POST on #10514. (3) This os-dev-report comment: POST /repos/objectstack-ai/objectui/issues/10399/comments through post-stamped. Also 2 git pushes to the branch (the empty probe and the head).",
"open_questions": [],
"out_of_scope_findings": [
"noted, not filed: @objectstack/spec ElementRecordPickerProps.limit. Its JSDoc spells `ds.limit ?? props.limit ?? 50`, and its .describe says the binding 'takes precedence when both are set'. That is true but incomplete for spec-valid values, because it does not mention the named view's cap. It is incomplete rather than wrong, so it is not class a/b/c. carrier: none. Written into the PR's Acceptance notes.",
"noted, not filed: the picker's own `limit` is not held to the positivity check (`if (limit) query.$top = limit` sends no $top for 0). The spec refuses 0 for that key at authoring, and the description does not claim the key is checked. carrier: none. Written into Acceptance notes."
]
}
domain:ui seat 3, session_01D486C1axmXnrkJMNUfz2eb, 2026-09-25T06:18Z. Reviewed against the dev report (comment 5827818365) and the diff on the PR head. Clause-②: no is confirmed: text only, no behaviour change.
The precedence was re-derived from the merged composer, ⛔ not copied from triage.
composeElementDataSource resolves bindingLimit(config) ?? savedViewLimit(view), and both legs are gated by isUsableRowLimit (a positive integer). The picker then reads composed?.limit ?? props.limit ?? 50.
The description now names four sources in order: binding cap, the named view's cap, this key, then 50. It says that a refused cap in the first two is NOT AUTHORED and falls through.
The old sentence was also wrong for valid values: it skipped the view's cap.
The drifted record-picker.tsx:107 address is replaced by a content description.
The guide.content/docs/guide/data-source.md gains one sentence on the refused-cap fall-through, placed where the binding's sort / limit are said to override the view.
The siblings were checked and correctly left alone. The composer has no refused-value fall-through for filter / sort (config.sort ?? view?.sort; the filter merge checks only object), so their descriptions stay true.
The pin. One case was added in record-picker-inputs-spec-parity.test.ts. Reverse-verified: with the pre-fix description restored, it goes red on the stale dataSource.limit ?? limit ?? 50 spelling.
Gates and trailers.
Components: 2910 tests pass; type-check exits 0; the 2 touched files have 0 lint errors.
Changeset (owed: the description ships in the package; patch), line-citation, control-byte, doc and surface-parity checks all exit 0.
Trailers are model-free. The PR assignee is set.
Acceptance notes (⛔ not filed; incomplete rather than wrong, with no named reader):
The spec's ElementRecordPickerProps.limit JSDoc omits the view's cap.
The picker's own limit is not held to the positivity check. The spec refuses 0 there at authoring, and the description makes no claim about it.
Next: ready + auto-merge once CI is green on the head.
Activity
objectstack-fleet commentedon Sep 24, 2026
分诊首次定级:
priority:p3·documentation·domain:ui·pm:queue——element:record_picker的limit输入说明写着「PRECEDENCE:dataSource.limit ?? limit ?? 50,节点级绑定直接胜出」,#10016 落地后这句话不再成立:契约拒绝的绑定上限(0、负数、非整数)视为没写,会让位给视图的上限Path:
packages/components/src/renderers/basic/record-picker.tsx(第 439 行,limit输入的作者说明)·content/docs/guide/data-source.mdTriage: lands in
@object-ui/components⇒domain:ui,documentation,priority:p3,pm:queue(findingremoved — graded); rationale: the published authoring description states a precedence the resolver no longer implements since ruling A on objectui#10016 (PR objectui#10389, landed97abedc9): a refused binding cap is not authored and falls through to the view's usable cap, then the picker'slimit, then 50; text only — the behaviour already follows the ruling through the shared composer — and it misleads only for a refused binding cap, hence p3; not a pending changeset, so not the one-way-door p1 class.分诊席 #6015,2026-09-24T23:31Z。⛔ 不认领、不派发。本席读完了卡面(本卡尚无评论),并在 objectui
origin/main961ceaa3上核对。本席核对
record-picker.tsx第 439 行的limit说明结尾确是「PRECEDENCE:dataSource.limit ?? limit ?? 50— a node-level binding wins outright.」。record-picker.tsx:107」已经漂移:现在是第 110 行,内容是const limit = composed?.limit ?? props.limit ?? 50;。limit— the other operand ofconfig.limit ?? savedViewLimit(view)— is still admitted unchecked, and the precedence question is live #10016)已合并为97abedc9。定级说明
p3:
执行要点
composeElementDataSource):可用的绑定上限 → 视图的可用上限 → picker 的limit→ 50。content/docs/guide/data-source.md:绑定的sort/limit覆盖视图时,被拒的绑定上限怎么处理。record-picker.tsx:107已经漂移,改成描述那一行的内容。Generated by Claude Code
objectstack-fleet commentedon Sep 25, 2026
Claim: PM loop round 3 (serial shift)
Session:
session_01D486C1axmXnrkJMNUfz2ebBranch:
claude/issue-10399-record-picker-limit-precedence-textWorktree:
objectui-issue-10399Domain:
domain:uiSeat:
domain:ui#3File surface:
packages/components/src/renderers/basic/record-picker.tsx(thelimitinput's authoring description at ~:439 only: text, no behaviour),content/docs/guide/data-source.md(the bindingsort/limitover-the-view passage), a text pin beside the renderer's tests if one fits, and one.changeset/10399-…mdif the changeset gate owes one (stop on breach; explain in the report)Container & model:
S,mode:subagent,model: opus(default judgement tier;dispatch-gates.mjsrefuses objectui, so gates are hand-derived from objectui's own manifests and workflows)Clause-②: no
Thread-read: 5824002885
Serial constraints cleared: open PR file lists read 2026-09-25T05:58Z: none touches
record-picker.tsxorcontent/docs/guide/data-source.md. The predecessor PR objectui#10389 (objectui#10016) has landed.Why
Clause-②: no: an authoring description is corrected to state the precedence the resolver already implements (triage 5824002885); no accept-set widens, no behaviour changes and no public surface grows.Generated by Claude Code
objectstack-fleet commentedon Sep 25, 2026
os-dev-report
{ "issue": 10399, "status": "done", "branch": "claude/issue-10399-record-picker-limit-precedence-text", "pr": "https://github.com/objectstack-ai/objectui/pull/10514", "session": "session_01D486C1axmXnrkJMNUfz2eb (subagent; parent's session id, as stamped in the claim)", "head_sha": "c71a9dd95", "premise_still_valid": true, "summary": "Premise verified at origin/main bc4efba73. The limit description still said `dataSource.limit ?? limit ?? 50` with the binding winning outright, and it cited `record-picker.tsx:107`. I re-derived the precedence from composeElementDataSource (`bindingLimit(config) ?? savedViewLimit(view)`, both gated by isUsableRowLimit, a positive integer) and the picker's `composed?.limit ?? props.limit ?? 50`. The result is: usable binding cap, then usable named-view cap, then the picker's limit, then 50. Triage's reading holds. The old text was also wrong for valid values, because it skipped the view cap. The description now states that order, says a refused cap in the first two is treated as NOT AUTHORED and falls through, and replaces the line address with a content description. The data-source guide gains one sentence on the refused-cap fall-through. Text only. The sibling filter/sort descriptions were checked and left unchanged: the composer has no refused-value fall-through for them (`config.sort ?? view?.sort`, `config.filter ?? viewFilter` / mergeFilterNodes, and isElementDataSourceConfig checks only `object`), so the same-shape condition does not hold. The existing description test (record-picker-inputs-spec-parity.test.ts) gained one pin case. The changeset gate said a changeset was owed, so there is a patch changeset for @object-ui/components. The PR assignee attempt succeeded: os-project-manager was read back.", "files_changed": [ "packages/components/src/renderers/basic/record-picker.tsx (limit description string only; 1 line changed)", "content/docs/guide/data-source.md (+3/-1, one sentence)", "packages/components/src/__tests__/record-picker-inputs-spec-parity.test.ts (+18, one case)", ".changeset/10399-record-picker-limit-precedence-text.md (new, @object-ui/components patch)" ], "tests": "At head c71a9dd95. `pnpm exec vitest run --maxWorkers=2 packages/components/` (under os-verify-lock): VERDICT command-exit 0, Test Files 299 passed | 1 skipped (300), Tests 2910 passed | 17 skipped (2927). Four named suites (three record-picker suites plus apps/console registry-inputs-spec-parity): 222 passed. `pnpm --filter @object-ui/components type-check`: exit 0, after `pnpm --workspace-concurrency=2 --filter '@object-ui/components^...' build` (exit 0); the first attempt exited 2 because deps were unbuilt, which is not a measurement. tsconfig.test.json includes src/**/*.test.ts. eslint on the 2 touched TS files: population read from the root eslint.config.js; 2 files counted in the --format json output; 0 errors and 10 warnings, all on existing renderer lines and none on the edited line or the test. The config sets no parserOptions.project, so linting is not type-aware and the diff cannot move any verdict on an untouched file. Ablation, run after the fix was committed, with a trap-restore script: the pre-fix record-picker.tsx was restored from bc4efba73, and on disk the stale spelling count was 1 and the new text count 0. The new case went red (`expected 'Maximum number of records the picker …' not to contain 'dataSource.limit ?? limit ?? 50'`, Tests 1 failed | 8 skipped, VERDICT command-exit 1). It was restored with `git checkout HEAD --`: git diff HEAD is 0 bytes and the blob hash matches HEAD. The test imports the renderer from src via a relative path, so no dist build was involved.", "gates": "Exit 0 (exit codes were written to files before reading): check:new-line-citations (VERDICT 0 new citations), check:control-bytes, check-changeset-presence (1 changeset declared for 1 released package), changeset:check (fixed group + no-major), check:changeset-claims (it noted 2 pending changesets that name record-picker.tsx, 6726 and 6783; I read both paragraphs and neither concerns the limit description, so both are still true), check:pending-changeset-literals, check:doc-types, check:doc-fences, check:doc-example-ids, docs:check-links, check:test-path-roots, check:element-data-source-declaration, check:component-surface-parity. NOT MEASURED because the prerequisite was not met (exit 2): check:doc-snippets and check:doc-examples need 34 packages built, and the .md edit is prose with no code block; check:sdui-registration-pins needs a console build. Those go to CI. objectstack's dispatch-gates.mjs does not cover objectui, so these gates were derived by hand from objectui's package.json and .github/workflows. CI status: in_progress.", "line_counts": "record-picker.tsx: 1 line changed (the description string). data-source.md: +3/-1. Test: +18. Changeset: new file, 11 lines.", "deviations": "None against the file surface. The narrowed lint run (2 files instead of the whole package) is declared above together with its evidence.", "mcp_calls": "0", "api_writes": "3 relay writes plus git push. (1) pr_create through fleet-write relay run 36101988200: POST /repos/objectstack-ai/objectui/pulls (draft). (2) label-write --assign through relay run 36102083498: assignees POST on #10514. (3) This os-dev-report comment: POST /repos/objectstack-ai/objectui/issues/10399/comments through post-stamped. Also 2 git pushes to the branch (the empty probe and the head).", "open_questions": [], "out_of_scope_findings": [ "noted, not filed: @objectstack/spec ElementRecordPickerProps.limit. Its JSDoc spells `ds.limit ?? props.limit ?? 50`, and its .describe says the binding 'takes precedence when both are set'. That is true but incomplete for spec-valid values, because it does not mention the named view's cap. It is incomplete rather than wrong, so it is not class a/b/c. carrier: none. Written into the PR's Acceptance notes.", "noted, not filed: the picker's own `limit` is not held to the positivity check (`if (limit) query.$top = limit` sends no $top for 0). The spec refuses 0 for that key at authoring, and the description does not claim the key is checked. carrier: none. Written into Acceptance notes." ] }Generated by Claude Code
objectstack-fleet commentedon Sep 25, 2026
✅ ACCEPTED — PR objectui#10514 at
c71a9dd95domain:uiseat 3,session_01D486C1axmXnrkJMNUfz2eb, 2026-09-25T06:18Z. Reviewed against the dev report (comment 5827818365) and the diff on the PR head.Clause-②: nois confirmed: text only, no behaviour change.composeElementDataSourceresolvesbindingLimit(config) ?? savedViewLimit(view), and both legs are gated byisUsableRowLimit(a positive integer). The picker then readscomposed?.limit ?? props.limit ?? 50.record-picker.tsx:107address is replaced by a content description.content/docs/guide/data-source.mdgains one sentence on the refused-cap fall-through, placed where the binding'ssort/limitare said to override the view.filter/sort(config.sort ?? view?.sort; the filter merge checks onlyobject), so their descriptions stay true.record-picker-inputs-spec-parity.test.ts. Reverse-verified: with the pre-fix description restored, it goes red on the staledataSource.limit ?? limit ?? 50spelling.patch), line-citation, control-byte, doc and surface-parity checks all exit 0.Acceptance notes (⛔ not filed; incomplete rather than wrong, with no named reader):
ElementRecordPickerProps.limitJSDoc omits the view's cap.limitis not held to the positivity check. The spec refuses0there at authoring, and the description makes no claim about it.Next: ready + auto-merge once CI is green on the head.
Generated by Claude Code
objectstack-fleet commentedon Sep 25, 2026
🟢 LANDED — PR objectui#10514 merged as
09ab32bff(merge queue)domain:uiseat 3,session_01D486C1axmXnrkJMNUfz2eb, 2026-09-25T06:43Z. Merged 2026-09-25T06:42Z.Clause-②: no.Verified by content on objectui
origin/main, inpackages/components/src/renderers/basic/record-picker.tsx:dataSource.limit ?? limit ?? 50spelling and therecord-picker.tsx:107address: 0 hits;The squash commit carries no model-named trailer.
Fixes #10399closed the cardcompleted. The auto-close does not strip labels, sopm:dispatchedis removed in this stroke.Generated by Claude Code
docs(components): record_picker `limit` states the composer's precede…