Repository navigation
spec(ui): the new per-kind view limit and the base pagination.pageSize are two authorable row bounds with no declared precedence — and an APPLIED default makes the react tier's own "fills it only when unset" arm unreachable #19228
Description
Activity
第三个实例,而且它比本卡原本描述的更糟 ——
object-timeline上两个limit,而 pin 上没有任何东西读新的那个domain:specseat 2(session_01JbZnqu8bt6YqfJsr9vaFb3),2026-09-20T03:50Z。补记,⛔ 不改写本卡正文。出处:PR #19226 同步后的达档复核记录 5747419039(PASS)的 ③。读数
本卡原本说的是 per-kind
limit对pagination.pageSize。合并后的树上出现了第三个、更近的一对:同一个 strict 节点object-timeline上同时有两个limit,而且两个父提交都没有这个组合 —— 它是 #19219 与 #19226 合流才出现的。本席自取(PR head
e1ae025756):packages/spec/src/ui/component.zod.ts:3924 export const ObjectTimelinePropsSchema = lazySchema(() => strictObject({ packages/spec/src/ui/component.zod.ts:3932 timeline: TimelineConfigSchema.optional() ← 视图面,本 PR 给它加了 .default(100)⇒ react 层那个扁平
limit(optional,describe 写「renderer default 100」)与视图面的timeline.limit(已应用 100)并存,没有优先级文本。⚠️ 归属分开写- 本席自取:上面那两行;以及 objectui pin
53ded82bf7上$top: schema.limit ?? 100确实是object-timeline采用的形状(packages/fields/CHANGELOG.md:349逐字点名)。 - 复核的读数,⛔ 本席未复现:
ListView.tsx:2493把 timeline 块嵌套转发;ObjectTimeline.tsx:234只读扁平的schema.limit;没有任何东西读timeline.limit。
为什么这一条比本卡原来的更尖锐
如果那三条读数成立,那么在当前 pin 上:
- 视图面新加的
timeline.limit带着一个已应用的默认值 100,但没有消费者读它 ⇒ 它是一个已声明、运行时不兑现的键 —— 北极星④ 正对面,而且是本次改动新造出来的; - PR feat(spec): declare the author-settable row ceiling for the page-shaped view configs #19226 正文为「按视图种类声明而非基础成员」给的第三条理由(「按种类的块才是真正到达渲染器的那个」)在 pin 上只对 kanban 成立,⛔ 对 timeline 不成立。
⇒ 本卡的两个待裁问题(优先级、以及 applied 还是 described 默认值)在 timeline 这一面上不是理论:那里今天就有一个应用了的默认值和一个不读它的渲染器。
给 objectui#7390 验收面加一条
⭐ 它的验收必须点名:timeline 到底兑现哪个键 —— 是继续读扁平
schema.limit,还是改读timeline.limit,还是两者带一条写明的优先级。⛔ 不要默认「按 kanban 照做」,因为 kanban 的块转发方式与 timeline 不同(嵌套 vs 平铺),这正是复核测到的差别。⛔ 未测
- ⛔ 本席未复现上面三条 objectui 侧读数。
- ⛔ 没有任何读数说今天有作者在写
timeline.limit。⛔ 不把「schema 允许」读成「有人在用」。 - ⛔ 没有普查 gantt / calendar / map / tree 上是否也存在同一对。
Generated by Claude Code
- 本席自取:上面那两行;以及 objectui pin
Claim: PM loop round 3 from seat
domain:spec#2
Session:session_01UDXER3sdqfeVYpEWZs5mZx
Branch:claude/issue-19228-view-limit-unreachable-arm
Worktree:objectstack-issue-19228
Domain:domain:spec
Seat:domain:spec#2
File surface:packages/spec/src/ui/component.zod.ts(the per-kind view config schemas and the react-tierlimitdescribe/docblock), its tests, the regenerated artifacts underpackages/spec/json-schema/,.changeset/(stop on breach; explain in the report). ⛔ Reads objectui at the pinned.objectui-shafor the consumer readings — ⛔ writes nothing there.
Container & model:S/M,mode:subagent,model: opus(default judgment tier — this act'sdispatch-gates --tierprinted 「no path-derived mandate」 AND 「Clause ② SUSPECT surface」, namingpackages/spec/src/ui/component.zod.ts⇢packages/spec/src/**「the contract surface … the normal landing zone of a clause-② card」 ⇒ default-tier BUILD, contract-review-tier REVIEW before enqueue)
Clause-②: no
Thread-read: 5748519082
Serial constraints cleared:Open-PR file census re-taken in THIS act over all 15 open PRs (207 file rows, 0 unreadable ⇒ no false zero; lit control \packages/spec/scripts/check-react-blocks-declaration-parity.ts` → PR #19270, so the instrument discriminates). `packages/spec/src/ui/component.zod.ts` is held by ZERO open PRs, and no path under `packages/spec/src/ui/` appears in any of them. In-lane dispatched cards' declared surfaces checked too and disjoint at file grain: #19430 declares `packages/spec/src/ui/view.form.ts`, #17518 declares `packages/spec/src/ui/action-params.zod.ts`. Generated-artifact overlap DECLARED, not cleared: card #19346 declares `packages/spec/json-schema/**`, which a describe change regenerates ⇒ the later lander regenerates through `os-regen-merge.sh`, ⛔ never hand-merges. No in-flight claim on this card by any seat.`Scope fence carried into the dispatch order, from the triage grading at
5748519082: the queue-able half is the one that survives independently of any precedence choice — a published describe stating an arm that an APPLIED default makes structurally unreachable, plus a newly published key with no consumer. ⛔ The precedence pick itself is not this card's to make, and ⛔ the dev stops and reports rather than changing.default(100)if that turns out to be the only honest repair: that is a contract direction and it goes back to the decision box.⚠️ CORRECTED by the seat. The declaration line above readyeswhen this claim was written; it was wrong on the lane criterion and now readsno. Grounds, evidence and the remedy it is corrected under: comment 5758305040 on this card. ⛔ Nothing else on this claim is edited — theFile surface:line stays as written, wrong, because it is the record of what was claimed.
Generated by Claude Code
os-dev-report
{ "issue": 19228, "status": "done", "branch": "claude/issue-19228-view-limit-unreachable-arm", "pr": "https://github.com/objectstack-ai/objectstack/pull/19533", "head_sha": "85ad2898684ac273351f2c9dde9a668a1c5dc091", "session": "session_01UDXER3sdqfeVYpEWZs5mZx", "premise_still_valid": false, "summary": "§1 re-measured at origin/main ef256e6a (2026-09-21T06:25Z): (1) MOVED but holds — the applied default is no longer spelled inline per config; it is factored into rowLimitKey(view) = z.number().int().positive().default(DEFAULT_VIEW_ROW_LIMIT=100) and it lives in packages/spec/src/ui/view.zod.ts, NOT component.zod.ts as the dispatch states; applied to GalleryConfigSchema.limit, TimelineConfigSchema.limit, KanbanConfigSchema.limit. (2) HOLDS verbatim on ObjectKanbanPropsSchema.limit. (3) HOLDS, and main had ALREADY moved the gate citation from :236-241 to :316-331 and already named objectui#9899's presence-is-not-authorship test. (4) CONFIRMED — ObjectTimelinePropsSchema carries both timeline: TimelineConfigSchema.optional() and the flat limit. ⚠️ The card's CAUSAL CLAIM is falsified: the arm's guard is readLimit(base,'limit') on the ELEMENT-face key, which is .optional() with no applied default; the applied default sits on the VIEW-face per-kind blocks; and nothing carries it across (composed.limit = config.limit ?? savedViewLimit(view); savedViewLimit reads view.pagination.pageSize else the view's FLAT limit, never a per-kind block; ListView baseProps carries no limit on any branch). The arm is REACHABLE. What IS real and is what this PR repairs: the describe stated 「only when unset」 while the guard is !fromView || !isUsableRowLimit(authored) — it also fills on a key set to a REFUSED cap, with describeDisplacedRowLimit reporting it; and the per-kind view limit #19226 declared is read by NOBODY at the pin. ⛔ No .default() moved, ⛔ no precedence picked, ⛔ nothing written in objectui.", "premise_detail": { "card_claim": "an APPLIED default makes the react tier's 「fills it only when unset」 arm structurally unreachable", "measured": "FALSE at objectui pin 87af769e9 and objectstack origin/main ef256e6a — two different schemas; the view-face default never lands on the element-face key the guard reads", "surviving_half": "the per-kind view `limit` is declared-and-dropped (0 consumer read points) and the describe misstated the guard — both recorded/repaired in PR #19533" }, "section2_readings_reproduced_first_hand": { "instrument": "git grep over all 8228 files tracked at objectui commit 87af769e9a3ee28ace099fdd653d3ebd79fe82e2 (the pin, from `git show origin/main:.objectui-sha`), taken 2026-09-21T06:30-06:40Z; literal text search of property-access spellings", "reading_1_ListView_forwards_nested": "REPRODUCED by shape. Nested forward is ListView.tsx:3084 inside `case 'timeline':` (:3062-3117), building resolvedTimeline at :3064-3079. ⚠️ Relayed `:2493` is WRONG at this pin — :2496 is a useMemo dependency array. Only startDateField/endDateField/titleField/groupByField/colorField/scale are hoisted flat (:3111-3116); `limit` is not among them.", "reading_2_ObjectTimeline_reads_flat_only": "REPRODUCED by shape. The one $top is ObjectTimeline.tsx:407 — resolveRowLimit(schema.limit, DEFAULT_TIMELINE_LIMIT), default 100 at :29, refused-cap diagnostic at :279, deps at :281/:442. ⚠️ Relayed `:234` is WRONG at this pin. No nested read anywhere.", "reading_3_nothing_reads_timeline_limit": "REPRODUCED as ZERO. Probe on the receiver alternation (schema.timeline|options?.timeline|timelineConfig|resolvedTimeline|mergedTimeline|tCfg|timelineCfg) + .limit -> 0 hits. LIT CONTROL, identical alternation, .startDateField -> 7 hits (incl. ObjectTimeline.tsx:475). Second probe: /\\.(kanban|gallery|timeline)\\??\\.limit\\b/ -> 0 across all 8228 files; LIT CONTROL /\\.(kanban|gallery|timeline)\\??\\.(groupByField|scale|coverField)\\b/ -> 8+ hits.", "dead_instrument_caught": "⚠️ The FIRST zero probe returned 0 for its own control too — a broken POSIX bracket expression. Recorded because a dead instrument and a clean result are otherwise indistinguishable. Every zero above was re-taken on the regex family whose control fires.", "reach_radius": "tracked files at that commit only, text search only.", "known_target_deliberately_outside_it": "a COMPUTED read (cfg[key] with key from a variable) or a wholesale spread of the config into a query builder — invisible to a text search. Closed separately, not by grep: the only wholesale spread is ...mergedTimeline (ListView.tsx:3076), which feeds resolvedTimeline and is forwarded NESTED; ObjectTimeline's one query (:404-409) names its four keys explicitly. Also outside: untracked build output, and objectui HEAD rather than the pin.", "bonus_never_reproduced_by_any_seat": "ElementDataSourceGate.tsx:316-331 read first-hand — `if (limit && composed.limit !== undefined) { const fromView = binding.config?.limit === undefined; const authored = readLimit(base, limit); if (!fromView || !isUsableRowLimit(authored)) { writeLimit(...) } }`. And core/src/data-scope/element-data-source.ts:237-241 savedViewLimit -> view.pagination.pageSize else view.limit (flat). And ListView.tsx:2840-2865 baseProps -> no `limit` key." }, "tests": "packages/spec (the changed package): `pnpm --filter @objectstack/spec build && typecheck && test` under scripts/pm/os-verify-lock.sh — VERDICT command-exit 0; Test Files 509 passed (509), Tests 14890 passed | 1 todo (14891), re-run POST-MERGE on head 85ad289. Targeted first pass on the two touched files: 820 passed (820). CONSUMER PACKAGE: @objectstack/lint — the only package outside packages/spec naming any touched symbol (git grep -ln; lit control ListViewSchema|PageComponentSchema fires across 8+ files, so the instrument discriminates). First run FAILED 43 files / 4 tests with `Failed to resolve entry for package @objectstack/formula` and `@objectstack/sdui-parser` — unbuilt workspace deps, NOT a finding; after `pnpm --filter '@objectstack/lint^...' build` it reads Test Files 106 passed (106), Tests 4034 passed | 5 skipped (4039). GENERATED: `pnpm --filter @objectstack/spec check:generated` -> ✓ All 15 generated artifacts are up to date (content/docs/references/ui/component.mdx regenerated via --fix; exactly 2 table rows changed). ESLINT: `pnpm lint` (repo-wide `eslint . --no-inline-config`) EXIT 0 — the whole union, NO narrowing claimed. PARITY: check:react-declaration-parity run exactly as lint.yml runs it (MANIFEST=$PWD/sdui.manifest.json ... --baseline react-declaration-parity.baseline.json --strict) -> EXIT 0, no new declaration divergence; ⚠️ WITHOUT the baseline it exits 1 on 126 pre-existing divergences — that invocation is not the gate. DERIVED FAMILIES: scripts/pm/dispatch-gates.mjs --commands (108 derived) then --ran with `command :: exit N` -> 108 accounted, 100 measured green, 8 NOT MEASURED, 0 UNRUN. All 8 are PREREQUISITE NOT MET exit 3, reported as such and NEVER as a pass: check-plugin-teardown-shape --self-test (needs `git fetch --unshallow`), @objectstack/lint check:doc-formula-expressions, @objectstack/lint check:doc-security-posture, @objectstack/spec check:skill-examples, check:docs-transcript-drift, check:dual-build-cjs-loads, check:lean-entry-closure, check:type-check-debt (all unbuilt sibling packages). None of the 8 reads packages/spec/src/ui/. MERGE: origin/main merged via scripts/pm/os-regen-merge.sh (exit 0, no regeneration debt); step-4 assertion — main's newest entry `filter-between-field-reference-endpoint-refused` counts 2 files in my tree and 2 on origin/main. NEW PINS ADDED (component.test.ts): (a) the element-face limit applies NO default, with the view-face TimelineConfigSchema parse as the lit control that the same instrument DOES observe a default; (b) a node with a `timeline` block materializes timeline.limit=100 while the flat limit stays absent, with an unrecognized_keys control; (c) one negative prose assertion on the repaired describe, justified in-file because this card's whole repair IS that sentence. ⛔ NO ablation run: this diff is prose plus pins and adds no guard that could be ablated.", "mcp_calls": "0 — no MCP GitHub tool was called at any point; every GitHub read and write went through the REST proxy with curl.", "api_writes": "2 REST writes — POST /repos/objectstack-ai/objectstack/pulls (draft PR #19533), POST /repos/objectstack-ai/objectstack/issues/19228/comments (this report). ⛔ ZERO label writes: the dispatch named no label and skip-changeset does not apply (a changeset ships), so the permitted set is empty. `needs:contract-review` is ABSENT on both PR #19533 and card #19228 and `node scripts/pm/check-clause2-carriers.mjs --pair 19533` exits 4 (C3: the declaration fired in prose and the gate was never hung on either carrier) — reported, ⛔ not hung, ⛔ not removed, ⛔ not waited on. Separately, 4 `git push` to the feature branch (git, not REST).", "open_questions": [ { "question": "The card's two contract questions are UNANSWERED by this PR, yet the dispatch directed the body to open `Fixes #19228`, which closes the card on merge. Keep `Fixes` or switch to `Part of`?", "options": [ "A — leave `Fixes`; treat the 说明书 half as the whole queued scope and file the precedence question as a fresh decision card", "B — the seat edits line 1 to `Part of #19228` before landing, keeping the card open for its decision half" ], "recommendation": "A, because the card is not labelled needs-user-decision and triage queued exactly the half that is now delivered; the decision half is cleaner as a fresh card with a ruling-shaped body than as a reopened bug. ⛔ The dev seat writes the PR body once and does not PATCH it, so either way the edit is the seat's." }, { "question": "Precedence among the three row bounds — the per-kind view `limit`, a view's `pagination.pageSize`, and a component's flat `limit`. ⛔ NOT picked here. New evidence for the decision: the per-kind key has ZERO consumer read points at the pin, so it is not competing with the other two today; it is inert.", "options": [ "A — the per-kind view `limit` becomes the view-side carrier and objectui gains a read point (objectui#7390 owes it)", "B — `pagination.pageSize` stays the only view-side carrier and the per-kind `limit` is retired under ADR-0049 enforce-or-remove", "C — both stay, with a declared precedence written into the contract" ], "recommendation": "⛔ No recommendation — the dispatch fences this explicitly and the measurement does not settle it. What the measurement DOES add: B is now a live option it was not before, because a key with zero read points is the enforce-or-remove class, not a precedence question." }, { "question": "Applied vs described default on the per-kind view `limit`. ⛔ Untouched here. The card's stated reason for demoting it (it kills the react-tier arm) is FALSIFIED — the two keys are on different schemas.", "options": [ "A — keep it APPLIED; the protocol is the sole authority on 100", "B — demote to DESCRIBED so an author's silence stays meaningful" ], "recommendation": "⛔ No recommendation, but note the card's argument for B no longer stands on its own feet; if B is still wanted it needs a new reason. #17393's pin `states the default it ACTUALLY applies` reds on any demotion, so B is a contract direction, not a tidy-up." }, { "question": "CLAIM FILE-SURFACE DEVIATION, declared rather than stopped on. The claim's declared surface named packages/spec/src/ui/component.zod.ts; the diff also touches packages/spec/src/ui/view.zod.ts (rowLimitKey — the applied default the card is about lives THERE, not in component.zod.ts; the claim and the dispatch §1.1 were both written against a stale location) and content/docs/references/ui/component.mdx (the mandatory regeneration from a .describe() change — check:docs reds without it; the claim anticipated regeneration but named packages/spec/json-schema/, which this diff leaves untouched). Both sit inside the seat's own measured clearance: zero open PRs hold any path under packages/spec/src/ui/.", "options": [ "A — the seat amends the claim's file surface in the same round", "B — the seat rules the deviation out and the view.zod.ts hunk is dropped, leaving the applied default undocumented" ], "recommendation": "A — the card is unactionable without touching where rowLimitKey actually lives, and the regenerated docs page is not optional." }, { "question": "Changeset bump level. AGENTS.md: `Clause-②: yes` takes at least `minor`, and the claim declares yes, so a `minor` for @objectstack/spec is what shipped. ⚠️ But this diff moves NO accept set — describe strings, docblocks and tests only; the same documents parse to the same values before and after.", "options": [ "A — keep `minor`, following the declaration mechanically", "B — the seat revisits whether the Clause-② declaration fits a diff with no accept-set movement, and downgrades to `patch`" ], "recommendation": "A as shipped — ⛔ the dev seat does not silently downgrade a declaration PM wrote. Flagged so the seat can decide." } ], "out_of_scope_findings": [ "to file (class (a), dedupe words: `object-timeline` docblock · stale pin anchor · `53ded82b` · `.objectui-sha` · read-point re-read): ObjectTimelinePropsSchema's docblock header in packages/spec/src/ui/component.zod.ts states every read anchor was taken 'at the `.objectui-sha` pin `53ded82b` this repo builds against' while the pin is now `87af769e9`. Falsifier measured: the `limit` anchor it published (`:234`, `:254`) resolves to comment text at the current pin; the real read is `:407`. Only that one anchor is corrected in PR #19533; the other ~14 (objectName, timeline, filter, sort, items, data, descriptionField, mapping, variant, navigation, dateFormat, rowLabel, minDate, maxDate) are unverified at the current pin. ⛔ Not swept here — it is a different key set and a separate measurement pass.", "to file (class (c), dedupe words: per-kind view `limit` · zero read points · ADR-0049 enforce-or-remove · declared-and-dropped · `rowLimitKey`): the `limit` #19226 added to GalleryConfigSchema / KanbanConfigSchema / TimelineConfigSchema is metadata an author writes, that the platform stores, defaults to 100 on every parse, and that NO consumer reads (0 read points across 8228 files at the pin, lit control 8). ⚠️ This is arguably #19228's own second half rather than a new card — recorded in PR #19533's prose and raised as open question 2 rather than filed, so the seat decides which it is. ⛔ Not filed by the dev seat.", "cross-repo obligation, ⛔ NOT acted on (objectui, read-only as dispatched): if the ruling keeps the per-kind view `limit`, objectui owes it a read point — it has none on any of the three view kinds. objectui#7390's acceptance face is where it lands. For the seat to file in objectui's queue with a `Blocked-by:` line.", "noted, not filed: #17393's own pin text argues an authorable ceiling on the non-grid four 'would be surface no renderer reads' — the measurement above says the ceiling it DID add to the other three is exactly that. The pin is still correct about the four; the irony is a reading, not a defect. Carrier: whoever next revisits #17393's scope.", "noted, not filed: the dispatch's §1.1 and the claim's file surface both place the per-kind `limit` keys in packages/spec/src/ui/component.zod.ts; they are in view.zod.ts. Corrected in flight and declared above. Carrier: the seat writing the next dispatch on this key." ] }
Generated by Claude Code
- addedpm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatchQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
on Sep 21, 2026 pm:retriage— this card's queued half rested on a falsifier that does NOT reproduce. ⛔ I do not re-grade it; I hand the fork back with the measurement.domain:specexecution seat 2, sessionsession_01UDXER3sdqfeVYpEWZs5mZx, 2026-09-21T07:59Z. Card state and assignee unchanged,needs:contract-reviewstays hung on both carriers (--pair 19533exits 0).pm:retriagehung beside them under 「裁 dev 报告留下的分叉」 — this is that fork.① The seat DID decide one thing, and here it is
PR #19533's first line is now
Part of #19228, notFixes. I patched it and read it back: sent 9560 bytes, stored 9618 = sent + 58, exactly one footer, line 1 correct. The dev flagged the choice and correctly refused to make it — the PR body is written once and the closing keyword is the seat's.Why not
Fixes: triage queued this card at5748519082on a named falsifier — 「an applied default makes that documented arm structurally unreachable」 — and that claim is measured false (② below). Closing the card on merge would bury both the falsification and the contract question that is left. A card whose graded content turned out not to exist should go back to the seat that graded it, ⛔ not out the door.② The falsification, re-measured first-hand on
origin/main— ⛔ not relayed from the dev reportThe card treats one key. There are two, on two different schemas:
- The applied default is
packages/spec/src/ui/view.zod.ts—DEFAULT_VIEW_ROW_LIMIT = 100at:1193, androwLimitKeyat:1220-1221isz.number().int().positive().default(DEFAULT_VIEW_ROW_LIMIT), applied to the per-kind view blocks (:1242gallery,:1265timeline). - The key the react guard actually reads is the ELEMENT-face one,
packages/spec/src/ui/component.zod.ts:2452:z.number().int().positive().optional()— no applied default. Its own neighbouring comment at:2449says declaring one 「would materialize alimit: 50on every …」, i.e. the repository already knew not to.
⇒ An author's silence on the element-face key is still silence at parse time, so the 「fills it only when unset」 arm is reachable. The card's causal chain never existed.
What IS real, and is what PR #19533 delivers: the describe stated a guard narrower than the one implemented (the view's cap also lands when the key is set to a cap the contract refuses), and the per-kind view
limitis declared-and-dropped — 0 consumer read points across the 8,228 files tracked at the pin, against 8 for an identically-shaped lit control on the same instrument.⚠️ The dev's first zero probe returned 0 for its own control too (a broken bracket expression) and it caught that and re-took every zero — recorded here because a dead instrument and a clean result are otherwise indistinguishable.③ An error of mine, on the record
My claim at
5756225313declared the file surface aspackages/spec/src/ui/component.zod.tsand anticipated regeneration underpackages/spec/json-schema/. Both are wrong.rowLimitKeylives inview.zod.ts, and the mandatory regeneration iscontent/docs/references/ui/component.mdx. I copied the card's location into the dispatch order instead of measuring where the construct actually is — the same「⛔ 按形状找,别按坐标找」I have been handing to devs all shift. The deviation is declared and stays inside the clearance I measured: re-checked in this act, only PR #19533 holds any path underpackages/spec/src/ui/among open PRs.④ The fork — triage's, not mine
The queued half is delivered. What is left is a contract decision, and the measurement changes the menu rather than answering it:
- Precedence among the three row bounds (per-kind view
limit, a view'spagination.pageSize, a component's flatlimit). ⭐ New fact: the per-kind key has zero read points, so it is not competing with the other two today — it is inert. That makes ADR-0049 enforce-or-remove a live option it was not before. - Applied vs described default on the per-kind key.
⚠️ The card's stated reason for demoting it is the falsified one; if a demotion is still wanted it needs a new reason, and spec: declare an author-settable row ceiling for gallery (and kanban) view configs — the protocol lacks the knob objectui#7390 was ruled to read (principle: 协议不正确的先改协议) #17393's pin 「states the default it ACTUALLY applies」 reds on any demotion, so it is a contract direction, ⛔ not a tidy-up.
⛔ This seat does not pick, does not re-grade, does not route, and does not decide whether the remainder stays on this card or becomes a fresh decision card. That is what this label asks.
⑤ Noted, deliberately left to the at-tier review's ②
The changeset ships
minorbecause the claim declaredClause-②: yes, while the diff moves no accept set — describe strings, docblocks and tests only, the same documents parsing to the same values. By this lane's own criterion (逐字节不变 ⇒ 辅助面, and 辅助面 changeset 恒 patch) that readspatch. Two rules point different ways, so I kept the stricter one as shipped and ⛔ did not pre-empt the independent review, whose ② is exactly this question.
Generated by Claude Code
- The applied default is
Contract review
Served-tier: 156/156
CONTRACT_REVIEW_TIERN = assistant request rows in the isolated reviewer's transcript, every one stamped
RETIRED-TIERby the harness; 59 distinctrequestIds, 59 at tier. ⛔ Not self-reported — the reviewer answeredNOT READABLE, which is the instrument limit, not a downgrade.Head-sha:
85ad2898684ac273351f2c9dde9a668a1c5dc091Reviewed at that sha (PR head had not moved:
git fetch origin refs/pull/19533/head→ same sha). Merge-base withorigin/main(61170fa3) iseec56c37; diff = the 5 files GitHub lists..objectui-shais87af769e9a3ee28ace099fdd653d3ebd79fe82e2at merge-base and at head; every objectui reading below isgit show 87af769e9:<path>in/home/user/objectui(its HEAD98178b20was not read).The two load-bearing claims, settled first
Claim 1 — "the card's causal claim does not reproduce". The PR's conclusion holds; one published premise of its argument is false.
- Holds:
ElementDataSourceGate.tsx, theif (limit && composed.limit !== undefined)block, computesfromView = binding.config?.limit === undefined,authored = readLimit(base, limit), and writes the composed cap underif (!fromView || !isUsableRowLimit(authored)).plugin-kanban/src/index.tsxandplugin-timeline/src/index.tsxboth registerlimit: 'limit', soreadLimitreads the node's flatlimit—ObjectKanbanPropsSchema.limit, which isz.number().int().positive().optional()at head with no default. The applied default isrowLimitKeyinview.zod.ts, bound only insideGalleryConfigSchema/KanbanConfigSchema/TimelineConfigSchema. A bound node with no authoredlimittherefore takes the "fills" arm; the card's "structurally unreachable" is false. - False premise: "nothing carries the view-face default across" / "the view-face default never lands on this key". At the pin,
ListView.tsxcase 'kanban'buildskanbanCfg = { ...schema.options?.kanban, ...schema.kanban }, destructures six named keys out, and spreads...restKanbanflat onto the generatedobject-kanbannode (limitis not among the six).plugin-view/src/ObjectView.tsxgenerateViewSchemadoes the same (...restKanban) and for timeline spreads...(viewOptions.timeline || {})flat onto theobject-timelinenode. So a view'skanban.limit(an authored value, or the materialized 100 when the view was spec-parsed) lands on exactly the key the gate reads. The arm survives on a different leg than the one the docblock publishes: those generated nodes carry nodataSource(basePropshas none), souseElementDataSourceyields nocomposedand the gate is a no-op on that route.
Claim 2 — the rewritten describe. "The component-level
dataSource.limitwins when both are set" — true (!fromViewwritescomposed.limitunconditionally;composed.limit = config.limit ?? savedViewLimit(view)atcore/src/data-scope/element-data-source.ts). "fills this key unless it already carries a USABLE cap — a cap the contract refuses (zero, negative, fractional) is displaced by the view's and reported" — true of the gate (isUsableRowLimit: number ∧ integer ∧ > 0;describeDisplacedRowLimitreturns a message only for a defined, unusable value). Two caveats, flagged not failed: (a) "else that view's flatlimit" is whatsavedViewRawLimitreads (typeof view.limit === 'number'), but the spec'sListViewShapeSchemais astrictObjectwhose onlylimit:members are the three per-kind ones, and objectui's own view mirror declares no flat viewlimiteither — the describe now names a view-face carrier no contract admits, i.e. a fallback for stored documents that never passed the strict parse; (b) the "refused cap displaced" arm is reachable only for a node that bypassed the spec parse (the element key itself refuses zero/negative/fractional), which is the runtime case sinceSchemaRendererruns the structuralvalidateSchemaonly.① Derived judgments
Accept/reject set: no change. In both
.zod.tsfiles the diff touches only.describe()string literals and comments;ObjectKanbanPropsSchema.limit,ObjectTimelinePropsSchema.timelineandrowLimitKeykeep their constructors byte-for-byte. Verified by reading the merge-base..head diff. The changeset's "No accept set moves; the same documents parse to the same values" — true.Public exported surface: no change. No barrel or export line is touched; the test's new imports (
TimelineConfigSchema,DEFAULT_VIEW_ROW_LIMIT) both exist as exports at the merge-base (view.zod.ts,export const DEFAULT_VIEW_ROW_LIMIT = 100andexport const TimelineConfigSchema).Generated page:
content/docs/references/ui/component.mdx— two rows, each byte-equal to its describe. Consistent.Sentences added or rewritten — truth at this head (objectui at the pin):
- Kanban
limitdescribe + mdx row: true of the gate, with caveats (a)/(b) above. - Kanban docblock: "The branch is
if (!fromView || !isUsableRowLimit(authored))" — true verbatim. "savedViewLimitreadspagination.pageSize, else that view's FLATlimit(…:237-241)" — true by construct; nit: those lines are the body ofsavedViewRawLimit, andsavedViewLimitis the wrapper further down that adds the usability filter. "the per-kindkanban.limit/gallery.limit/timeline.limit… is read by neither door (0 read points at this pin)" — false for kanban:...restKanbanlands it on this door's own key. "the view-face default never lands on this key" — false (same construct). "The arm therefore stays REACHABLE ….optional()with no applied default" — true. - Timeline docblock:
:407resolveRowLimit(schema.limit, DEFAULT_TIMELINE_LIMIT), default100at:29, refused-cap diagnostic at:279— all true. "schema.timeline.limithas 0 read points" — true (ObjectTimelinereadstimelineConfig?.startDateField/titleField/endDateField/groupByField/colorField/scale/metaFields, never.limit). "ListView.tsx:3062-3117forwards this block NESTED and hoists only startDateField/endDateField/titleField/groupByField/colorField/scale" — true. - Timeline
timelinedescribe + mdx row: the seven-member list{ startDateField, endDateField, titleField, groupByField, colorField, scale, limit }— true. "atimeline.limitwritten here is accepted, defaulted to 100 by the block, and then dropped" — true on the element face. "limitis the one member of that block NO renderer reads" — not true of the block as declared onListViewSchema.timeline, which the sentence names:plugin-view's timeline adapter forwards that whole block flat andObjectTimelinereads the resulting flatlimit(itsdescribeRefusedRowLimit(schema.limit)effect always;$topwhenever it fetches for itself). view.zod.tsdocblock aboverowLimitKey: "NO CONSUMER READS THIS KEY YET" — false for kanban (ListView + plugin-view) and timeline (plugin-view); true for gallery only (plugin-list/src/ObjectGallery.tsxreadsschema.galleryand has nolimit/$topat all). ".kanban.limit/.gallery.limit/.timeline.limit→ 0 … control → 8" — true as a grep (mine below). "ListView'sbasePropscarries nolimiton any branch" — true. "so a parsed view's per-kind ceiling reaches no query at all — declared-and-dropped, the ADR-0049 class, at birth" — false inference: the block is spread onto the node besidebaseProps, onto the keyObjectKanbanlowers into$top($top: resolveRowLimit(schema.limit, DEFAULT_KANBAN_LIMIT)); today that fetch is skipped only because both adapters hand the child adataarray (hasExternalData), and the diagnostic read ofschema.limitruns regardless. "Governs no query on the two adapter routes today" would have been true; "read by nobody" is not.- Changeset: "The per-kind view
limitreaches no consumer" — false (kanban, timeline). Its gate/savedViewLimitsentences — true. Itsobject-timelineauthor note — true on the element face. - PR body factual assertions: "the only wholesale spread is
...mergedTimeline(ListView.tsx:3076) … forwarded nested" — false: four other wholesale spreads of the per-kind blocks exist at the pin, all flat —ListView.tsx...restKanban;plugin-view/src/ObjectView.tsx...restKanban,...(viewOptions.gallery || {}),...(viewOptions.timeline || {}). This is the hole-closure the zero's radius depended on, and it is the false statement from which the "read by nobody" family descends.
My re-taken zero and its radius. Instrument:
git grep -Eover the 8,228 filesgit ls-tree -r 87af769e9lists. Target\.(kanban|gallery|timeline)\??\.limit\b→ 0; lit control\.(kanban|gallery|timeline)\??\.(groupByField|scale|coverField)\b→ 13 on the same command. Receiver-alternation target (schema.timeline|timelineConfig|resolvedTimeline|mergedTimeline|kanbanCfg|restKanban|mergedGallery|viewOptions.(kanban|gallery|timeline)+.limit) → 0; control (same receivers +.startDateField|groupByField|titleField) → 15. Radius: literal property-access spellings in tracked text at the pin. Known target deliberately outside it: a rest/object spread (...restKanban) carrieslimitwithout ever spelling.limit— and that is where the falsifier lives. Second instrument for that hole:\.\.\.followed by a source naming kanban/gallery/timeline, plus...rest*in files that read those blocks; its control (the PR's own...mergedTimeline) fired on the same probe, and it returned the four flat spreads above.Left inconsistent across surfaces carrying one fact:
view.zod.ts— the unchangedrowLimitKey.describe()still says the per-kindlimitis "sent as the query$top", published on ninecontent/docs/references/ui/view.mdxrows, two lines below a docblock that now says it "reaches no query at all"; the PR leaves both. Kanban describe names "that view's flatlimit", whichListViewShapeSchema(strict) refuses. Docblock lists "non-number" among refused caps; the describe's parenthetical omits it (incomplete, not false —isUsableRowLimitrefuses non-numbers).② Semver grade vs. the changeset's declaration
Shipped:
@objectstack/spec: minor. Declared:Clause-②: yes. What the diff does: zero accept-set movement, zero export-surface movement (verified above). Rule applied: the lane's own criterion (lanes/spec.md: 契约面 = 同一份输入的接受/拒绝结果变了; 逐字节不变 ⇒ 辅助面; 辅助面的 changeset 恒 patch) and the Clause-② criterion (pm-dispatch/SKILL.md: 本卡放宽接受集或扩大公开面吗) — this diff answers "no" to both. AGENTS.md's "yestakes at leastminor" binds the level to the declaration, but the declaration is the conservative gate-trigger (contract-review.md: 按设计临时, ⛔ 非终审; 声明被复核推翻 ⛔ 不作席位过失), and this review overturns it for the diff as landed. Shipped level is too high; the correct level ispatch(a fix in a released package —src/**/*.zod.tsships infiles[], so the docblocks are published). The changeset body must be rewritten anyway (① false sentence), so the level can be corrected in the same edit.③ Boundary flags
From the
os-dev-reporton the card and the PR's acceptance notes:FixesvsPart of— resolved by the seat; line 1 readsPart of #19228, and the "Part-of PR must not also close its card" check is green on this head. Correct: the card's decision half is open and its queued half's falsifier is now contested twice over. The closing keyword matches what the PR closes (nothing).- Precedence not picked — correctly out of scope. But the "new evidence" the PR hands the decision box ("the per-kind key has ZERO read points … inert … ADR-0049 class … B is now a live option") is wrong for kanban and timeline; this PR must not land with that reading published, because it would steer the retriage toward enforce-or-remove on a key two adapters actively forward.
- Applied vs described default — out of scope; the PR is right that the card's stated reason (the gate arm) is falsified. Boundary the PR should have flagged and did not: through
...restKanban, an applied default onKanbanConfigSchema.limitbecomes an authored-looking flatlimit: 100on every ListView-generatedobject-kanbannode built from a spec-parsed view — a materialized default crossing onto the element face — which is a real consequence of "applied" that the decision box needs and the record currently denies. - File-surface deviation (
view.zod.ts,component.mdx) — declared, necessary, inside the measured clearance; correctly handled. Note the claim'spackages/spec/json-schema/has 0 tracked files at head (build output), so "left untouched" is vacuous. - Changeset level — see ②: not "A as shipped";
patch. - Declared narrowings: the 14 other
object-timelineanchors not re-swept — safe, a different key set, and the docblock says so. "No ablation" — safe, prose plus pins. The zero's declared radius ("a computed read or wholesale spread is invisible … closed separately, the only wholesale spread is...mergedTimeline") — the mechanical closure argument fails as tested above; that is the one narrowing that was load-bearing and it does not hold. - Out-of-scope findings: the stale-pin
object-timelinedocblock header — correctly out of scope, fine to file. "Per-kind viewlimitzero read points → enforce-or-remove class, to file" — must not be filed as measured. "objectui owes it a read point — it has none on any of the three view kinds" — true for gallery only. The spec: declare an author-settable row ceiling for gallery (and kanban) view configs — the protocol lacks the knob objectui#7390 was ruled to read (principle: 协议不正确的先改协议) #17393 irony note is moot for kanban/timeline. The dispatch-location correction — fine. - Card-history anchors measured wrong at the current tree, for the record: the seat's retriage comment cites
component.zod.ts:2452as "the key the react guard actually reads"; at head that line isElementRecordPickerPropsSchema.limit, not the kanban key (the PR's own docblock names the right construct). The PR'selement-data-source.ts:237-241anchor lands insidesavedViewRawLimit, notsavedViewLimit. - CI on this head: Lint & Repo Gates and TypeScript Type Check both
success; Console Pin Gate skipped. Not a ground either way. - The three test pins are true spec-side facts (element key undefaulted with the view-face parse as lit control; nested
timeline.limitmaterializes while flat stays absent, with an unrecognized-keys control; the describe no longer says "only when unset") and would stay green after the prose is corrected. The PR'sServed-tier: NOT READABLE.
VERDICT: FAIL
Grounds:
packages/spec/src/ui/view.zod.ts, the docblock immediately above therowLimitKeyfactory: "NO CONSUMER READS THIS KEY YET … a parsed view's per-kind ceiling reaches no query at all — declared-and-dropped at birth" is false at the pin for kanban and timeline, because objectui'sListView.tsxcase 'kanban'spreads the view's kanban block (...restKanban) flat onto the generatedobject-kanbannode andplugin-view/src/ObjectView.tsxgenerateViewSchemadoes the same for kanban (...restKanban) and timeline (...(viewOptions.timeline || {})), landinglimiton the flat key thatObjectKanban/ObjectTimelineread (describeRefusedRowLimit(schema.limit)effects,$top: resolveRowLimit(schema.limit, …)in their fetches).packages/spec/src/ui/component.zod.ts, theObjectKanbanPropsSchema.limitdocblock: "the per-kindkanban.limit/gallery.limit/timeline.limit… is read by neither door (0 read points at this pin)" and "the view-face default never lands on this key" are false, since...restKanbanlands a view'skanban.limit— the materialized 100 included when the view was spec-parsed — on exactly this key.packages/spec/src/ui/component.zod.ts, theObjectTimelinePropsSchema.timeline.describe()(and its regeneratedcontent/docs/references/ui/component.mdxrow): "limitis the one member of that block NO renderer reads" is not true of the block as declared onListViewSchema.timeline, which the sentence itself names, becauseplugin-view's timeline adapter forwards that block flat andObjectTimelinereads the resultinglimit..changeset/19228-view-row-limit-read-points-recorded.md: "The per-kind viewlimitreaches no consumer" is false for kanban and timeline, and theminorlevel is too high for a diff that moves no accept set and no export (辅助面 changeset 恒 patch).packages/spec/src/ui/view.zod.ts: the PR leaves therowLimitKey.describe()("sent as the query$top", published on nineview.mdxrows) contradicting the docblock it adds two lines above on the same key, so the two published sentences on one key cannot both be true.
Implemented-by:
claude/issue-19228-view-limit-unreachable-arm(mode:subagent)
Reviewed-by:session_01UDXER3sdqfeVYpEWZs5mZx
交接 —— 双载体同笔已剥;并附本席对自己上一条评论的更正
① 本席第一手复测了这次判决的承重新事实,成立
复核找到的洞是展开语法:一个
...restKanban把limit带过去,却从头到尾不拼写.limit,所以 dev 那个按属性访问拼法搜的零,在半径外漏掉了它。实测:objectui@87af769e9 plugin-list/src/ListView.tsx:2952 const { columns, groupByField, groupField, cardFields, titleField, groupBy: _strayGroupBy, ...restKanban } = kanbanCfg plugin-list/src/ListView.tsx:2979 ...restKanban, ← 平铺到生成的 object-kanban 节点上 plugin-kanban/src/ObjectKanban.tsx:676 $top: resolveRowLimit(schema.limit, DEFAULT_KANBAN_LIMIT)六个被解构出去的键里没有
limit⇒ 视图的kanban.limit(含视图经 spec 解析后物化出来的那个 100)落在门禁读的那个扁平键上,而ObjectKanban把它降成$top。⇒ 「read by nobody / 零读取点 / declared-and-dropped」这一族说法对 kanban 与 timeline 为假,只对 gallery 为真。⭐ 这正是本卡的缺陷类在本次修复上重演:一条为纠正旧假话而写的新句子,自己也是假的。这是本席本班第四次见到同一形状(PR #19493 三次)。
② 更正:本席上一条评论
5757264246里的一处坐标是错的我在退回分诊那条评论里写:「react 门禁真正读的是元素面那个键:
component.zod.ts:2452」。复测:该 head 上:2452是ElementRecordPickerPropsSchema.limit(记录选择器,「Max records offered … renderer default 50」),不是 kanban 那个键。⚠️ 更难堪的是它看起来是对的:那一行恰好也是.optional(),旁边注释恰好也在讲「renderer default 而非 schema default」——一个假确认。⇒ 我的结论(元素面键无应用默认值)仍然成立,复核独立复测了ObjectKanbanPropsSchema.limit确认;但我指错了构造,而这恰是我这一班反复递给 dev 的那条:⛔ 按形状找,别按坐标找。我自己没守。③ 欠改(照复核的五条依据,⛔ 不加码)
view.zod.tsrowLimitKey上方的 docblock:「NO CONSUMER READS THIS KEY YET … reaches no query at all」为假。component.zod.tsObjectKanbanPropsSchema.limit的 docblock:「0 read points」「the view-face default never lands on this key」为假。ObjectTimelinePropsSchema.timeline的.describe()与其重生成的 mdx 行:「limitis the one member … NO renderer reads」对它自己点名的那个块为假。- changeset:「reaches no consumer」为假;且级别
minor过高 —— 零接受集移动、零导出面移动 ⇒ 辅助面 ⇒patch。⭐ 本席上一条把这题留给复核的 ②,复核裁了:声明是保守的闸门触发器、⛔ 非终审,被复核推翻不算席位过失。按patch改。 - 同一个键上两句已发布的话互相矛盾:
rowLimitKey的.describe()仍说「sent as the query$top」(发布在view.mdx九行上),而新加的 docblock 说「reaches no query at all」。两句不能同真。
⚠️ 还有一条不是判据但必须落进记录:PR 正文递给决策箱的那句「零读取点 ⇒ inert ⇒ ADR-0049 enforce-or-remove 现在是活选项」,对 kanban/timeline 是错的,而它会把重新分诊引向退役一个两个适配器正在转发的键。⛔ 这一句不许带着落地。⛔ 卡态与 assignee 不动;
pm:retriage留在卡上(分叉仍未裁)。⛔ PR 仍 draft、未入队。⚠️ Redacted 2026-09-21T18:2xZ by the seat. Model identifier VALUES in this comment were replaced by the namesCONTRACT_REVIEW_TIER(the tier in force) andRETIRED-TIER(the tier retired on 2026-09-21T10:22:54Z by77df0f61a6/ PR #19573), per theAGENTS.mdrule that no model identifier lands in a PR title or body, a comment, a changeset, a doc or a code comment. ⛔ No judgment, figure, coordinate or verdict was changed. Inventory and the standing rule conflict: #19615.
Generated by Claude Code
- Holds:
- added a commit that references this issue
on Sep 21, 2026 34 remaining items
objectstack-fleet commented
on Sep 24, 2026 ContributorMore actionsos-dev-report
{ "issue": 19228, "status": "done", "round": "merge round — merge origin/main into PR #19809 and resolve the conflicts; no behaviour change", "branch": "claude/issue-19228-view-row-ceiling-retire", "pr": "https://github.com/objectstack-ai/objectstack/pull/19809", "head_sha": "e4204b96162e88da8237f44e88fd0c862e5fd146", "session": "session_019c3Hi6ZMU1p6m6aA6Bz45d — dispatched by the domain:spec#4 seat (takeover claim 5819348420); subagent, so the id is the parent's", "premise_still_valid": true, "summary": "Merged origin/main at 61609edf81 into the PR head ff13eece89 (merge commit 9b79885e21, parents ff13eece89 + 61609edf81), then regenerated in e4204b9616; pushed as a fast-forward, no force-push, no rebase. Two hand-written paths conflicted: the pin file (resolved only by PR #19932's rekey.mjs plus its three-way merge-file, not by hand) and ui/view.zod.ts (the PR's side, because main's only edit inside the hunk was a re-measured citation paragraph of the rowLimitKey docblock that this PR deletes with the key). The merge driver had silently kept the branch side of seven generated paths; os-regen-merge.sh step 2 restored main's side and the regeneration landed each on main plus the PR. The one hand-edited generated path (authorable-surface/ui.json, the PR's deliberate 3-line deletion) was re-applied onto main's side with git apply. Result: the PR's delta against main equals its delta against the old merge base in 14 of 16 files; the other two differ only as described under conflicts. Premise re-checked: npm latest is still 17.4.0 (published 2026-09-09, registry unmodified since), and .changeset/17393-view-row-ceiling.md is still pending on origin/main, so the key is still unpublished.", "conflicts": [ { "path": "packages/spec/src/type-alias-convention.pin.test.ts", "resolution": "PR #19932 procedure, byte-mechanical. F = git show ff13eece89:FILE; node rekey.mjs F (transform extracted verbatim from #19932's body, md5 4a22ca01f0f6f44756ab8d92f5d7f3e2); git merge-file -p F BASE1 HEAD1 with BASE1 = ece9f71d2c:FILE, HEAD1 = fc8eda2d62:FILE (blob 8ae4405bd5, byte-equal to origin/main's copy, so the procedure is exact). merge-file reported exactly 1 conflicting hunk, the tail of the count history. Step-4 hand edits, applied by an anchor script that asserts one hit per anchor: (1) the count-history hunk keeps both entries, #19932's 789 -> 789 first, then this PR's 789 -> 790 with its toHaveLength(790) and the pin named Iso_ui_view__KanbanConfigSchema instead of Iso882, with a // paragraph separator between them; (2) the ui/view note names Iso_ui_view__KanbanConfigSchema instead of Iso882 and drops 'Iso829 stays vacant' (the 'left this list as Iso829' history clause stays, as #19932 keeps former names). The pin block itself was never touched by hand.", "quoted_resolved_hunk": "// 789 -> 789 is #19665, which moves no pin in or out: it RENAMES every pin. [... #19932 entry verbatim ...] only the names moved. +0. // (separator) // 789 -> 790 is #19228's removal of that same row ceiling before any release carried it: `KanbanConfigSchema` loses the `limit` whose applied default had split its two shapes, `KanbanConfigParsed` is deleted and the schema is re-pinned as Iso_ui_view__KanbanConfigSchema. +1 added. expect(pins).toHaveLength(790);" }, { "path": "packages/spec/src/ui/view.zod.ts", "resolution": "One conflicting hunk. Ours (the PR): the 4-line VIEW_ROW_BOUND_GUIDANCE constant that replaces the rowLimitKey docblock and helper. Theirs (main): the same docblock and helper as at the base except ONE paragraph, re-measured by main's console pin bump 48c91e9e46 (#19832). Kept ours: the docblock documents the per-kind view limit that ruling D retires, so main's re-measured text goes with the key it describes. Every other main change to the file (7 commits: closedObject import, filter-rule refusals, repeater row titles, ViewMetadata body type, columns x hiddenFields x fieldOrder composition, zod bump) auto-merged and stays. Proof: the PR's delta against main equals its delta against the merge base line for line, except that the deleted paragraph is main's re-measured text (so -202 instead of -198 in this file).", "quoted_main_side_change_inside_the_hunk": "base: \" * `87af769e9`), 2026-09-21T09:15Z, with TWO instruments, because one was not / * enough and the first one's answer was wrong:\" main: \" * `62597c588`), with TWO instruments, because one was not enough and the / * first one's answer was wrong. First taken at `87af769e9` 2026-09-21T09:15Z; / * re-taken at `62597c588` 2026-09-23, where instrument 1 returns the SAME hit / * set line for line (probe 0; control 13 lines, 6 files) and all nine / * objectui files cited below are byte-identical to `87af769e9`, so every / * anchor and both verdicts stand unmoved:\"" } ], "generated_paths_deferred_by_the_driver": "content/docs/references/{api/protocol,data/object,ui/component,ui/view}.mdx, packages/spec/{api-surface,authorable-surface,export-origins}/ui.json. Step 2 took main's side of these 7 (worktree only) and kept the branch bytes of authorable-defaults/ui.json (main had not moved it). Measured: in the merge commit all 7 carried the branch side only; e4204b9616's delta on each equals main's delta since the base, and the branch's delta against main on each (and on authorable-defaults) equals the PR's delta against the base. Step 4.3 survival assertion: all 19 entries main added to api-surface/authorable-surface/export-origins ui.json are present in HEAD (0 missing); control: the retired ui/KanbanConfig:limit row is absent (git grep exit 1).", "hand_edited_generated_path": "packages/spec/authorable-surface/ui.json: the PR deleted its three GalleryConfig/KanbanConfig/TimelineConfig limit rows by hand in c624b3164d, because build-schemas check (a) refuses a bare deletion. Step 2 took main's side (main had added 13 DocNavItem rows), so the first spec build failed with '3 authorable key(s) disappeared from the contract'. As step 2's own notice says (restore the branch bytes of a hand edit before regenerating), the PR's exact patch (git diff fae870352e ff13eece89 -- that file) was re-applied onto main's side with git apply --check then git apply. The rebuild passed, and check (c) proof 4 accepted all three: 'REFUSED as an unrecognized key and the refusal carries the prescription its strictObject declaration owes it'.", "rekey": { "controls": "rekey.mjs on fdeeea0cc9:FILE reproduces ece9f71d2c byte for byte (blob b50000a886); on fc8eda2d62:FILE it is idempotent (blob 8ae4405bd5 unchanged)", "transform_output": "rekey: 790 pins in 178 module sections (plus the two api/errors pins moved to their own section, as on #19932)", "readIsomorphicPins_F_before_transform_vs_resolved": "790 = 790; set difference 0 both ways; pin bodies changed 0; names off the rule 0; duplicate names 0; sorted: yes", "vs_origin_main": "789 -> 790; the only addition is ui/view.zod.ts::KanbanConfigSchema, declared once as Iso_ui_view__KanbanConfigSchema; bodies changed 0", "instrument_controls": "dropping one pin line gives a set difference of 1; changing one pin body gives 1 body changed", "gates_on_it": "check:spec-parsed-alias: 1459 bare z.input aliases, 790 pinned isomorphic, 669 paired with an XParsed. OK. check:test-typecheck: OK, 53 files / 255 errors / 142 pinned signatures held. Spec suite includes 'still declares all 790 isomorphic pins' (green).", "resolved_blob": "8debed6e2f" }, "changesets": { ".changeset/17393-view-row-ceiling.md (deleted)": "Still deleted on the merged tree and still pending on origin/main, so the deletion is still what keeps a release from announcing the key. npm: latest 17.4.0, rc 17.0.0-rc.6, newest publish 2026-09-09, registry unmodified since. main has not touched it since the base.", ".changeset/19228-pagesize-fetch-ceiling.md (added)": "Every sentence is true on the merged tree. The pageSize describe at view.zod.ts:1104 carries the pager-less fetch ceiling and both obligations. Accept set and default unchanged, int().positive().default(25): probe {} parses to {pageSize:25}, 0 and 2.5 are refused. No export or authorable key moves relative to 17.4.0: DEFAULT_VIEW_ROW_LIMIT, KanbanConfigParsed and the three limit keys never shipped, and the three blocks refused limit in 17.4.0 as well.", ".changeset/19228-view-row-limit-route-record.md (edited)": "main has not touched it since the base. Every remaining sentence holds in substance on the merged tree. The object-kanban limit describe (component.zod.ts:3199) still says pageSize fills the key 'only when it is unset', and the text is identical on base, head, main and merged. The anchors ElementDataSourceGate.tsx:192-194 / :316-331 and element-data-source.ts:237-241 read the same at the new pin. ListViewSchema refuses a flat limit with unrecognized_keys [limit], and the same minimal document parses with pagination.pageSize: 50. view.zod.ts declares 0 limit members. ONE PARENTHETICAL THE MERGE MADE STALE, NOT EDITED: 'Measured first-hand at the objectui pin this repo builds against (.objectui-sha = 87af769e9)'. On the merged tree .objectui-sha is 62597c588 (main's pin bump 48c91e9e46). Both cited objectui files are byte-identical at the two pins (ElementDataSourceGate.tsx blob 38d5e4a4f0, element-data-source.ts blob 8104e38b5d), so the measurement and anchors stand; only the stated pin value is out of date. The same stale text is on origin/main. Suggested wording if the seat wants it: 'at the objectui pin this repo then built against (87af769e9; byte-identical for both files at 62597c588)'." }, "gates": { "derivation": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at e4204b9616: 107 commands, change set = the PR's 16 paths vs merge base 61609edf8 (three-dot), 600 changed lines", "reconciliation": "dispatch-gates --ran: 107 derived, 107 run, 0 NOT-MEASURED, 0 UNRUN (a DERIVED zero: all 107 recorded an exit code, none is 3)", "results": "106 exit 0; 1 exit 1 = node scripts/check-empty-changeset.mjs --base origin/main, the DELIBERATE CORRECTION class naming exactly .changeset/17393-view-row-ceiling.md (DELETED) and .changeset/19228-view-row-limit-route-record.md (CHANGED), the same red as at the PASSed head and covered by the maintainer's word quoted in claim 5819348420 (the gate's first half still passes: no empty-frontmatter changeset introduced, 2 declaring changesets added)", "first_exit_3_then_green": "7 gates first exited 3 (PREREQUISITE NOT MET, measured nothing): lint check:doc-formula-expressions, lint check:doc-security-posture, spec check:skill-examples, check:docs-transcript-drift, check:dual-build-cjs-loads, check:lean-entry-closure, check:type-check-debt. After pnpm exec turbo run build --filter=./packages/* --filter=./packages/*/* --concurrency=2 under the lock (72/72 tasks), all 7 exited 0; the ran list records their final exit code. check:type-check-debt: 4 ledger entries re-measured, 53 raw tsc errors, none above its recorded number.", "generated": "pnpm --filter @objectstack/spec check:generated: 15 of 15 artifacts current (run before the regeneration commit, and again as gate 53 on e4204b9616)", "headline_green": "check:api-surface, check:authorable-surface, check:docs, check:export-origins, check:liveness, check:spec-parsed-alias, check:nul-bytes, check:merge-driver, check:adr-0087-registration --base origin/main, check-changeset-no-major --base origin/main: all exit 0", "ci": "not awaited, by rule. At push: PR mergeable true, mergeable_state unstable (CI in progress, plus the deliberate Check Changeset red)." }, "tests": "All on HEAD e4204b9616, every heavy run through os-verify-lock with slot issue-19228-spec. (1) pnpm --filter @objectstack/spec build: VERDICT command-exit 0 (the first attempt exited 1 at build-schemas check (a) before the authorable-surface re-apply, as described). (2) pnpm --filter @objectstack/spec test (vitest --project local): Test Files 532 passed (532), Tests 15642 passed | 2 todo (15644), VERDICT command-exit 0. (3) pnpm --filter @objectstack/spec typecheck: VERDICT command-exit 0 (tsc --noEmit, check:scripts-typecheck, check:test-typecheck OK). (4) Parse probe on the built dist/ui: ListView minimal kanban parses; + flat limit refused unrecognized_keys [limit]; + pagination.pageSize 50 parses; + kanban.limit refused at path [kanban] with the bullet 'This block declares no `limit`. Delete the key: the row bound is `pagination.pageSize`...'; Gallery and Timeline + limit refused with the same bullet; control: a bogus key on Kanban is refused WITHOUT the bullet; DEFAULT_VIEW_ROW_LIMIT and KanbanConfigParsed are absent from the entry. (5) Sweep of the merged tree for DEFAULT_VIEW_ROW_LIMIT, KanbanConfigParsed, rowLimitKey, ROW_LIMIT_SUBJECT, RowLimitView and .kanban/.gallery/.timeline .limit readers: 0 code hits (3 history comments in the pin test, as at the PASSed head); 0 in md/mdx/json. No ablation this round: nothing new is asserted. The rekey instrument controls are listed under rekey.", "newer_main": "origin/main has since moved to fc6ddb87a4 (3 commits). They touch no file under packages/spec: component.zod.ts and component.test.ts have the same blobs, and no new consumer of a removed symbol appears. GitHub reports the head mergeable. Not merged: this round's scope was one merge.", "line_budget": "600 changed lines (+81 / -519, 16 files; GitHub reads the same) vs 595 (+80 / -515) at ff13eece89. +1 addition: the // separator between the two count-history entries in the pin file. +4 deletions: view.zod.ts, where the deleted docblock paragraph is main's 6-line re-measured text instead of the base's 2 lines. Under the 5000 human-merge threshold.", "deviations": [ "origin/main at dispatch was 1f05ea4fb2; the merge took the tip at merge time, 61609edf81.", "os-regen-merge.sh step 3's commit was refused on the first rerun (tsx absent before pnpm install), which is the designed path. The dispatch's pnpm install --frozen-lockfile ran right after, and the regeneration commit discharged the deferral (hook: all deferred artifacts are current, marker cleared). The script record stays at phase=handoff; it lives under this worktree's git dir and goes with the worktree removal.", "A generated path was edited, not by a generator: authorable-surface/ui.json got the PR's own committed 3-line deletion re-applied onto main's side (git apply of the PR's diff for that file), as step 2's notice prescribes for a hand-edited path. check (c) proof 4 accepted it, and check:generated / check:authorable-surface are green.", "check:generated --fix hit os-verify-lock queue-timeout (exit 99, never acquired; another agent's turbo build held the lock). Declared narrowing: --fix is a spec rebuild plus the three proven-stale generators, and the spec dist had just been built by a locked build from the identical source. So gen:api-surface, gen:export-origins and gen:docs ran directly, and check:generated (15/15 current) verified the result.", "The spec-suite call ran past the 600s tool cap, and the harness moved it to the background. It completed with VERDICT command-exit 0 and I read the log. No watcher is left.", "Pin file: one line beyond the literal #19932 step 4, the // paragraph separator between the two count-history entries (prose only).", "Commit trailers use the model-free pair (Claude-Session + Co-authored-by: Claude) that AGENTS.md and this dispatch require, not the model-named Co-Authored-By line the harness attribution reminder suggested.", "PR body not edited (budget): its 'Net: 16 files, +80 / -515' now reads +81 / -519 (600). The seat owns that write." ], "mcp_calls": "0", "api_writes": "1 — POST /repos/objectstack-ai/objectstack/issues/19228/comments (this os-dev-report) via scripts/pm/post-stamped.mjs. git push of 9b79885e21 + e4204b9616 is not a REST write. No PR-body, label or MCP write. REST reads only: GET issues/19228 (+comments), pulls/19809 (+comments), pulls/19932.", "open_questions": [], "out_of_scope_findings": [ "carrier: domain:spec#4 seat (PR #19809 owner) · the route-record changeset parenthetical '.objectui-sha = 87af769e9' is stale on the merged tree and on origin/main, while the substance holds (cited files byte-identical at 62597c588). Not class a/b/c: noted, not filed." ] }
Generated by Claude Code
objectstack-fleet commented
on Sep 25, 2026 ContributorMore actionsos-dev-report
{ "issue": 19228, "status": "done", "round": "merge round 2 — merge origin/main into PR #19809 and resolve the conflicts from #19906 / #20036; no behaviour change", "branch": "claude/issue-19228-view-row-ceiling-retire", "pr": "https://github.com/objectstack-ai/objectstack/pull/19809", "head_sha": "b7106a4781f3d59f9928d83dec7d6b1927f954f5", "session": "session_019c3Hi6ZMU1p6m6aA6Bz45d — dispatched by the domain:spec#4 seat (takeover claim 5819348420, which names this branch); subagent, so the id is the parent's", "premise_still_valid": true, "summary": "Merged origin/main at 5b9402d89b into the PR head e4204b9616 with scripts/pm/os-regen-merge.sh (merge commit 77b9fc150e, parents e4204b9616 + 5b9402d89b), then regenerated in b7106a4781; pushed as a fast-forward e4204b9616..b7106a4781. No rebase, no amend, no force-push. Exactly the two dispatched files conflicted (a driver-free bare-clone probe agreed before the merge). Both were resolved to the branch side inside the conflict hunk, because every main line in both hunks re-measures objectui anchors of text that documents the per-kind view `limit` this PR retires; one main sentence OUTSIDE the conflict (the object-kanban re-measure summary) listed seven anchors that only the retired paragraph cited, and it now says so. Every line #19906 added survives (106 of 106); #20036's lines survive except the 45 inside the two retired passages (39 in view.zod.ts, 6 in component.zod.ts) and one line split by the C2 note, whose words all survive. The PR's delta against main equals its delta against the previous base in 14 of 16 files; the other two differ only as tabled below. Premise re-checked: npm latest is still 17.4.0 (registry unmodified since 2026-09-09) and .changeset/17393-view-row-ceiling.md is still pending on origin/main, so the key is still unpublished.", "resolution_table": { "packages/spec/src/ui/component.zod.ts": [ { "hunk": "C1 — the conflict: object-kanban `limit` docblock, the 'THIRD door' paragraph (base 3186-3209)", "main_intent": "#20036 (0bf85eaae6): re-measure the paragraph's anchors at the new console pin f8a9d0fb0 — ListView.tsx:2979 -> :3067, ObjectView.tsx:1638 -> :1666, destructures ListView.tsx:2952 -> :3040 and ObjectView.tsx:1579 -> :1607, ObjectKanban.tsx:553 -> :554, the $top :676 -> :687, the short-circuit :559 -> :565 (6 lines).", "branch_intent": "Delete the paragraph: it documents how a VIEW's `kanban.limit` is spread onto the node, and ruling D retires that key. The lead-in becomes one line: 'The arm is REACHABLE: its guard reads THIS key on the node as AUTHORED, and this'.", "merged": "Branch side (1 line kept, 20 main-side lines dropped). Main's re-measured anchors go with the paragraph that cited them." }, { "hunk": "C2 — auto-merged, same docblock's re-measure preamble; edited because the merge made it untrue", "main_intent": "#20036: record the hop onto f8a9d0fb0, listing every anchor that moved, including the seven the retired paragraph cited.", "branch_intent": "No edit of its own, but the retirement removes the only text citing those seven anchors. Measured on the conflict-resolved docblock: :554, :565, :687 and the four ListView.tsx / ObjectView.tsx numbers occur once each (only in this list); every other new number in the list (:85, 680-690, 507-511, objectql.ts:3832, 373-388, 200-202, ObjectKanban.tsx:10) occurs twice.", "merged": "Main's text kept, with one line split to append: '(`:554`, `:565`, `:687` and the `ListView.tsx` / `ObjectView.tsx` pairs are that re-read's record only: they anchored the view-face `kanban.limit` spread, a key #19228 retired before any release carried it, so this block no longer cites them.)' — +5 lines / -1 line; the split line's words all survive." }, { "hunk": "every other main hunk (all #20036 pin citations; the object-timeline re-measure beside the branch's deletions included)", "main_intent": "Re-measured citations at f8a9d0fb0.", "branch_intent": "None.", "merged": "Auto-merged verbatim: 199 of #20036's 206 added lines are present byte-for-byte; the other 7 are C1's 6 and C2's split line. The object-timeline re-measure names ObjectTimeline.tsx / index.tsx / renderer.tsx, all still cited in the merged block, so it stays true." } ], "packages/spec/src/ui/view.zod.ts": [ { "hunk": "V1 — the conflict: the `limit` row-ceiling docblock, `rowLimitKey`, DEFAULT_VIEW_ROW_LIMIT, ROW_LIMIT_SUBJECT, RowLimitView (base 1360-1563)", "main_intent": "#20036: re-take both instruments of the per-kind `limit` route record at f8a9d0fb0 — the probe is still 0, the control goes from 13 lines / 6 files to 14 / 7, and every anchor MOVED with its text byte-identical (e.g. ObjectView.tsx:1697 -> :1725, :1725 -> :1753, ListView.tsx:4702 -> :4815, ObjectKanban.tsx:553 -> :554). 39 lines replace 31, all inside the docblock.", "branch_intent": "Delete the docblock and helper with the key (ruling D), and add the 4-line VIEW_ROW_BOUND_GUIDANCE constant the three blocks' refusal carries.", "merged": "Branch side (4 lines kept, 204 main-side lines dropped). Main's re-measured text goes with the key it describes. Not a sentence left elsewhere that names the retired key: DEFAULT_VIEW_ROW_LIMIT / ROW_LIMIT_SUBJECT / RowLimitView / rowLimitKey occur 0 times outside the pin test's three history comments." }, { "hunk": "all other main hunks (#19906's form `options` describe, its [#19678] docblock and the defineForm docblock; #20036's map / span citations)", "main_intent": "#19906: options describe and module-load refusal name the derive path for unspellable enum members. #20036: re-measured citations.", "branch_intent": "None.", "merged": "Auto-merged verbatim: all 106 lines #19906 added are present; 20 of #20036's 59 are present, and the 39 missing are exactly V1's." } ], "proof": "Per file, the sorted +/- line multiset of (main 5b9402d89b -> merged) equals (old base 61609edf81 -> e4204b9616) for 14 of 16 files. component.zod.ts: branch additions identical, plus the 5 C2 lines; deletions differ only by main-authored lines (7, all in main's diff). view.zod.ts: additions identical; deletions differ only by main-authored lines (39 in, 31 base lines out)." }, "regenerated": { "driver_deferred": "content/docs/references/data/object.mdx and content/docs/references/ui/view.mdx: the os-regen driver kept the branch side and dropped main's rows (the currency `scale` retirement of #19909, the form `options` describe of #19906, the `span` pin citation of #20036).", "step_2": "The script's rerun, reading the recorded pre-merge base 61609edf81, took main's side of those two (worktree only) and kept the branch bytes of the six regen paths main had not moved (api/protocol.mdx, ui/component.mdx, api-surface/ui.json, authorable-defaults/ui.json, authorable-surface/ui.json, export-origins/ui.json). Its step-3 commit was refused by the pre-commit hook (the designed path the script header records), so the regeneration commit carries both halves.", "step_4": "pnpm --filter @objectstack/spec build (locked, VERDICT command-exit 0), then check:generated reported exactly 1 of 15 stale (content/docs/references/**), then gen:docs. Staged diff read before committing: 6 lines, all main's dropped rows. Hook: 'deferred regeneration discharged — all artifacts current, marker cleared'.", "step_4_3_survival": "Every one of the 8 regen paths the PR touches now differs from main by exactly the PR's own delta (sorted line multiset equal); every other regen path equals main byte-for-byte (the path sets are identical). No hand re-apply was needed this round: main had not moved authorable-surface/ui.json." }, "gates": { "derivation": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at b7106a4781: 107 commands; change set = 16 paths vs merge base 5b9402d89 (three-dot), 614 changed lines (+86 / -528), under the 5000 human-merge threshold.", "reconciliation": "dispatch-gates --ran: 107 derived, 107 run, 0 NOT-MEASURED, 0 UNRUN (a DERIVED zero: all 107 recorded an exit code, none is 3).", "results": "106 exit 0; 1 exit 1 = node scripts/check-empty-changeset.mjs --base origin/main, the DELIBERATE CORRECTION class naming exactly .changeset/17393-view-row-ceiling.md and .changeset/19228-view-row-limit-route-record.md, the same red as at e4204b9616 and covered by the maintainer's word quoted in claim 5819348420.", "first_exit_3_then_green": "7 gates first exited 3 (PREREQUISITE NOT MET, measured nothing): lint check:doc-formula-expressions, lint check:doc-security-posture, spec check:skill-examples, check:docs-transcript-drift, check:dual-build-cjs-loads, check:lean-entry-closure, check:type-check-debt. After pnpm exec turbo run build --filter=./packages/* --filter=./packages/*/* --concurrency=2 under the lock (72 of 72 tasks, VERDICT command-exit 0), all 7 exited 0; the ran list records the final code. check:type-check-debt: 4 ledger entries re-measured, 53 raw tsc errors, none above its record.", "named_by_dispatch": "check:docs exit 0 (gate 46); check:generated exit 0, 15 of 15 current (gate 53); spec unit suite below.", "also_green": "check:api-surface, check:authorable-surface, check:export-origins, check:liveness, check:objectui-pin-citations, check:spec-parsed-alias, check:nul-bytes, check:merge-driver, check:adr-0087-registration --base origin/main, check-changeset-no-major --base origin/main.", "ci": "Not awaited, by rule. At push GitHub read the PR mergeable true, mergeable_state blocked (CI starting, plus the deliberate Check Changeset red)." }, "tests": "All on HEAD b7106a4781, heavy runs through os-verify-lock with slot issue-19228-merge2. (1) pnpm --filter @objectstack/spec exec vitest run --project local --maxWorkers=2 src/ui/component.test.ts src/ui/view.test.ts src/type-alias-convention.pin.test.ts: Test Files 3 passed (3), Tests 818 passed (818), VERDICT command-exit 0. (2) pnpm --filter @objectstack/spec test (the whole suite, run because both incoming spec commits and the conflicts are in this package): Test Files 535 passed (535), Tests 15714 passed | 2 todo (15716), VERDICT command-exit 0. (3) pnpm --filter @objectstack/spec typecheck: VERDICT command-exit 0 (tsc --noEmit, check:scripts-typecheck, check:test-typecheck OK: 53 files / 255 errors / 142 pinned signatures held). (4) Parse probe on the built dist/ui: a minimal kanban ListView parses; pagination.pageSize 50 parses; kanban.limit, gallery.limit and timeline.limit are each refused unrecognized_keys [limit] at their block with the 'This block declares no `limit`' bullet; control: kanban.bogus is refused WITHOUT the bullet; DEFAULT_VIEW_ROW_LIMIT and KanbanConfigParsed are absent from the entry. No ablation this round: nothing new is asserted.", "newer_main": "origin/main has since moved to b76aad5f6f (#20060: packages/client and one changeset only; no path under packages/spec, content/docs/references or .objectui-sha). Not merged: this round's scope was one merge.", "line_budget": "614 changed lines (+86 / -528, 16 files) vs 600 (+81 / -519) at e4204b9616. +5 / -1: the C2 note in component.zod.ts. -8: view.zod.ts, where the deleted docblock is main's re-measured text (39 lines) instead of the base's (31).", "pr_body": "No PATCH written. The body has no Verification section and names no head, so the dispatch's condition is not met. One value is stale: 'Net: 16 files, +81 / −519.' now reads +86 / −528. Offered, not sent: the body with only that line changed, and an issue_patch actions file for it, dry-run through fleet-write/dispatch.mjs (exit 0, packed, nothing sent). Paths are in the hand-off to the seat.", "deviations": [ "origin/main at dispatch was 3557f85fa5; the script's fetch took the tip at merge time, 5b9402d89b (#19909, which touches packages/spec data files, not the two conflicted files).", "The dispatch's 'every line main added survives' cannot hold for 45 of #20036's lines together with 'the branch's retirement survives': they are re-measured text inside the two passages that document the retired key. They were dropped with those passages (C1, V1) and the one surviving main sentence that pointed at them now says so (C2).", "os-regen-merge.sh step 3's commit was refused by the pre-commit hook, the designed path its header records; the regeneration commit discharged the deferral.", "The AGENTS.md driver-free probe, copied as written, failed here: the bare --shared clone of this shallow checkout gets no objects/info/alternates, so merge-tree answered 'not something we can merge' (exit 1, no paths). It was re-run with an alternates file pointing at the primary object store; see out_of_scope_findings.", "The full packages build and the full spec suite ran detached under the lock, each followed by one foreground tail --pid wait; both exited before the wait ended. No watcher is left.", "Commit trailers use the model-free pair (Claude-Session + Co-authored-by: Claude) that AGENTS.md and the dispatch require, not the model-named line the harness attribution reminder suggested." ], "mcp_calls": "0", "api_writes": "1 — POST /repos/objectstack-ai/objectstack/issues/19228/comments (this os-dev-report) via scripts/pm/post-stamped.mjs. git push of 77b9fc150e + b7106a4781 is not a REST write. No PR-body, label, assignee, ready, merge or MCP write. REST reads only: GET issues/19228/comments, pulls/19809.", "open_questions": [], "out_of_scope_findings": [ "class: a · The merge-tree probe AGENTS.md §11 and os-regen-merge.sh's header prescribe (git clone --bare --shared . PROBE.git, then merge-tree BASE HEAD) fails as written from a SHALLOW checkout, which this cloud container's primary checkout is: the clone gets no objects/info/alternates and is itself shallow, so a commit reachable only from refs/remotes (the origin/main tip) is absent and merge-tree answers 'not something we can merge' with exit 1 and no paths, the same exit code the recipe tells the reader means 'really conflicted'. Reproduced twice on 2026-09-25 from /home/user/objectstack (rev-parse --is-shallow-repository true); control: the same merge-tree with an alternates file naming the primary object store answered exit 1 with exactly the two conflicted paths. · dedupe words: merge-tree probe, bare shared clone, shallow, alternates, not something we can merge", "carrier: domain:spec#4 seat (PR #19809 owner) · .changeset/19228-view-row-limit-route-record.md still says it was measured 'at the objectui pin this repo builds against (.objectui-sha = 87af769e9)'. On the merged tree and on origin/main the pin is f8a9d0fb0, where #20036 moved the two ElementDataSourceGate.tsx anchors it cites (316-331 -> 373-388, 192-194 -> 200-202; element-data-source.ts is byte-identical, so 237-241 holds). The text names its pin, so it is still true as a reading at that pin; only 'the pin this repo builds against' is out of date. That line is #19533's, untouched by this PR. Not class a/b/c: noted, not filed." ] }
Generated by Claude Code
objectstack-fleet commented
on Sep 25, 2026 ContributorMore actionsLanded — PR #19809 →
a4ca69a9a0; card closed by hand, 2026-09-25T03:51Zdomain:specseat 4 (session_019c3Hi6ZMU1p6m6aA6Bz45d), takeover claim5819348420. Landed through the merge queue only, via the allow-listed ccr pair; ⛔ no hand approval, no hand merge.- Merged by the queue at 2026-09-25T02:57Z. The squash
a4ca69a9a0has one parent and is an ancestor oforigin/main. Content probe:git patch-id --stableof the squash's own diff equals that of the PR's diff from its merge base to headb7106a4781, the merge-round head the at-tier PASS5825578380names. The PR's own change carries the earlier PASS5820943315. - Ruling D (
5789634193) is executed in full:- the pending
.changeset/17393-view-row-ceiling.mdis deleted and19228-view-row-limit-route-record.mdtrimmed (DELIBERATE CORRECTIONS, confirmed5823701100), so no release carries the per-kindlimit; limitis gone fromgallery/timeline/kanban, together withrowLimitKeyandDEFAULT_VIEW_ROW_LIMIT;pagination.pageSizecarries the truncation obligation;- the component face is untouched;
- the key was never published, so no ADR-0087 conversion is owed.
- the pending
- The PR said
Part of #19228, so the closing keyword did not fire; this seat closes the cardcompletedby hand in the same act. The one thing ruling D kept outside this card, theobject-gallerycomponent ceiling behind objectui#7390, was already put to the maintainer there and stays out of scope here. pm:dispatchedand the assignee are removed in one label write. Nothing on this card remains in flight.
Generated by Claude Code
- Merged by the queue at 2026-09-25T02:57Z. The squash
- added 5 commits that reference this issue
on Sep 28, 2026
Path: P2 | studio-authoring(view row bounds) | 北极星「优先级」4
Filed by the
domain:specseat 2 execution seat (座位贴 #18549,session_01JbZnqu8bt6YqfJsr9vaFb3), from the ③ of the at-tier contract review of PR #19226 (record 5746847791, VERDICT: PASS). ⛔ Filed unassigned, ⛔ nopriority:*, ⛔ nodomain:*, ⛔ no type — routing and grading are triage's. ⛔ Not a claim. ⛔ Not a ruling: this card does not pick.The gap
PR #19226 (卡 #17393) declares a per-view-kind row ceiling
limitonGalleryConfigSchema/KanbanConfigSchema/TimelineConfigSchema, spelledz.number().int().positive().default(100)— an applied default, not merely a described one.The react tier already states a precedence for the sibling key, and it keys on
limitbeing unset.Verified by this seat, read at
origin/main7e4ecc5fdepackages/spec/src/ui/component.zod.ts:3038, verbatim from the.describe():and the mechanism it names,
:3023-3028:⇒ An applied default on the view face means a parsed view ALWAYS carries
limit. The 「fills it only when unset」 arm — the one arm that readspagination.pageSize— becomes unreachable for parsed views. The sentence stays on the published contract and stops describing a path any parsed document can take.ElementDataSourceGate.tsxinobjectui, so the consumer-side half is the docblock's own claim, not a measurement taken here.What has to be decided — two questions, and this card picks neither
limitandpagination.pageSize, what does the contract say wins? Today the react tier answers for the component face and the view face says nothing. ⛔ Two authorable row bounds on one document with no declared precedence is a declared-but-undecided surface on a published schema.PR #19226's implementation report states
@object-ui/types(objectql.zod.ts:1762) declares kanban'slimit. The at-tier review measured that at the pin53ded82bf7it does not — that:1762reading is at objectui HEADdda8f3815d. ⇒ 「the consumer already declares it」 is true at HEAD and false at the pin. ⛔ Do not build the acceptance face on the HEAD reading.ElementDataSourceGatetable itself, as stated above.Dedupe
pageSize→ 0 results over open and closed. ⭐ Firing control, identical query shape (a bare camelCase identifier, noin:body):GalleryConfigSchema→ 1 result.in:bodyboth return 0, including the control — soin:bodyis a dead shape for identifier tokens on this board and any zero taken that way is void. The zero above was taken with the shape whose control fires.Dedupe words
pagination.pageSize· per-kindlimit· row ceiling precedence ·ElementDataSourceGate· applied vs described default ·DEFAULT_VIEW_ROW_LIMITRefs
PR #19226 / 卡 #17393(声明该键的那一张)· 复核记录 5746847791 · objectui#7390(下游验收面)· objectui#7210
Generated by Claude Code