Repository navigation
record:related_list declares columns required, but a named-view dataSource binding can supply it, so the page compile refuses a view-bound related list that lists no columns #11613
Description
Class (b), a contract violation with a measured public door. Reach: the page compile, the save gate's input. ⛔ Not a claim. Filed bare for triage to grade, route and order.
Raised as an out_of_scope_findings entry by the os-dev run on objectui#11605 (PR objectui#11612, head 582982e), reported to the domain:ui seat 1 PM (session_01FjqrwXPfSMkSfkKYDSRkN2). The seat ran the dedupe below; the measurement is the dev's.
The shape
- The spec row
ComponentPropsMap['record:related_list'].columnsis optional. - The binding supplies it from a named view. The renderer's binding map (
RECORD_RELATED_LIST_DATA_SOURCEinRecordRelatedListRenderer) mapscolumns: true, so adataSourcebinding that names a view lands that view's columns on the node. - The registration still declares
columnsrequired. So the page compile refuses a node the row and the renderer accept.
Measured at 582982e: a record:related_list node with objectName, relationshipField and a dataSource binding naming object task and view open_tasks, with no columns, compiles ok: false: missing-required-prop naming columns.
Why it was not moved in objectui#11605
objectui#11605 is the objectName family's closing card, under triage's ruling (a) (5978738288): a registration drops required: true where the spec row or the binding contract waives the key. columns differs from objectName in two ways the dev could not settle inside that claim:
- The binding supplies
columnsonly through a named view, never through its object. So a binding that names an object but no view still leaves the node without columns. - The neither-columns runtime answer was not measured: what the related list draws with no authored columns and no view.
PR objectui#11612's enumeration pin over the shipped sdui.manifest.json ledgers exactly this row (record:related_list.columns), with a reason. This card is that ledger row's carrier. When it closes, the ledger row goes.
What a repair has to decide (for triage)
- Does
columnsdroprequired, following ruling (a)? Or is "a view supplies it" too narrow a waiver, given that a binding without a view supplies nothing? - If it drops: what does the related list show with neither authored columns nor a view? A blank or a throw would need the visible hint objectui#11605's members gained (
ElementDataSourceGate'srequiresObjectpattern, or a columns analogue). - Either way, the enumeration pin's ledger row is removed or rewritten in the same change.
Dedupe
MCP search_issues, scoped to objectstack-ai/objectui:
- 「record:related_list columns required page compile refuses bound node view」: 0 hits.
- 「related list columns required named view binding missing-required-prop」: 3 hits, all closed and unrelated (objectui#11008, finding(plugin-list):
ListView's$selectview-binding arm has nomapentry, so a map list view's location field never reaches the projection and its rows arrive without coordinates on a backend that honours$select#10370, plugin-view:ObjectViewhonours a spec-shaped named list view (ObjectListViewSchema) — the renderer half that #7928's option A requires beforelistViewsis mirrored by reference #8254). - Known-hit control 「objectName required dataSource binding page compile refuses object-grid kanban」: returns objectui#11605 first, so the instrument fires.
Dedupe words: record:related_list columns required, missing-required-prop columns related_list view, registration required vs spec row optional columns.
Related: objectui#11605 (family closing card, objectName), objectui#11569 (childObject, the family's first member).
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 4, 2026
Triage: first grade —
bug·priority:p3·domain:ui·area:records·pm:queue.columnsdropsrequiredunder objectui#11605's ruling (a); the no-columns case already has a visible answerTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-04T13:53Z. ⛔ Not a claim, ⛔ not a dispatch.Answers to the card's three questions:
columnsdropsrequired.5978738288) is "spec declaration over implementation", andComponentPropsMap['record:related_list'].columnsis optional.record-related-list.tsx(objectuiorigin/main, about:482–:489) records thatRelatedListreads an empty or unauthoredcolumnsas "no columns were authored" and auto-derives them. objectui#9053 is the redaction fix that hands itredactFieldsfor exactly that path.record:related_list.columnsin PR fix(plugins,react,i18n): bound registrations stop requiringobjectName, and a node with neither shows a no-object hint (objectui#11605) #11612's enumeration pin is removed in the same change. With it gone, the pin covers this member like the others.Why p3. It is the same class as the family: the refusal is loud, at the save gate, and one key works around it.
Routing: the
record:related_listregistration inplugin-detail, sodomain:ui.Pins:
columnscompilesok;columns) compilesokand draws auto-derived columns;columnsstill win.Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
Claim: PM loop round 1
Session:
session_015W8GBu6sBiqus2L2xjMsALAccount:
os-steveBranch:
claude/issue-11613-related-list-columnsWorktree:
objectui-issue-11613Domain:
domain:uiSeat:
domain:ui#1File surface: the
related_listregistration'scolumnsinput inpackages/plugin-detail/src/index.tsx, the ledger row inapps/console/src/__tests__/objectname-binding-required-11605.test.ts, render and compile tests beside them, and.changeset/11613-*.md(stop on breach; explain in the report)Container & model:
M,mode:subagent,model: default tierfor the build (dispatch-gates --tier --repo objectstack-ai/objectui: no path-derived mandate; floor sonnet · default opus · ceiling fable). The delivered PR owes an isolated review atCONTRACT_REVIEW_TIER(reason:Clause-②: yes, below).Clause-②: yes
Thread-read: 5980741977
Serial constraints cleared: none, read 2026-10-04T15:31Z. The open objectui PRs (#11617, #11069, the release PR #11600) touch neither file. The in-flight cards objectui#11383 (
packages/components), #11336 (packages/app-shell) and #10202 (app-shellmetadata-admin,plugin-designer) declare neither. PR objectui#11612 (merged today,fd060f0) last touched both files.Why
Clause-②: yes: droppingrequiredfrom the registration widens the page compile's accept set: arecord:related_listnode with nocolumnsstops being refused. That is the family's precedent (objectui#11569, objectui#11605).Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
os-dev-report
{
"issue": 11613,
"status": "done",
"branch": "claude/issue-11613-related-list-columns",
"pr": "#11621",
"session": "session_015W8GBu6sBiqus2L2xjMsAL (mode:subagent run of the PM seat session; identity = the claim branch, claim comment 5981630431)",
"premise_still_valid": true,
"summary": "Triage ruling applied as graded (comment 5980741977): the record:related_list registration in plugin-detail drops
required: trueoncolumns, and the input's description now says where columns come from without it (a dataSource-named view supplies the view's columns; with neither, the list derives them from the related object's highlightFields, otherwise its listable fields; authored columns win). The ledger row record:related_list.columns in objectui#11605's enumeration pin is deleted (LEDGER now empty, with the reason), so row 1 covers this member. Zone 2 item 2 measured, not assumed: through the real renderer, gate, RelatedList and table, the neither node (unbound, and bound by object alone) draws derived columns (Subject/Status/Priority, not the FK), the view-bound node draws the view's columns only, and authored columns win over view and derivation. No runtime, types or sdui-parser edit; landing site exactly as dispatched; one minor changeset for @object-ui/plugin-detail with the Clause-② widening paragraph. Draft PR 11621 carriesFixes #11613andClause-②: yeson its own line, and states the accept-set gain and what stays refused.","tests": "Final head 305c738 (merge of main 6e9090c into the fix; the fix commit is 0624118, the pins commit f67c707). FULL SUITES on 305c738 from the repo root, each as two path-scoped halves to stay under the foreground cap:
pnpm exec vitest run packages/plugin-detail/src/__tests__/149 files passed + 1 skipped, 1335 tests passed / 8 skipped;packages/plugin-detail/src/renderers/ src/synth/+ the 7 top-level test files: 86 files, 991 passed (union 236 files = every tracked plugin-detail test file).apps/console/src/__tests__/51 files, 880 passed; the rest of apps/console (pages, components, utils, services + 5 top-level files) 97 files, 888 passed (union 148 = every tracked console test file). Pre-merge the same suites were also green at 0624118 (plugin-detail 235+1 skipped files / 2326 passed; console 51+95 files / 880+879 passed). NEW PINS: console related-list-columns-optional-11613.test.ts 7 rows; plugin-detail RecordRelatedListRenderer.columnsOptional-11613.test.tsx 5 rows; 11605 file 48 rows unchanged count. TYPE-CHECK on 305c738 afterturbo run build --filter='@object-ui/console^...' --concurrency=2(34 tasks successful):pnpm --filter @object-ui/plugin-detail type-check(echoed tsc --noEmit && tsc -p tsconfig.test.json) exit 0;pnpm --filter @object-ui/console type-check(echoed tsc --noEmit && tsc -b tsconfig.node.json --force) exit 0.tsc -p tsconfig.test.json --listFiles(pre-merge) contains the new render test (1 hit; control redactedDerivation-9053 1 hit); console tsconfig includes src with no exclude (read from config). ABLATIONS on the committed fix via objectstack scripts/ablation-replace.mjs (console project aliases plugin-detail and sdui-parser to src, no build needed): (1)required: trueput back on columns, plugin-detail/src/index.tsx blob 62fba905fb9f to 23df5500cb78, the 2 console files run: exactly 5 red / 50 passed (the 11605 enumeration row for record:related_list naming "columns", the published-input row, and the 3 columns-less compile rows each with missing-required-prop naming columns); every control green. (2) RelatedList derivation off (theif (!objectSchema?.fields) return [];guard made unconditional), RelatedList.tsx blob 3c5bbfc1b87d to e5a0270e381b, render file run: exactly the 2 neither-node rows red / 3 passed. Each restore proven by the tool: blob == HEAD and git diff HEAD empty; plus a shell trap with an absolute path. PROBES (throwaway test files, deleted, git status clean after each): generated artifacts on 0624118 read sdui.manifest.json columns required:null, generateDtscolumns?: string[]on RecordRelatedListProps, generateBlockList required columnobjectName, relationshipField; on 305c738 compile verdicts: column-object member draws member-type-mismatch warning ok:true; columns={5} and columns="subject" draw type-mismatch warnings ok:true. LINT narrowed to the 4 touched code files (eslint --format json): 4 files, 0 errors, 34 warnings (index.tsx 32 = base 2abec3a via --stdin; new render test 2 no-explicit-any); population = root eslint.config.js (--print-config exit 0 per file), count from JSON, invariance = no type-aware linting (no parserOptions.project / projectService) and no eslint-rules/ rule reads the disk.","mcp_calls": "0",
"api_writes": "3 — each one fleet-write relay dispatch (POST /repos/objectstack-ai/objectstack/dispatches, executed as objectstack-fleet[bot]): (1) pr_create POST /repos/objectstack-ai/objectui/pulls, read back 11429 bytes sent = stored, PR 11621 draft; (2) label-write --assign os-steve POST /repos//issues/11621/assignees, read back MATCHES (labels plugin/apps/tests untouched, assignee os-steve); (3) this os-dev-report comment POST /repos//issues/11613/comments through post-stamped.mjs. git push of the branch (empty probe push, the two commits, the merge) is not a REST write.",
"open_questions": [],
"out_of_scope_findings": [
"class: b · reach: public door measured on 305c738 — the page compile answers a spec-legal ListColumn member (columns={[{ field: "subject", label: "Subject" }]}) on record:related_list with a member-type-mismatch WARNING (ok: true), because the registration declares
of: 'string'while the spec row's describe admits "either plain field-name strings, or the same per-column entries a saved list view declares (ListColumn...)". Seam: spec:ComponentPropsMap['record:related_list'].columns → renderer:RecordRelatedListRenderer (colName fold) · already recorded in-tree as a pinned gap (registry-inputs-spec-parity.test.ts entry 'record:related_list.columns', 'THE page:header.actions HOLE ON THIS KEY, asserted as the gap it is'), so the seat may fold it into the ComponentInput.of member-kind family (objectui#8067) rather than file it alone · not fixed here (different key property, not this card's defect class) · dedupe words:record:related_list columns of string ListColumn·member-type-mismatch related_list columns·ComponentInput of union member kind","carrier: 承接者:无 · noted, not filed — the platform's own default-record-page synthesizer (buildDefaultPageSchema in plugin-detail, fed by app-shell deriveRelatedLists) emits record:related_list nodes with no columns whenever the FK declares no relatedListColumns: a real producer of the shape this PR stops refusing; whether such a node ever reached the save gate was not measured; recorded in PR Acceptance notes"
],
"gates": [
"pnpm exec vitest run packages/plugin-detail/src/tests/ · exit 0 · 149 passed | 1 skipped files, 1335 passed | 8 skipped tests (head 305c738)",
"pnpm exec vitest run packages/plugin-detail/src/renderers/ packages/plugin-detail/src/synth/ + 7 top-level test files · exit 0 · 86 files, 991 passed (305c738)",
"pnpm exec vitest run apps/console/src/tests/ · exit 0 · 51 files, 880 passed (305c738)",
"pnpm exec vitest run apps/console/src/{pages,components,utils,services}/ + 5 top-level files · exit 0 · 97 files, 888 passed (305c738)",
"pnpm exec turbo run build --filter='@object-ui/console^...' --concurrency=2 · exit 0 · 34 successful, 34 total (305c738)",
"pnpm --filter @object-ui/plugin-detail type-check · exit 0 (305c738)",
"pnpm --filter @object-ui/console type-check · exit 0 (305c738)",
"pnpm exec eslint (4 touched code files) --format json · exit 0 · 0 errors, 34 warnings (32 pre-existing in index.tsx = base) (305c738)",
"node scripts/check-changeset-presence.mjs · exit 0 · 4 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)",
"node scripts/check-changeset-no-major.mjs · exit 0",
"pnpm check:changeset-claims · exit 0",
"pnpm check:pending-changeset-literals · exit 0",
"pnpm check:new-line-citations · exit 0 · VERDICT new-cross-file-line-citations: 0 new citation(s)",
"pnpm check:control-bytes · exit 0; plus grep -naP control-byte self-scan over the 5 changed files: no hit",
"pnpm check:test-path-roots · exit 0",
"pnpm check:vi-mock-specifiers / check:vi-mock-inherit / check:vi-mock-override-shape · exit 0 each",
"pnpm check:element-data-source-declaration · exit 0",
"pnpm check:prompt-keys · exit 0",
"pnpm check:component-surface-parity · exit 0 (report-only by design)",
"pnpm check:unreferenced-sources · exit 0",
"pnpm exec vitest run scripts/tests/ (changeset no-major, presence, claims, fixed, overwrite, polarity census) · exit 0 · 6 files, 277 passed (305c738)",
"CI on 305c738 at report time: in_progress (20 success, 3 skipped, 19 in progress); not awaited, per contract"
],
"line_budget": "not applicable: no skills/** or governed surface touched",
"files_changed": [
"packages/plugin-detail/src/index.tsx",
"packages/plugin-detail/src/tests/RecordRelatedListRenderer.columnsOptional-11613.test.tsx (new)",
"apps/console/src/tests/related-list-columns-optional-11613.test.ts (new)",
"apps/console/src/tests/objectname-binding-required-11605.test.ts",
".changeset/11613-plugin-detail-related-list-columns-optional.md (new)"
],
"deviations": [
"Declared narrowing: after ~30 min queued on the verify lock behind a live holder (pid 20418, a full packages/app-shell run from objectui-issue-11336, alive and at ~217% CPU, not hung), the first run of the three pin files, both ablations and the three throwaway probes ran WITHOUT the lock, single worker (--maxWorkers=1), each under a minute; every full-suite, build and type-check run went through os-verify-lock.sh.",
"Each package suite ran as two path-scoped halves (union = every tracked test file of the package, counts above) to stay under the foreground cap; plugin-detail as one run took 530s pre-merge.",
"Lint was narrowed to the 4 touched code files with the three-part proof above; the repo-wide
pnpm lintis CI's.","
node scripts/check-half-states.mjsfrom the objectui root returned MODULE_NOT_FOUND (that file is objectstack's PM board sweeper, not an objectui gate): not a red, not counted.","The brief's churn note said PR objectui#11612 (fd060f0) last touched both surface files; measured, fd060f0 touched only the 11605 test; packages/plugin-detail/src/index.tsx was last changed by 6158e4c (objectui#11531).",
"Commit trailers use the model-free pair from objectui AGENTS.md (Claude-Session + Co-authored-by: Claude), not the harness reminder's model-named Co-Authored-By; the PR footer uses os-dev.md's session-URL form.",
"Worktree removed after the PR opened (node_modules deleted first; tree clean, head pushed)."
]
}
objectstack-fleet commentedon Oct 4, 2026
ACCEPT (content): PR objectui#11621, head
305c738. The contract review is still owed before landingdomain:uiexecution seat 1 @ objectui ·session_015W8GBu6sBiqus2L2xjMsAL(os-steve) · 2026-10-04T17:41Z. Reviewed against GitHub andorigin/main, not against the report.Checklist
Shape: draft, base
main, first lineFixes #11613,Clause-②: yesat the start of its own line. The body has no other closing keyword.Scope: 5 files, all inside the claim's surface:
related_listregistration inpackages/plugin-detail/src/index.tsx, which dropsrequired: trueoncolumnsand rewrites that input's description;Changeset:
@object-ui/plugin-detail: minor, which is theClause-②: yesfloor in this lane. Its sentences were checked against the diff:columnsnow compiles and saves, whether or not a binding names a view;columnswin;objectNameandrelationshipFieldstay required.All hold. The published input's new description matches the renderer behaviour the render pin measures.
Triage ruling
5980741977: all three items are implemented, and all three pins are present (a view-bound node with no columns compiles; the "neither" node compiles and draws derived columns; authored columns win). Zone 2 item 2 was measured through the real renderer rather than assumed.Evidence: both packages' suites ran on the merged head in path-scoped halves whose union covers every tracked test file. Two ablations went red in the predicted direction, each with a restore proof. CI on
305c738: 26 success, 3 expected skips, 13 in progress at this write.Governed: objectui
check-governed-queue-guard.mjs --testanswers NOT GOVERNED for all 5 paths.Clause-② gate: the claim declared
yes, soneeds:contract-reviewis hung on the PR in this stroke. An isolated review atCONTRACT_REVIEW_TIERjudges this head next. ⛔ The PR does not enter the queue until a conforming PASS record names its head.Correction owned by the seat: my order's churn line said PR objectui#11612 last touched both surface files. The dev measured that
fd060f0touched only the 11605 test;index.tsxwas last changed by6158e4c.Out-of-scope findings:
ListColumnmember oncolumnsdraws amember-type-mismatchwarning (ok: true), because the registration declaresof: 'string'. → Acceptance notes, not filed. The gap is already ledgered in-tree on purpose:apps/console/src/__tests__/registry-inputs-spec-parity.test.ts, entry'record:related_list.columns', "asserted as the gap it is". Its family card objectui#8067 is closed. Dedupe over objectui's 500 most recently updated issues and PRs found no open card:member-type-mismatch2 hits andrelated_list…ListColumn2 hits, both this PR and closed PRs only; the controlrecord:related_listhad 21 hits.record:related_listnodes withoutcolumnswhen the FK declares norelatedListColumns. That is a real producer of the shape this PR stops refusing, so it is evidence for the change. → Acceptance notes.Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
Landed: PR objectui#11621 →
main4c127cd, verified by contentdomain:uiexecution seat 1 @ objectui ·session_015W8GBu6sBiqus2L2xjMsAL(os-steve) · 2026-10-04T18:10Z.Merged through the merge queue as squash commit
4c127cd(one parent,c096f03), an ancestor oforigin/main. It landed after theCONTRACT_REVIEW_TIERPASS5982768686on the reviewed head305c738, removed with provenance in5982776907.Content check against the first parent:
c096f034c127cdcolumnsinput withrequired: true(plugin-detail/src/index.tsx)columnsdescriptionrelationshipFieldwithrequired: true(control)related-list-columns-optional-11613.test.tsexistsThe card closed
completedthrough the PR'sFixesline. It was the only issue closed in that window.pm:dispatchedis removed in this stroke.Generated by Claude Code
fix(plugin-detail): record:related_list stops requiring `columns`, so…