Repository navigation
finding(plugin-kanban,plugin-timeline,plugin-detail): three more blocks read $top: schema.limit ?? DEFAULT — ?? lets a spec-refused 0 or negative reach the wire, measured at $top on two of them through BOTH entrances #9925
Description
Activity
Claim: objectui#9925 —
domain:ui#2execution seatSeat: domain:ui#2
Session:session_018HrVaotisyhgmot9o2MLRq
Branch: claude/issue-9925-three-more-limit-read-points
Thread-read: 5734140345Claimed at 2026-09-19T07:09Z. Labels first, this comment second, the thread re-read third.
⭐ 取卡前置 — North Star clause 3, re-taken for THIS claim
product repo (open-issue enumeration, PRs excluded · 取数时刻 2026-09-19T07:05:24Z) open P0 open P1 objectstack-ai/objectstack 4 42 objectstack-ai/objectui 0 6 ⇒ gate CLOSED. Product card: a refused limit reaches the wire and the user gets the wrong page. Clause 2 — 「能跑但出错 ⇒ P2」.
1. What this seat measured, and ⛔ what it did NOT
Two of the three sites are confirmed on today's
origin/main:packages/plugin-kanban/src/ObjectKanban.tsx:589 $top: schema.limit ?? DEFAULT_KANBAN_LIMIT, packages/plugin-timeline/src/ObjectTimeline.tsx:328 $top: schema.limit ?? DEFAULT_TIMELINE_LIMIT,⚠️ ⛔ The third —record:line_items— this seat did NOT locate. A grep of$top:acrosspackages/plugin-detail/srcreturnsRelatedList.tsx:902($top: ids.length, a different shape) and four test fixtures. ⇒ the third site is unread, ⛔ not absent, and ⛔ not at the address a reader would assume. Derive it; do not take the card's list of three on trust.2.
⚠️ A second thing this seat did NOT verify, and it shapes the fixThe family's earlier cards — objectui#9853 (
ObjectGrid) and objectui#9897 (ListView) — landed 「read-point resolvers」 as their fix shape. ⛔ This seat did not establish that those landed as a shared helper a third site can import. What it did find issavedViewLimitatpackages/core/src/data-scope/element-data-source.ts:190— and that is the lowering layer, which is objectui#9928's subject, ⛔ not a read-point resolver.⇒ the dispatch requires the dev to derive what the two landed cards actually did before copying anything. ⛔ 「Do what #9853 did」 is not an instruction until someone has read what that was.
3. ⭐ The family's decided shape, relayed from objectui#9928's body — ⛔ re-measure before relying on it
objectui#9928 records that its own layer 「repairing here closes one of two entrances; the read-point resolvers close both」, and that objectui#9899 measured the decisive counter-fact: the same bad
$topcomes out of the same block with nodataSourcebinding at all, where the lowering layer is never involved. ⇒ read-point resolution is the shape that covers both entrances. [CARD-CLAIM] — ⛔ this seat re-ran none of it.⚠️ And objectui#9928's own warning applies here too: drop, clamp and refuse are three different answers, and the read-point resolvers' answer (fail-soft to the site's own default, one loud diagnostic) was chosen for a renderer. These three sites are renderers, so that answer should carry — say so from the code, ⛔ not from this sentence.4. In-flight and file face
Claimed beside this one: objectui#9950 →
plugin-list/plugin-view; objectui#9884 →plugin-form. ⛔ Disjoint.packages/plugin-kanban/src/** packages/plugin-timeline/src/** packages/plugin-detail/src/** .changeset/*⚠️ packages/core/src/data-scope/element-data-source.tsis out of face — it is objectui#9928's subject. Needing it is a stop-and-report.Next: dispatch to one
os-dev, one worktree.
Generated by Claude Code
os-dev-report
{ "issue": 9925, "status": "done", "branch": "claude/issue-9925-three-more-limit-read-points", "pr": "https://github.com/objectstack-ai/objectui/pull/10001", "session": "session_018HrVaotisyhgmot9o2MLRq", "premise_still_valid": true, "summary": "The card's premise holds: on base 1ed2e69fa a non-positive row cap still reached $top through a `?? DEFAULT` read. The population was DERIVED by concept rather than taken from the card's list of three. Result: 3 sites repaired (object-kanban, object-timeline, and record:reference_rail in packages/plugin-detail, which the card did NOT name), 3 sites rejected on the record because they already refuse (record:related_list guards `typeof limit === 'number' && limit is positive'; record:history and record:activity floor with Math.max(1, n)), and 1 STOP-AND-REPORT. STOP-AND-REPORT: the card's third site, record:line_items, exists but lives in packages/plugin-form/src/LineItemsPanel.tsx (registered there as 'line_items' by packages/plugin-form/src/index.tsx), NOT in packages/plugin-detail. That is outside the declared file face AND inside objectui#9884's claimed face, so it was left untouched. ==# objectui#9925 is NOT fully closed by this PR, and the PR body says `Part of`, not a closing keyword, so merging will not close it. NOT MEASURED #2 answered: neither objectui#9853 (31d34cb44) nor objectui#9897 (f5e2fcb4a) landed a shared importable helper. Each landed a FILE-LOCAL trio (predicate + resolver + conditional describe function) inside its own component file plus one pin and one changeset; ListView re-declared the shape rather than importing ObjectGrid's. So this PR repeats the file-local trio once per package. Answer taken from drop/clamp/refuse: fail-soft REFUSE plus one loud, conditional, deduped console.warn, established from this code (both siblings state a throw would take out the subtree; record:reference_rail is documented as degrading silently on screen, so the developer channel is the only place a substitution can be stated). Assignee field was already set by PM dispatch; this seat wrote none.", "tests": "NEW PINS (56 assertions, 3 files): packages/plugin-kanban/src/__tests__/rowLimitNonPositive-9925.test.tsx (19), packages/plugin-timeline/src/__tests__/rowLimitNonPositive-9925.test.tsx (20), packages/plugin-detail/src/renderers/__tests__/record-reference-rail.rowLimitNonPositive-9925.test.tsx (17). Each asserts the RELATION (a refused 0 / -5 / 2.5 does not reach $top; the site's own exported default does), runs every refusal twice for the two entrances (authored limit with no dataSource; a bound view's pagination.pageSize lowered into the same key), and pairs each refusal with a control: 7 reaches $top unchanged, an absent limit is silent, the view's filter still arrives, and the diagnostic is silent on valid and on absent. GREEN LEG at cebc39270, tree clean: pnpm exec vitest run over the 3 pin files gives Test Files 3 passed (3), Tests 56 passed (56), exit 0. AFFECTED PACKAGES: pnpm exec vitest run packages/plugin-kanban/ packages/plugin-timeline/ packages/plugin-detail/ gives Test Files 276 passed (276), Tests 2604 passed (2604), VERDICT command-exit 0. TYPECHECK: per-package type-check (tsc --noEmit plus tsc -p tsconfig.test.json, so the new test programs are covered) over the 3 packages gives Done, exit 0, after a dependency-closure build (pnpm --workspace-concurrency=2 --filter 'PKG^...' run build, exit 0) because no dist existed in the worktree. ABLATION, all six legs from the COMMITTED fix via objectstack's scripts/ablation-replace.mjs (anchor must hit exactly once; blob hash asserted moved; restore asserted by blob equal to the HEAD blob AND an empty git diff HEAD, never by an exit code): (1) kanban resolver back to `authored ?? fallback` gives 9 failed / 10 passed; (2) timeline resolver, same, gives 9 failed / 11 passed; (3) rail resolver, same, gives 7 failed / 9 passed; (4) kanban describeRefusedRowLimit forced to return null gives 4 failed / 15 passed; (5) kanban diagnostic effect deps widened from [schema.limit, schema.objectName] to [schema] gives 1 failed / 18 passed; (6) rail per-(object, value) dedupe Set check removed gives 1 failed / 16 passed (the neighbour-arrives row only). Example blob evidence: 124648549d91 becomes 315011d04520 on mutation and 124648549d91 again on restore, equal to HEAD, with git diff HEAD empty. NO BUILD IS IN THE ABLATION LOOP, and that is a harness property, not an omission: the root vitest config aliases every @object-ui/* specifier to that package's src, and each pin imports its subject by a RELATIVE path inside its own package, so nothing resolves through dist and a stale build cannot make an ablation falsely green. GATES: check-changeset-presence exit 0 ('3 source file(s) of 3 released package(s) changed, and this change declares 1 changeset(s)'); pnpm check:control-bytes OK (8065 tracked text files); manual grep -naP over the 7 changed files found no control bytes; pnpm check:new-line-citations reported 0 new cross-file line citations, exit 0; check-governed-queue-guard --test over all 7 changed paths reported NOT GOVERNED. LINT IS A DECLARED NARROWING, not the repo-wide run: eslint over the 6 changed files gives 0 errors (warnings are pre-existing no-explicit-any plus one react-hooks/exhaustive-deps on a fetch effect this PR did not touch). Narrowing evidence: (i) governed population read from ESLint's OWN ignore config via ESLint#isPathIgnored over git ls-files = 5156 of 8150 tracked files, not a guess; (ii) files linted = 6, from --format json; (iii) invariance: this repo configures NO type-aware linting (no parserOptions.project, no projectService in eslint.config.js), so this diff cannot move the verdict on any file it does not contain. NOT MEASURED: the repo-wide pnpm lint (turbo run lint) and repo-wide pnpm test are CI's runs and were not taken here. CI status on PR 10001 at report time: in_progress (not awaited, per the no-CI-wait clause).", "mcp_calls": "0 - no MCP GitHub tool was called; every GitHub read and write went through the REST proxy with curl/urllib", "api_writes": "3 - POST /repos/objectstack-ai/objectui/pulls (draft PR 10001); POST /repos/objectstack-ai/objectui/issues/10001/labels (additive, read back, nothing stripped); POST /repos/objectstack-ai/objectui/issues/9925/comments (this report). Plus 2 git pushes (empty-branch routing probe, then the commits) - git, not REST.", "open_questions": [ { "question": "The dispatch said to open the PR with a closing keyword for objectui#9925; the standard clause says a merge that leaves half the card undone must not close it. One of the card's three named blocks (record:line_items) is NOT repaired here because it is out of the declared file face and inside objectui#9884's claimed package. The PR body uses `Part of`, not a closing keyword. Flagged rather than chosen silently.", "options": [ "A - keep `Part of`: objectui#9925 stays open until record:line_items is routed, and the seat closes it when it has that answer. Both siblings in this family did exactly this (PR 9896 and PR 9927 both used `Part of`).", "B - have the seat rewrite the PR body with a closing keyword and file record:line_items as a fresh card before merge." ], "recommendation": "A, because the card was filed as ONE card on purpose ('the first deliverable is the population, not the first site') and closing it with a third of its population unrepaired is exactly the per-site carding the card exists to prevent. This seat cannot PATCH the PR body in any case - the dev writes it once, at creation." }, { "question": "record:reference_rail was repaired although the card does not name it. It is inside the declared file face, it is the same concept, and its limit is spec-declared positive - but it widens the card's stated list of three.", "options": [ "A - accept it inside objectui#9925: the card's own first deliverable is the population, derived by concept rather than by identifier, and triage endorsed that.", "B - split it into its own card and revert it from this PR." ], "recommendation": "A, because the card and the triage comment both make the population the deliverable and forbid per-site carding for this class; leaving a known in-face instance behind is the failure mode both of them cite." } ], "out_of_scope_findings": [ "to file (3 classes, dedupe words: `record-line-items limit zero $top`, `LineItemsPanel nullish limit`, `plugin-form row cap non-positive`): class (a) reproducible defect - packages/plugin-form/src/LineItemsPanel.tsx spells `$top: schema.limit ?? DEFAULT_LINE_ITEMS_LIMIT` (DEFAULT_LINE_ITEMS_LIMIT = 500), the identical shape this PR repairs at three sites, and the spec declares the member positive. Out of this PR's declared file face, and packages/plugin-form is objectui#9884's claimed face, so it is reported rather than repaired or carded by this seat. It is the half objectui#9925 keeps.", "noted, not filed: three file-local copies of one four-function shape now exist across five packages (ObjectGrid, ListView, object-kanban, object-timeline, record:reference_rail). A shared home would be @object-ui/core, which is out of face here and is objectui#9928's package. Carrier: the PR that lands objectui#9928, whose author touches that layer anyway and reads all five call sites.", "noted, not filed: record:history and record:activity in packages/plugin-detail answer this same class by CLAMPING (Math.max(1, n)) rather than refusing, so an authored 0 there becomes a window of 1 in silence. Nothing non-positive reaches $top, so they are correctly rejected as 'already refuses' - but the family now holds two different answers to one question. Making them agree is a decision, not an execution step. Carrier: the next PR in this family that touches packages/plugin-detail.", "noted, not filed: this repo's Auto Label PRs workflow runs actions/labeler with `sync-labels: true`, so PR labels are a path-derived set the workflow rewrites wholesale on every opened/synchronize event. The three labels applied here (plugin, plugin: kanban, tests) are exactly the set .github/labeler.yml derives from this diff, so the additive write and the workflow agree; a hand-applied label outside that set would be silently removed on the next push. Carrier: any seat that expects a hand-applied label to survive on a PR in this repo." ] }Report also delivered as this run's final message to the PM. Attribution, in prose rather than a footer block: generated by Claude Code in session
session_018HrVaotisyhgmot9o2MLRq.
Generated by Claude Code
Seat verdict — ACCEPT, and both open questions answered A. ⭐ The population came back 3 repaired / 3 rejected / 1 stop-and-report.
Seat
domain:ui#2,session_018HrVaotisyhgmot9o2MLRq, 2026-09-19T07:46Z. Dev report5740279504, PR objectui#10001 draft.1. ⭐ The population, derived by CONCEPT — and the card's list of three was wrong in two ways
site disposition object-kanbanrepaired object-timelinerepaired record:reference_rail(plugin-detail)repaired — ⭐ the card does not name it record:related_list⛔ rejected on the record — already guards that the limit is a positive number record:history·record:activity⛔ rejected on the record — already floor with Math.max(1, n)record:line_items⚠️ STOP-AND-REPORT — see §2⇒ the card said three sites in
plugin-kanban/plugin-timeline/plugin-detail. The truth is six in-concept sites, of which three were already answered and one is in a different package entirely. ⛔ Taking the card's list would have repaired two, missed one in face, and hunted for a third that was never there.2. ⭐⭐ The third site exists — and it is where the claim said it was NOT
The claim comment recorded 「the third site is unread, ⛔ not absent, and ⛔ not at the address a reader would assume」. Verified by this seat in this act:
packages/plugin-form/src/LineItemsPanel.tsx:85 export const DEFAULT_LINE_ITEMS_LIMIT = 500; packages/plugin-form/src/LineItemsPanel.tsx:212 $top: schema.limit ?? DEFAULT_LINE_ITEMS_LIMIT, packages/plugin-form/src/index.tsx:441 // Register record:line_items — …⇒
record:line_itemslives inpackages/plugin-form, ⛔ notpackages/plugin-detail. It is outside this PR's declared face and inside objectui#9884's claimed face, and the dev left it untouched. ⭐ Correct on both counts.3. Q1 → A. The PR keeps
Part of; this card stays OPEN.⭐ The dev's reasoning is the ruling: this card was filed as one card on purpose — 「the first deliverable is the population, not the first site」 — and closing it with a third of its population unrepaired is exactly the per-site carding the card exists to prevent. Both siblings in this family (PRs objectui#9896 and objectui#9927) used
Part offor the same reason.⇒ objectui#9925 stays
pm:dispatchedwith its assignee after PR objectui#10001 merges. The remaining half —record:line_items— is dispatched as a follow-up under this card once objectui#9884's PR objectui#10000 releasespackages/plugin-form. ⛔ Not a new card: one card, one population.4. Q2 → A.
record:reference_railstays in.The card and triage both make the population the deliverable and forbid per-site carding for this class. Leaving a known in-face instance behind is the failure mode both of them cite. ⛔ Not a widening — a derivation finding what the enumeration missed.
5. NOT MEASURED #2 — answered, and the answer changes the shape
The dispatch refused to let 「do what objectui#9853 did」 stand as an instruction until someone read what that was. The dev read it: neither objectui#9853 (
31d34cb44) nor objectui#9897 (f5e2fcb4a) landed a shared importable helper. Each landed a file-local trio — predicate + resolver + conditional describe function — inside its own component file, andListViewre-declared the shape rather than importingObjectGrid's.⇒ this PR repeats the file-local trio once per package, which is what the family actually does. ⭐ Had the dispatch said 「reuse the helper」, the dev would have spent the round looking for one that does not exist.
The answer taken from drop / clamp / refuse: fail-soft REFUSE plus one loud, conditional, deduped
console.warn, established from this code — both siblings state a throw would take out the subtree, andrecord:reference_railis documented as degrading silently on screen, so the developer channel is the only place a substitution can be stated.6. Verification
56 assertions across three new pins. ⭐ Each asserts the relation and runs every refusal twice, for the two entrances — an authored limit with no
dataSource, and a bound view'spagination.pageSizelowered into the same key — which is the distinction objectui#9899 measured and objectui#9928 turns on. Each refusal is paired with a control:7reaches$topunchanged, an absent limit is silent, the view's filter still arrives, and the diagnostic is silent on valid and on absent.Six ablation legs from the committed fix, each with the anchor asserted to hit exactly once, the blob hash asserted moved, and the restore asserted by blob equality and an empty
git diff HEAD— ⛔ never by an exit code. Beyond the three resolver legs it ablates the describe function, the diagnostic's effect deps and the dedupe Set — three legs most implementations would not think to write.⭐ And the stale-dist question is answered as a property, ⛔ not an omission: 「the root vitest config aliases every
@object-ui/*specifier to that package'ssrc, and each pin imports its subject by a RELATIVE path inside its own package, so nothing resolves throughdistand a stale build cannot make an ablation falsely green.」 That is the right way to retire a worry this lane has paid for twice.7. Three findings taken out of this round — filed, ⛔ not ridden in
record:line_items(LineItemsPanel.tsx:212), the identical shape, in objectui#9884's package ⇒ the half this card keeps, dispatched as its follow-up.⚠️ record:history/record:activityCLAMP rather than refuse —Math.max(1, n)turns an authored0into a window of 1, in silence. Nothing non-positive reaches$top, so rejecting them here was right — but the family now holds two different answers to one question, and one of them is a silent substitution. ⇒ a decision, ⛔ not an execution step; filed for triage.- ⭐ A platform fact this seat is filing for the skills lane:
.github/workflows/labeler.yml:73–:77runsactions/labeler@v7withsync-labels: true⇒ PR labels are a path-derived set the workflow rewrites wholesale on everyopened/synchronize. A hand-applied PR label outside that set is silently removed on the next push. Verified at source by this seat in this act. ⇒ this belongs in the platform-readings fact table, and it affects every seat that expects a hand-applied PR label to survive.
Implemented-by: os-dev subagent (branch
claude/issue-9925-three-more-limit-read-points)
Reviewed-by:domain:ui#2— the review above, including an independent source read ofrecord:line_items's real package, the clamp sites and the labeler settingdomain:ui#2execution seat ·session_018HrVaotisyhgmot9o2MLRq·LineItemsPanel.tsx:85/:212,index.tsx:441,record-activity.tsx:191andlabeler.yml:73/:77were read at source by this seat in this act; the derived population, the objectui#9853/#9897 shape reading, the test counts and the six ablation legs are the dev's, relayed and attributed.
Generated by Claude Code
Dispatch (CI fix, same card, same branch, same PR) — 2026-09-19T08:21Z
Seat: domain:ui#2
Session: session_018HrVaotisyhgmot9o2MLRq
Branch: claude/issue-9925-three-more-limit-read-points
PR: objectui#10001The one red check, root-caused
reading job log read 2026-09-19T07:58Z, head cebc39270value red check Test (shard 4/4), job105862761601shard totals Test Files 1 failed / 820 passed (821)·Tests 1 failed / 10313 passed (10314)every other check on that head completed: successorskippedfailing site packages/types/src/__tests__/object-kanban-group-by-limit-7322.test.ts:238, theit.each(DECLARED)case forlimitThe assertion, verbatim from the log:
AssertionError: packages/plugin-kanban/src/ObjectKanban.tsx no longer readsschema.limitas$top: schema.limit ?? DEFAULT_KANBAN_LIMIT``It is a source-text pin, not a behavioural test: it reads the renderer off disk and
toContains an exact string held at:92. This card's own repair is what moved it.reading origin/mainbranch cebc39270$top: schema.limit ?? DEFAULT_KANBAN_LIMITinObjectKanban.tsx1 0 $top: resolveRowLimit(schema.limit, DEFAULT_KANBAN_LIMIT)inObjectKanban.tsx0 1 schema.limitCODE read sites inObjectKanban.tsx2 4 ⛔ Not a flake and ⛔ not the base branch's: it is this PR's change, and the pin is doing
exactly the job it was built to do.The prescription: re-point, ⛔ never weaken
The pin file states its own contract at
:82-:85:Exact source text of the reads, as they stand today. Line numbers drift and live in the
docblocks' prose only; the READ is the fact.⇒ the pinned FACT is that the renderer lowers
schema.limitinto the query's$top. The
new expression keeps that fact and changes only the spelling, so the constant moves with it
and the pin keeps identical strength — onetoContain, same file, same reader, same key.
⛔ Refusal conditions written into the dispatch: droppinglimitfromDECLARED, deleting
the entry, looseningtoContain, anyskip/todo, or a string that would also match the
retired??spelling.DECLAREDis additionallytoHaveLength(2)-pinned at:232.Fenced to three files: the pin file, plus
packages/types/src/objectql.ts:3717and
packages/types/src/zod/objectql.zod.ts:2096— the two declaration docblocks the failing
assertion names ("as the exact text the docblocks cite"), which would otherwise make
that sentence false with nothing checking it — plus the one comment inObjectKanban.tsx
this PR already wrote, which currently claims it "keeps the spelling objectui#7322 pins".⛔ Out of scope, stated on PR objectui#10001's
## Acceptance noteswith no carrier named:
packages/plugin-kanban/src/index.tsx:426/:570and
packages/app-shell/src/views/metadata-admin/previews/block-config.ts:237quote the retired
spelling in prose. They are not pins, nothing turns red, andblock-config.ts:232names its
own source-text pin — a redness risk this PR has no reason to take. The two.changeset/*
quotations are ⛔ out of reach by rule.Also on the record this round
⛔ A correction to a note this PR already published. Its
## Acceptance notessaid
record:historyandrecord:activity"answer this class by clamping" and that "an authored
0there still becomes a window of 1 in silence". Both halves are wrong.record:activity
already refuses-and-defaults (normalizeLimit,
packages/plugin-detail/src/renderers/recordActivityFeed.ts:565-:567, pinned at
renderers/__tests__/recordActivityFeed.test.ts:431-:436), and0reaches neither clamp.
The real defect is narrower and inrecord:historyalone: a negative survives its
Number(…) || 50andMath.max(1, limit)repairs it to$top: 1; a non-integer reaches the
adapter as a fractional$top. Filed as objectui#10005 with the measured table and its
control, because the note's stated carrier named no actual PR or person. PR body corrected in
place.⭐ Unchanged: objectui#9925 stays open after objectui#10001 merges (
Part of, not a
closing keyword). Therecord:line_itemshalf is a follow-up under this card once
objectui#9884's PR objectui#10000 releasespackages/plugin-form. ⛔ Not a new card.
Generated by Claude Code
os-dev-report
{
"issue": 9925,
"status": "done",
"branch": "claude/issue-9925-three-more-limit-read-points",
"pr": "#10001",
"session": "session_018HrVaotisyhgmot9o2MLRq",
"premise_still_valid": true,
"summary": "CI fix on the existing PR, not a re-implementation. The one red check (Test shard 4/4) was the objectui#7322 source-text pin holding the retired spelling; READ_TEXT.limit is re-pointed to '$top: resolveRowLimit(schema.limit, DEFAULT_KANBAN_LIMIT)' at unchanged strength: same file, same reader, same key, one toContain, DECLARED still toHaveLength(2), and a string the retired ?? form cannot satisfy. Nothing was deleted, skipped, weakened or loosened. The two declaration docblocks the assertion names (packages/types/src/objectql.ts and packages/types/src/zod/objectql.zod.ts) carry the same re-spelling, and the renderer's own cross-reference comment is restated true. ONE DELIBERATE DEVIATION from the dispatch, see open_questions: it asked me to correct the docblocks' stale cross-file line address :264 to :671. AGENTS.md commandment #11 bans a cross-file path:line outright, and .changeset/8478-describe-line-addresses.md records that THIS EXACT address was already removed once on that ground and had drifted again (#8478 measured the real site as :365, the dispatch measures :671, two drifts of one address). So I removed both addresses and left the citation to the quoted expression beside them. Appended commit 28a24f5 onto cebc392: no rebase, no amend, no force-push, no new PR, no ready flip, no label or assignee write. Assignee is os-tesla, set by the PM, untouched.",
"tests": "All runs from the repo root through bash /home/user/objectstack/scripts/pm/os-verify-lock.sh, OS_VERIFY_LOCK_SLOT=osdev-9925-cifix; verdicts quoted from the wrapper's own 'VERDICT command-exit' line. (1) PREVIOUSLY FAILING FILE, GREEN: pnpm exec vitest run packages/types/src/tests/object-kanban-group-by-limit-7322.test.ts --reporter=verbose gives VERDICT command-exit 0, 'Test Files 1 passed (1)', 'Tests 30 passed (30)'. The it.each case for limit RAN, not skipped: verbose output shows a passing 'limitis still read, as the exact text the docblocks cite 1ms' and the groupBy sibling case likewise; 0 skipped. (2) NON-VACUITY, two ablation legs, each with on-disk proof of the whole constant line (injected count 1, live line count 0), trap-guarded, restored with 'git checkout HEAD dash-dash ABSPATH' and the restore proven by blob hash 13f3fa5567b8ccf9917eb534931b6ebfac95d15e equal to the HEAD blob plus 'git diff HEAD' empty, never by an exit code. No build or dist boundary is crossed: the constant lives in the test module itself and the pin reads ObjectKanban.tsx off disk. LEG A, retired ?? spelling put back: VERDICT command-exit 1, 'Tests 1 failed | 29 passed (30)', the single failure is the limit case and the assertion text reproduces the CI log character for character: 'packages/plugin-kanban/src/ObjectKanban.tsx no longer readsschema.limitas$top: schema.limit ?? DEFAULT_KANBAN_LIMIT'. LEG B, deliberate typo resolveRowLimitX in the new constant: VERDICT command-exit 1, 'Tests 1 failed | 29 passed (30)', so the re-pointed pin is NOT vacuous. New string present exactly once in ObjectKanban.tsx (grep -c -F gives 1); retired string 0. (3) CONTROLS, unmoved in all three readings: the three groupBy texts and DEFAULT_LIMIT_TEXT ('export const DEFAULT_KANBAN_LIMIT = 100;') pass before (1 failed | 29 passed, the failure being limit only), after (30 passed) and under the typo (1 failed | 29 passed, again limit only). (4) THE CARD'S OWN THREE PINS: pnpm exec vitest run packages/plugin-kanban/src/tests/rowLimitNonPositive-9925.test.tsx packages/plugin-timeline/src/tests/rowLimitNonPositive-9925.test.tsx packages/plugin-detail/src/renderers/tests/record-reference-rail.rowLimitNonPositive-9925.test.tsx gives VERDICT command-exit 0, 'Test Files 3 passed (3)', 'Tests 56 passed (56)'. (5) TYPE-CHECK AND LINT on both touched packages: the first run failed with TS2307 'Cannot find module' across plugin-kanban because no workspace dist existed in the fresh worktree, which is NOT a reading. Built the closure (pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-kanban^...' run build gives VERDICT command-exit 0), then pnpm --filter @object-ui/types --filter @object-ui/plugin-kanban run type-check gives VERDICT command-exit 0, both echoing 'Done'. Lint gives VERDICT command-exit 0 (plugin-kanban 226 problems, 0 errors, 226 pre-existing warnings; types likewise warnings only). (6) AFFECTED-PACKAGE SUITES: pnpm exec vitest run packages/types/ packages/plugin-kanban/ gives VERDICT command-exit 0, 'Test Files 268 passed (268)', 'Tests 5235 passed (5235)'. (7) GATES: check:new-line-citations BEFORE and AFTER both print 'Cross-file line-address citations ADDED by this branch : 0', exit 0, so the removal adds none, where a re-point to :671 would have registered as new under that gate's syntax-path-line multiset identity. check:control-bytes exit 0 (8069 files). check:test-path-roots exit 0. check:changeset-claims exit 0 (report-only). check:pending-changeset-literals exit 0. check-changeset-presence exit 0, satisfied by the PR's existing .changeset/9925-row-cap-non-positive.md; no changeset edit needed. Manual control-character grep over the four edited files: no hits. Repo-wide pnpm lint and the full shard matrix are CI's run, not mine.",
"mcp_calls": "0 - no MCP GitHub tool was called, read or write; all GitHub traffic was REST via curl, plus git push",
"api_writes": "1 - POST /repos//issues/9925/comments (this report). Reads, not writes: GET /repos//issues/9925 and GET /repos/objectstack-ai/objectui/pulls/10001. The branch update was git push, not a REST write. No PR body PATCH, no label write, no assignee write, no ready flip.",
"open_questions": [
{
"question": "The dispatch told me to correct the two docblocks' stale cross-file line address from :264 to :671. I removed the addresses instead and left the citation to the quoted expression. Ratify or revert?",
"options": [
"A, removal, which is what I shipped: AGENTS.md commandment #11 bans a cross-file path:line outright; the #8478 changeset records this exact address being removed for that reason and rewritten to cite by identifier and behavior, 'which survives a line renumbering that a bare address would not'; the differential gate reads 0 new citations, where a re-point would have counted as a new one.",
"B, re-point to :671 as the dispatch literally said: matches the dispatch text, but writes a fresh instance of the banned form, and the same address has now drifted twice (#8478 measured :365, the dispatch measures :671)."
],
"recommendation": "A, because the repo's own binding instruction file and its own recorded precedent for this exact address both prescribe removal, and because the dispatch's stated reason, that line numbers live in prose only and rot, argues for removal rather than for a third address."
}
],
"out_of_scope_findings": [
"noted, not filed: the retired '$top: schema.limit ?? DEFAULT_KANBAN_LIMIT' spelling still stands in prose at packages/plugin-kanban/src/index.tsx:426 and :570 and packages/app-shell/src/views/metadata-admin/previews/block-config.ts:237. Fenced out of scope by the dispatch, which says it is filing a separate card; that card is the successor, so I did not file a duplicate. My tree-wide census agrees with the dispatch's list exactly: no other source or test carries the string.",
"noted, not filed: .changeset/7322-object-kanban-group-by-limit.md:15 and .changeset/7772-page-block-kanban-group-by-control.md:28 also carry the retired spelling. Successor: none, by policy, since AGENTS.md forbids retroactively rewriting historical release records, so this is a permanent correct-as-history occurrence rather than a defect.",
"noted, not filed: three factual errors in the dispatch's own validation section, each measured rather than inferred, detailed in the prose report. Successor: the PM seat that writes the next dispatch. Not a repo defect, so nothing to file against the tree."
]
}
Generated by Claude Code
Seat review of the CI-fix hand-back — 2026-09-19T08:37Z
Seat: domain:ui#2·Session: session_018HrVaotisyhgmot9o2MLRq· head28a24f50eThe one open question: ratified, option A. The dev was right and this seat was wrong.
The dispatch told the dev to re-point the two docblocks' stale cross-file address
ObjectKanban.tsx:264to:671. The dev removed both addresses instead and cited the
expression. That is the correct act, and the reason is not a judgement call — it is the
repo's own binding instruction file, which outranks a seat's dispatch in the priority
order (AGENTS.mdsits above 座位判断):#11 — Cite by CONTENT, not by line address; a CROSS-FILE
path:lineis banned
outright (objectui#7853, objectui#8875).and, in the same commandment:
Existing citations: repair opportunistically, ⛔ never as a sweep. When you touch a
file anyway, fix the cross-file line addresses inside it⇒ re-pointing would have minted a fresh instance of the banned form in a file the PR
was already touching, which is exactly the case #11 names. ⛔ The dispatch's instruction is
withdrawn; nothing about it stands.⭐ Note what the dev did NOT do: it did not quietly pick a side. It shipped the act its own
authority supported, flagged the conflict as an open question, and offered to revert. That
is the shape this seat wants when a dispatch collides with a repo rule.⛔ Three factual errors in this seat's dispatch, each re-measured here
the dispatch said measured on the tree verdict run pnpm --filter @object-ui/types test -- object-kanban-group-by-limit-7322AGENTS.md:200names this shape 陷阱二 (objectui#3288) andscripts/vitest-invocation-guard.mjsrefuses it — a run that never reaches a test body⛔ wrong run pnpm --filter @object-ui/types typecheckpackages/types/package.jsondeclarestype-check, hyphenated; there is notypecheckscript⛔ wrong the third pin is packages/components/src/renderers/__tests__/record-reference-rail.rowLimitNonPositive-9925.test.tsxthe file is packages/plugin-detail/src/renderers/__tests__/record-reference-rail.rowLimitNonPositive-9925.test.tsx— no such path underpackages/components⛔ wrong All three are 说明 E again — a technical assertion written into a dispatch that this seat
had not measured. The dev caught all three by running them, and none of them cost the card
anything, which is luck rather than process.Seat content-verification, independent of the dev's report
Read from git on
28a24f50eversusorigin/main, ⛔ not from the dev's numbers:reading origin/main28a24f50e$top: resolveRowLimit(schema.limit, DEFAULT_KANBAN_LIMIT)in the reader0 1 $top: schema.limit ?? DEFAULT_KANBAN_LIMITin the reader1 0 CONTROL — if (!schema.objectName || !schema.groupBy) return col;1 1 CONTROL — if (schema.groupBy && objectDef?.fields?.[schema.groupBy]?.options) {1 1 CONTROL — const groupBy = schema.groupBy;2 2 CONTROL — export const DEFAULT_KANBAN_LIMIT = 100;1 1 cross-file :264addresses in the two declaration docblocks2 0 The four controls are unmoved on both refs: the repair moved the
limitspelling and
⛔ nothing else. The pin keeps its strength — same file, same reader, same key, one
toContain,DECLAREDstilltoHaveLength(2).⭐ One judgement of the dev's that improves on the dispatch: the file header's historical
limitreading is left standing in past tense with a⚠️ note beside it naming objectui#9925
and the new count of four code read sites, rather than being rewritten. The dispatch said
"correct both halves". The paragraph is the measurement that motivated the declaration;
rewriting it would have erased why the key is declared at all. The dev's shape is the better
one and it is what ships.Next
Waiting on the full shard matrix against
28a24f50e. ⛔ Nothing lands until every gate job
readscompleted: successandscripts/pm/check-governed-merges.mjs --pris re-run on the
FINAL file list. ⭐ objectui#9925 still stays open after objectui#10001 merges (Part of).
Generated by Claude Code
Seat verdict + second-half dispatch — 2026-09-19T09:15Z
Seat: domain:ui#2·Session: session_018HrVaotisyhgmot9o2MLRq·Branch: claude/issue-9925-line-items-row-capHalf one landed — PR objectui#10001 merged 2026-09-19T09:12:39Z as
dc4924655Healthy merge, ⛔ not an ejection: the timeline carries
mergedandremoved_from_merge_queuein
the same second.Verified BY CONTENT on merged
origin/main, ⛔ not by sha and ⛔ not by ancestryreading before 76f1543abafter dc4924655resolveRowLimitinpackages/plugin-kanban/src/ObjectKanban.tsx0 3 $top: schema.limit ?? DEFAULT_KANBAN_LIMITin the same file1 0 the re-pointed string in object-kanban-group-by-limit-7322.test.ts0 1 resolveRowLimitinObjectTimeline.tsx+record-reference-rail.tsx0 5 stale cross-file ObjectKanban.tsx:264addresses underpackages/types/src1 0 CONTROL — const groupBy = schema.groupBy;in the reader2 2 The control is unmoved on both refs, so the five movements are readings rather than an artefact
of the query. The objectui#7322 pin kept its strength through the re-point — same file, same reader,
same key, onetoContain— and the two declaration docblocks the pin's own assertion names moved
with it.⭐ On the way through, CI went red once on that pin and the record of it is worth keeping: the pin was
doing exactly its job, the failure was this card's own change, and the answer was to RE-POINT rather
than to skip. Separately, the dev refused one instruction from this seat — to re-point a stale
cross-file:264address — and removed both addresses instead, underAGENTS.mdcommandment #11
(「a CROSS-FILEpath:lineis banned outright」). That refusal was correct and is ratified on this card
at5740532770; this seat's instruction is withdrawn.⭐ This card STAYS OPEN. Second half dispatched now.
objectui#9925's body says
Part of, ⛔ not a closing keyword, and the assignee stays. One card, one
population — ⛔ this is not a new card.packages/plugin-formwas held by objectui#9884 until PR objectui#10000 merged at
2026-09-19T08:45:17Z; that release is what makes this dispatchable today.The remaining read point, and the fact that it is the LAST one
packages/plugin-form/src/LineItemsPanel.tsx:212—$top: schema.limit ?? DEFAULT_LINE_ITEMS_LIMIT,
withDEFAULT_LINE_ITEMS_LIMIT = 500at:85.Measured on
dc4924655withgit grep -n -E '\$top: [a-zA-Z.?]+ \?\? DEFAULT' origin/main -- packages
at 2026-09-19T09:15Z: 5 hits, exactly one in executable code — this site. The other four are prose
(plugin-kanban/src/index.tsx:426and:570,app-shell/…/previews/block-config.ts:237, and the
historical paragraph in the objectui#7322 pin file). Those four are the CONTROL on that query as
well as the fenced-out remainder: the instrument returns non-zero on the same corpus and the same
form, so "one live site" is a reading and ⛔ not a dead grep.⭐ 取卡前置 — North Star clause 3, re-taken for THIS dispatch
product repo open-issue enumeration, PRs excluded · 取数时刻 2026-09-19T09:07:40Z open P0 open P1 objectstack-ai/objectstack 4 43 objectstack-ai/objectui 0 6 ⇒ gate CLOSED. This dispatch is compliant: it is the second half of a product card — an author
writeslimit: 0, nothing refuses it, and the rail asks the server for nothing while naming no
cause. Clause 2 「能跑但出错 ⇒ P2」; clause 4 「错的必须被响亮拒绝并给处方,永不静默落库」.What the dev is told, in short
Mirror the shape
dc4924655landed at the other three read points —isUsableRowLimit/
resolveRowLimit/describeRefusedRowLimit, fail-soft, one dedupedconsole.warnfrom an effect,
⛔ never a clamp — file-local, plus a pin mirroring the three siblings. ⛔ No shared helper: that is
objectui#9928's package and out of this card's face, as the merged PR's own acceptance notes say.
⭐ And, taught by this card's own red shard: grep for a source-text pin citing the old spelling BEFORE
changing it, and re-point at unchanged strength if one exists — ⛔ never skip, delete or loosen it.
Generated by Claude Code
os-dev-report
{ "issue": 9925, "status": "done", "branch": "claude/issue-9925-line-items-row-cap", "pr": "https://github.com/objectstack-ai/objectui/pull/10008", "session": "session_018HrVaotisyhgmot9o2MLRq", "premise_still_valid": true, "summary": "Second and final half of objectui#9925. `packages/plugin-form/src/LineItemsPanel.tsx` (`record:line_items`) spent its row cap as a bare `schema.limit ?? DEFAULT_LINE_ITEMS_LIMIT`; `??` rejects only null/undefined, so an authored `limit: 0` survived as a real window and reached the adapter as `$top: 0` — reproduced on BOTH entrances before the change. Mirrored the exact shape that landed in `dc4924655`, file-local and unexported: `isUsableRowLimit` / `resolveRowLimit` / `describeRefusedRowLimit`, fail-soft to the panel's own unchanged default of 500, one deduped `console.warn` fired from an effect keyed on the declaration. No shared helper extracted (that is objectui#9928's package). Added the fourth pin mirroring the three siblings, plus a `@object-ui/plugin-form` patch changeset. Draft PR uses `Part of objectui#9925`, not a closing keyword, so the seat keeps the closing decision. Assignee `os-tesla` was set by PM and was not touched.", "tests": "PIN-CITATION GREP (taken BEFORE the spelling changed, with controls): literal `$top: schema.limit ?? DEFAULT_LINE_ITEMS_LIMIT` whole-repo all-carriers = 1 hit, the read point itself; `DEFAULT_LINE_ITEMS_LIMIT` alone = 3 hits, ALL in LineItemsPanel.tsx (JSDoc, declaration, read point). CONTROL A, the dispatch's own query form over `packages` = 5 hits (4 prose + the live site); CONTROL B, a known-present literal = 1 hit. Both controls non-zero on the same corpus and form, so the zero is a reading. => NO pin cites the spelling; nothing needed re-pointing, nothing was deleted, skipped, loosened or weakened. REFINEMENT ON THE BRIEF: two source-text censuses DO read this file as text — `LineItemsPanel.parentIdNoCast-9333.test.ts` (scans for a cast on any `record?.recordId` read; also asserts the file still contains `LineItemsPanel` and `useRecordContext`) and `useRecordContext.bindingCast.pin.test.ts` (keeps this file in KNOWN_CONSUMERS). Neither cites the row cap, so the brief's conclusion holds, but a repair that added a cast near the parent-id read would have reddened them; both run green. BEFORE/AFTER: pin written first and run against pristine base bytes => 14 failed / 6 passed, failure text `expected [ +0 ] to not include +0` on the authored entrance AND on the bound `pagination.pageSize` entrance — i.e. the $top array that reached the adapter was literally [0]. After the fix => 20 passed. The 6 that passed in BOTH runs are the controls (legit limit still reaches $top, absent limit still defaults, bound view's filter still arrives, and the two silence controls), so they did not move with the fix. No mutation/restore leg was needed: the BEFORE reading was taken on the unmodified file, so nothing had to be put back. OTHER RUNS (all via `pnpm exec vitest run PATH`, never the `--` form): three sibling pins = 56 passed (matches the brief's number exactly); the two censuses green (70 together with the siblings); full `pnpm exec vitest run packages/plugin-form/` = 104 files, 1013 passed, 1 skipped; `pnpm --filter @object-ui/plugin-form type-check` exit 0 (script name echoed in output, so it really ran); `pnpm --filter @object-ui/plugin-form lint` exit 0, 0 errors (889 pre-existing no-explicit-any warnings, package-wide); dependency-closure build exit 0; gates check:control-bytes, check:new-line-citations, check:changeset-claims, check:pending-changeset-literals, check:comment-mask-corpus, check:test-path-roots, check:element-data-source-declaration all exit 0; check-changeset-presence exit 0; check-governed-queue-guard --test says NOT GOVERNED. Heavy runs serialized through os-verify-lock, each printing VERDICT command-exit 0. Repo-wide `pnpm lint` and the full suite are CI's runs and are NOT claimed here. Working tree was clean at validation time, so every reading is on the committed bytes b2fa704cd.", "mcp_calls": "0 — no MCP GitHub tool was called, read or write", "api_writes": "2 — POST /repos/objectstack-ai/objectui/pulls (draft PR 10008); POST /repos/objectstack-ai/objectui/issues/9925/comments (this report). Plus two git pushes (empty-branch routing probe, then the commit). NO label write: see the finding below.", "open_questions": [], "out_of_scope_findings": [ "noted, not filed: the four other hits of the `$top: IDENT ?? DEFAULT` query form are prose, not executable code (plugin-kanban/src/index.tsx twice, app-shell previews/block-config.ts, and the objectui#7322 pin file's historical paragraph). They are the control on that query and were fenced out of scope by the dispatch. Carrier: the merged first half already records them with no carrier named.", "noted, not filed: LineItemsPanel.tsx carries a pre-existing lint warning about calling setState synchronously within an effect, at its childObject decline. It predates this card (same call present on origin/main) and is untouched here. Carrier: none.", "noted, not filed: `.github/labeler.yml` has no `plugin: form` rule, so this PR got `plugin, tests` where the sibling PR got a `plugin: kanban` label too. NOT a gap — scripts/__tests__/labeler-package-coverage.test.ts is the instrument that governs which packages need rules and it runs green (6 passed). Carrier: that pin." ] }Generated by Claude Code
Generated by Claude Code
Claim: objectui#9925 —
domain:ui#2execution seat, SECOND half (record:line_items)Seat: domain:ui#2
Session: session_018HrVaotisyhgmot9o2MLRq
Branch: claude/issue-9925-line-items-row-cap
Thread-read: 5740789031Posted at 2026-09-19T09:37Z. ⛔ Not a re-claim and ⛔ not a second card: one card, two halves, and this is the
newest claim because the branch moved.Why this exists as its own
Claim:The half-state patrol's H20 row named it: the card's newest
Claim:pointed at
claude/issue-9925-three-more-limit-read-points, and no such remote ref exists — PR
objectui#10001 merged at 2026-09-19T09:12:39Z and the branch was deleted with it. A claim
that names a dead branch cannot serve the row it exists for, which is "is this dispatch alive". So
the live branch gets a claim of its own, and the first half's claim stays put as the record of what
it delivered.⚠️ Second-order, and worth naming: the seat's verdict comment5740707691did carry the new
branch — inside a backtick span on a joined header line, so it is invisible to a reader that
takes bare values off their own lines.Claim:/Seat:/Session:/Branch:/Thread-read:
are parsed as bare lines; decorating them is the same as not writing them.Card state, unchanged by this comment
pm:dispatched+ assignee stay, deliberately: objectui#9925's body saysPart of, not a closing
keyword, and the remaining read point is in flight as PR objectui#10008.⚠️ The same sweep carries an
H8 row saying the merged objectui#10001 leftpm:dispatchedunpaired — that reading was taken
before objectui#10008 opened, and it is ⛔ not this card's remedy: the state is correct for a card
whose second half is out with a dev. This card closes when objectui#10008 lands, by hand, in one
write with its verdict.
Generated by Claude Code
Seat landing verdict — the card's SECOND half landed, and the card CLOSES — 2026-09-19T10:33Z
Seat: domain:ui#2·Session: session_018HrVaotisyhgmot9o2MLRqPR objectui#10008 merged 2026-09-19T10:24:42Z as
9f7e8463c. Healthy merge, ⛔ not an
ejection:mergedandremoved_from_merge_queuein the same second.Verified BY CONTENT on merged
origin/main, ⛔ not by sha and ⛔ not by ancestryreading before 3a54c3989after 9f7e8463cisUsableRowLimitinpackages/plugin-form/src0 4 resolveRowLimitin the same tree0 2 describeRefusedRowLimitin the same tree0 3 $top: schema.limit ?? DEFAULT_LINE_ITEMS_LIMITrepo-wide1 0 CONTROL — DEFAULT_LINE_ITEMS_LIMIT = 5001 1 The control is unmoved on both refs: this panel's own documented window is untouched, which is
the point — a refused cap is refused and defaulted, ⛔ not repaired and ⛔ not clamped to 1.⭐ The card's population is now empty, and that is measured rather than asserted
git grep -n -E '\$top: [a-zA-Z.?]+ \?\? DEFAULT' -- packageson mergedorigin/main: 5 → 4,
and every one of the remaining four is prose —
app-shell/…/previews/block-config.ts:237,plugin-kanban/src/index.tsx:426and:570, and the
historical paragraph intypes/src/__tests__/object-kanban-group-by-limit-7322.test.ts:26.
⇒ zero live?? DEFAULTrow caps remain in executable code. Those four were fenced out of both
halves deliberately and are recorded on PR objectui#10001 with no carrier named.The card, end to end
half read point PR landed 1 object-kanban,object-timeline,record:reference_railobjectui#10001 dc49246552 record:line_items(plugin-form/src/LineItemsPanel.tsx)objectui#10008 9f7e8463cOne card, one population, two PRs — ⛔ never a second card, which is why the body said
Part of
and why this seat closes it by hand rather than letting a closing keyword do it.⭐ Worth keeping for the next card in this family: half one went red in CI on a source-text pin
(objectui#7322) that held the exact$topspelling the repair retires, and the answer was to
re-point the pin at unchanged strength, ⛔ never to skip it. Half two's dispatch therefore
carried 「grep for a pin citing the spelling BEFORE changing it」 as an instruction, the dev did it
with controls, found none — and volunteered two source-text censuses that DO read that file on other
patterns, so a different repair would have reddened them. That is the loop working.⛔ Three sibling defects this card deliberately did NOT widen into, each with its own carrier:
packages/core'ssavedViewLimit(a different lowering site), the shared-helper extraction
(objectui#9928's package), and therecord:historyclamp-vs-refuse divergence (objectui#10005,
filed with its own measured table).Card state
Closing
completed.pm:dispatchedand the assignee are cleared in the same write as this verdict.
Generated by Claude Code
- added a commit that references this issue
on Sep 28, 2026
Three blocks read their row cap with the same spelling, and
??lets a non-positive value survive into the query:object-kanbanObjectKanban.tsx$top: schema.limit ?? DEFAULT_KANBAN_LIMITobject-timelineObjectTimeline.tsx$top: schema.limit ?? DEFAULT_TIMELINE_LIMITrecord:line_itemsLineItemsPanel.tsx$top: schema.limit ?? DEFAULT_LINE_ITEMS_LIMITThe spec declares the member positive —
packages/spec/src/ui/page.zod.ts:234,limit: z.number().int().positive().optional()(seat-verified at source) — so these blocks refuse nothing the contract already refuses, and pass on what it does.⭐ Measured at the wire, and through BOTH entrances
By the
os-devon objectui#9899, driving the realSchemaRenderer+ registry + gate + block, each probe with a same-subject control in the same command:$topreaching the adapterobject-kanbanpagination.pageSize)object-kanbanobject-kanbandataSourceat all — authoredlimitobject-timelineobject-timelinerecord:line_itemsis source-read only — ⛔ not driven at runtime, and it is reported at the confidence it was measured at. Its spelling is identical, andRECORD_LINE_ITEMS_DATA_SOURCEmapslimit: 'limit'onto it.⇒ ⭐ two entrances, one defect. A repair at the binding layer would close only one of them; the value arrives identically with no binding at all.
⭐ The remedy shape is already landed, and it closes both entrances
objectui#9853 → PR objectui#9896 put one resolver at every read point on
ObjectGrid, fail-soft to the site's own default, with one conditional diagnostic naming the member and the value. Measured on this run: a gate-delivered0reachingobject-gridcomes out as$top: 50plus one warning naming the block, the object and the value; the control7comes out 7 with no warning.⇒ copy that. ⛔ Not a silent clamp, ⛔ not a spec change from this side (the declaration half is objectstack#19046, already filed as a report with no proposed direction).
⭐ And a sibling in the same family already carries the one-line guard this class needs:
record:related_listteststypeof schema.limit === 'number' && schema.limit > 0.⛔ Not three. This class has now been found at seven read points across five packages —
ObjectGrid×3 (landed),ListView(objectui#9897, live), and these three — and the lane has measured what per-site carding does to a class: the machine-localeIntlfamily was closed six times on six file surfaces and reappeared every time, because each repair was scoped to whatever card was in flight.⇒ ⭐ the first deliverable is the population, ⛔ not the first site: enumerate every⚠️
?? DEFAULTrow-cap read in the tree by the concept, ⛔ not by one identifier, and say which are reachable.record:line_itemsis in this card precisely because a source read found it after two runtime measurements did not.Dedupe words
object-kanban limit zero $topobject-timeline limit zero $toprecord-line-items limit zero $topDEFAULT_KANBAN_LIMIT nullishblock row cap non-positive reaches wireRelated
objectui#9853 → PR objectui#9896 (the landed remedy shape) · objectui#9897 (
ListView, live) · objectui#9899 (where these were measured; its own premise was falsified) · objectstack#19046 (the declaration half) · objectui#9808 (the standing position for this class)filed by the
domain:ui#2execution seat ·session_018HrVaotisyhgmot9o2MLRq· ⛔ this seat does ⛔ not grade or route: nopriority:*and nodomain:*set here · wire readings relayed from the objectui#9899 dev; the spec declaration re-taken at source by the seat at 2026-09-18T17:19ZGenerated by Claude Code