You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
plugin-detail: record:related_list reads its declared actions and renders them on the related list, host-bridge actions as the default (objectstack#20665 ruling ENFORCE) #11163
Child of objectstack-ai/objectstack#20665, filed by the director seat (objectstack#12708, session_01AsCNgFBs8HCjwhyHQsFbx3) on the maintainer's ruling ENFORCE (batch #247, 2026-09-30, 「业务上需要支持,ENFORCE」; the ruling record is on objectstack#20665). objectstack#20665 is pm:blocked on this card. ⛔ Not a claim.
What the ruling decided
record:related_list.actions (packages/spec/src/ui/component.zod.ts:1285, "Action IDs available for related records") is declared, published and parsed, and no renderer reads it. Under ruling A′ ④ (#18900) the maintainer chose ENFORCE on business need: a related list carries its own action buttons, as a Salesforce related list does (the standard New plus custom list buttons), and CRM authoring — hotcrm's included — configures actions per list.
What this card builds (objectui plugin-detail, record-related-list.tsx)
The renderer reads schema.actions: each action ID resolves through the existing action registry and renders on the list.
Host-bridge actions stay the default when actions is absent; when the author declares actions, the authored list is what renders (the composition rule the maintainer's letter implies — the seat states it in the PR and pins it).
An action ID the registry cannot resolve is refused loudly where the registry resolves it (an author-visible refusal, never a silently dropped button).
The parity ledger's last exemption, NO_READ_SITE_TO_PIN for this key (apps/console/src/__tests__/registry-inputs-spec-parity.test.ts), becomes a member pin, and MEMBER_PIN_EXEMPTION_CEILING goes 1 → 0.
Pins: authored actions render in order; absent actions renders the host default; an unresolvable ID is refused; the parity ledger holds no exemption.
Measurement the seat records first (it no longer flips the word)
Whether the host bridge already offers a per-list action configuration. If it does, the PR states how the two channels compose (authored actions wins, the bridge is the default) rather than treating the key as a duplicate; the maintainer's letter is ENFORCE either way.
After landing
objectstack#20665 closes: the spec key is unchanged, its liveness row flips to live with this pin as the read site.
Related: objectstack#20665 (the ruling), objectui#8071 (the parity population), objectui#7300 (the closed tracker this replaces), objectui#11113 (slice 18, the ceiling at 1).
Claim: PM loop round 1
Session: session_0122Knsowci76D2rBWReCzzZ
Account: os-warren (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-11163-related-list-actions
Worktree: objectui-issue-11163
Domain: domain:ui
Seat: domain:ui#1
File surface:
packages/plugin-detail/src/renderers/record-related-list.tsx: the renderer reads schema.actions and resolves each ID through the existing action registry. Host-bridge actions stay the default when actions is absent.
packages/plugin-detail/src/index.tsx: the record:related_list registration's inputs, only if actions must be declared there.
packages/plugin-detail/src/RelatedRecordActionsBridge* / RelatedList.tsx: only where the authored list replaces the bridge default.
apps/console/src/__tests__/registry-inputs-spec-parity.test.ts: the record:related_list.actionsNO_READ_SITE_TO_PIN exemption becomes a member pin, and MEMBER_PIN_EXEMPTION_CEILING goes to 0.
Their pins, and one .changeset/11163-*.md.
⛔ Not RelatedToolbarButton's visible truthiness gate (objectui#11244, a finding awaiting triage). ⛔ Not DetailView.tsx (PR objectui#11246, seat 2). The dev stops on a breach and explains it in the report.
Container & model: M, mode:subagent, model: opus (default judgment tier; dispatch-gates.mjs --tier answers no path-derived mandate for objectui paths)
Clause-②: yes
Thread-read: none
Serial constraints cleared: read 2026-09-30T18:58Z at objectui origin/main. Open PR objectui#11246 (seat 2, objectui#9843) touches plugin-detail's DetailView.tsx, package.json and README.md, not the related-list files. No open PR touches record-related-list.tsx, RelatedList.tsx, RelatedRecordActionsBridge or the parity ledger. PR objectui#11237 (objectui#11212), which last edited RelatedList.tsx, merged as 8bab1571d9. area:records: no other card on this axis is in flight on these files.
Scope: the maintainer's ruling ENFORCE on objectstack-ai/objectstack#20665 (batch #247, 「业务上需要支持,ENFORCE」), as the card body records it, and the card body's build list: authored actions render in order; absent actions renders the host default; an unresolvable ID is refused loudly; the parity ledger holds no exemption. PR says Fixes #11163. Clause-②: yes — why: a published block starts honouring a declared key it ignored (a behaviour change for every document that authors actions), and its registration may declare a new input. Unsure ⇒ yes.
{
"issue": 11163,
"status": "done",
"branch": "claude/issue-11163-related-list-actions",
"pr": "#11263",
"session": "session_0122Knsowci76D2rBWReCzzZ",
"premise_still_valid": true,
"summary": "record:related_list now reads its declared actions (ENFORCE ruling on objectstack-ai/objectstack#20665). Composition rule, stated in the PR and pinned: absent = the host bridge's list_toolbar/list_item actions unchanged, with no lookup; authored = the authored list replaces the default, in authored order, each id resolved against the related object's registered actions (useMetadataItem + resolveDeclaredActionIds, the record:quick_actions.actionNames lookup, no second registry) and placed by its own locations (list_toolbar = header, list_item = row menu), run by the bridge's executor; [] = no actions (New/Edit/Delete/View are not action ids and stay the host's). An unresolvable id, an id with no list location, or a non-id array is named in a role=status notice on the list (never while the lookup is in flight; the resolvable entries still render). Measured: the bridge has NO per-list channel (resolve is keyed on the child object), and the registration already declared actions, so index.tsx and the bridge are untouched. Parity ledger: the NO_READ_SITE_TO_PIN exemption becomes a MEMBER_PINS entry and the constant is deleted; MEMBER_PIN_EXEMPTION_CEILING goes 5 → 4, not 1 → 0 as the card says, because the objectui#11111 bookings owed to objectui#11168 (4 units) landed in between.",
"tests": "RED FIRST at ae0b9d3 (renderer unmodified): vitest run packages/plugin-detail/src/tests/RecordRelatedListRenderer.authoredActions-11163.test.tsx → 'Tests 10 failed | 2 passed (12)', e.g. "expected [ 'invite', 'export_csv' ] to deeply equal [ 'export_csv', 'invite' ]". After the fix, same file → 'Tests 12 passed (12)'. ABLATION (fix committed at 0de68bb, via objectstack scripts/ablation-replace.mjs, anchor hit x1 → x0, blob 35704b30774d → e4cbb940b1ef): removing the in-flight guard → 'Tests 1 failed | 11 passed (12)', exactly 'CONTROL: no refusal is drawn while the lookup is still in flight'; restore: 'ok restored: blob == HEAD (35704b30774d) and git diff HEAD is empty'. No dist in the path (tests import the renderer relatively). FINAL head 95a8cd5 (branch merged with main af9e957 after PR objectui#11246 landed; pnpm install + deps rebuilt): build pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-detail^...' build → 'VERDICT command-exit 0'; pnpm --filter @object-ui/plugin-detail type-check (script name echoed) → 'VERDICT command-exit 0'; tsc -p tsconfig.test.json --listFiles lists the new test, relatedListActions.ts and record-related-list.tsx; vitest run packages/plugin-detail/src/tests/ → 'Test Files 144 passed | 1 skipped (145)', 'Tests 1296 passed | 8 skipped (1304)'; vitest run over the other 83 plugin-detail test files → 'Test Files 83 passed (83)', 'Tests 962 passed (962)'; vitest run over the 25 suites outside plugin-detail that git grep -l 'record:related_list' finds (incl. apps/console registry-inputs-spec-parity.test.ts) → 'Test Files 25 passed (25)', 'Tests 1020 passed (1020)'. Gates exit 0: check:action-forward-parity, check:component-surface-parity (REPORT-ONLY, no record:related_list row), check:handler-key-reads, check:new-line-citations ('VERDICT new-cross-file-line-citations: 0 new citation(s)'), check:control-bytes, check:doc-fences, docs:check-links, check-changeset-presence ('1 changeset(s): .changeset/11163-related-list-actions.md'), markdown-test-inputs --audit, check:doc-types, check:doc-example-ids, check:docs-route-closure, check:doc-example-readers, check:changeset-claims, check:pending-changeset-literals, check:test-path-roots, check:unreferenced-sources, check:spec-symbols, check:phantom-deps, check:element-data-source-declaration, check:action-ref-convention, check:self-import. eslint --no-inline-config on the 4 changed TS files: 0 errors, 17 warnings all on pre-existing lines of record-related-list.tsx (a narrowed run, not a measurement of the lint population). NOT MEASURED: check:doc-snippets and check:doc-examples (exit 2 PRECONDITION NOT MET, 34 packages unbuilt; they read TS fences / @example, the diff adds a json fence); check:sdui-registration-pins (exit 2, no console build; no registration changed); apps/console type-check and repo-wide pnpm lint (CI). CI on 95a8cd5 at report time: 42 check runs, 20 success, 3 skipped, 19 in_progress, 0 failed.",
"mcp_calls": "0 - no MCP GitHub tool called",
"api_writes": "3 - all through the fleet-write relay (POST /repos/objectstack-ai/objectstack/dispatches, landing as objectstack-fleet[bot]): (1) pr_create → POST /repos/objectstack-ai/objectui/pulls (draft, PR 11263); (2) label-write --assign os-warren → POST /repos//issues/11263/assignees; (3) this os-dev-report comment → POST /repos//issues/11163/comments. git push x4 (not REST).",
"gates": {
"build_deps": "exit 0",
"type_check_plugin_detail": "exit 0",
"vitest_plugin_detail": "228 files: 227 passed, 1 skipped; 2258 passed, 8 skipped",
"vitest_outside_suites": "25 files passed, 1020 tests passed",
"check:action-forward-parity": 0,
"check:component-surface-parity": 0,
"check:handler-key-reads": 0,
"check:new-line-citations": 0,
"check:control-bytes": 0,
"check:doc-fences": 0,
"docs:check-links": 0,
"check-changeset-presence": 0,
"markdown-test-inputs --audit": 0,
"check:doc-types": 0,
"check:doc-example-ids": 0,
"check:docs-route-closure": 0,
"check:doc-example-readers": 0,
"check:changeset-claims": 0,
"check:pending-changeset-literals": 0,
"check:test-path-roots": 0,
"check:unreferenced-sources": 0,
"check:spec-symbols": 0,
"check:phantom-deps": 0,
"check:element-data-source-declaration": 0,
"check:action-ref-convention": 0,
"check:self-import": 0,
"check:doc-snippets": "NOT MEASURED (exit 2 precondition)",
"check:doc-examples": "NOT MEASURED (exit 2 precondition)",
"check:sdui-registration-pins": "NOT MEASURED (exit 2 precondition)",
"ci": "in_progress"
},
"line_budget": "n/a - no skills/** or governed surface touched (check-governed-queue-guard --test: NOT GOVERNED)",
"files_changed": [
".changeset/11163-related-list-actions.md (+14 -0)",
"apps/console/src/tests/registry-inputs-spec-parity.test.ts (+37 -45)",
"content/docs/guide/slotted-pages.md (+32 -0)",
"packages/plugin-detail/src/tests/RecordRelatedListRenderer.authoredActions-11163.test.tsx (+314 -0, new)",
"packages/plugin-detail/src/renderers/record-related-list.tsx (+108 -2)",
"packages/plugin-detail/src/renderers/relatedListActions.ts (+171 -0, new)"
],
"deviations": [
"MEMBER_PIN_EXEMPTION_CEILING 5 → 4, not the card's 1 → 0: the objectui#11111 decision 3 = B bookings (4 element:* units owed to objectui#11168) landed after the card was written; they are untouched.",
"content/docs/guide/slotted-pages.md is outside the claim's file list; added under objectui AGENTS.md commandment #2 (docs-driven). The plugin-detail README was deliberately not touched (PR objectui#11246's surface).",
"packages/plugin-detail/src/renderers/relatedListActions.ts is a new module beside the renderer (the pure resolve-and-place rule), so the renderer file keeps exporting components only.",
"Merged main af9e957 into the branch after PR objectui#11246 landed (per the dispatch's same-day churn line); the full matrix was rerun on the merged head.",
"Commit trailers use objectui AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude) rather than the harness reminder's model-named trailer; PR footer uses the os-dev session-URL form. Both per the stated precedence.",
"RelatedRecordActionsBridge, RelatedList.tsx and index.tsx are untouched: the bridge has no per-list channel and the registration already declared the key."
],
"open_questions": [],
"out_of_scope_findings": [
"carrier: the seat that settles objectstack-ai/objectstack#20665 and flips its liveness row · noted, not filed · objectstack's action-name-undefined lint (validate-action-name-refs.ts, objectstack#20105) deliberately does not walk record:related_list.actions; now that the key renders, a misspelled id is refused only at runtime (the notice). Dedupe words: action-name-undefined, related_list actions, validate-action-name-refs, authoring-time refusal",
"carrier: 承接者:无 · noted, not filed (no reach measured) · the record_related action location: spec ACTION_LOCATIONS JSDoc 'actions on a related list section inside a record' and the platform docs table 'Related-list sections', while the related list (bridge default and now the authored channel) places by list_item/list_toolbar; an action declaring only record_related and named in actions is refused by the notice. Dedupe words: record_related location, related-list sections, ACTION_LOCATIONS, related list placement",
"carrier: 承接者:无 · noted, not filed · the bridge supplies onRowAction/onToolbarAction only when its own derived list for that surface is non-empty; authored placement uses the same rule over the same registry, so they agree whenever the bridge's objects and the MetadataProvider agree; on disagreement the authored surface is withheld (never a dead button). Dedupe words: onRowAction, onToolbarAction, RelatedRecordActionsBridge executor",
"carrier: objectui#11244 (finding awaiting triage) · not touched · authored toolbar actions flow through RelatedToolbarButton, whose visible truthiness gate is that card's; no pin fixture declares visible, so it does not bite these pins"
]
}
✅ ACCEPT: PR objectui#11263 at 95a8cd520; ready and auto-merge follow this ACCEPT
domain:ui seat 1 · session_0122Knsowci76D2rBWReCzzZ · 2026-09-30T20:35Z. Checked against the diff and the head's check-runs. Claim 5917731712; dev report 5919004096.
Contract review at CONTRACT_REVIEW_TIER: PASS on this head, which is the landing head (5919231109). Implemented-by: claude/issue-11163-related-list-actions, Reviewed-by: session_0122Knsowci76D2rBWReCzzZ.
item
reading
the ruling: ENFORCE on objectstack#20665 (「业务上需要支持,ENFORCE」)
record:related_list now reads its declared actions
the composition rule (stated in the PR and pinned)
Absent: the host bridge's list_toolbar / list_item actions, unchanged, with no lookup. Authored: the authored list replaces the default, in authored order. Each id resolves against the related object's registered actions through the existing record:quick_actions.actionNames lookup (useMetadataItem + resolveDeclaredActionIds; no second registry), is placed by its own locations, and is run by the bridge's executor. []: no actions. New / Edit / Delete / View are not action ids and stay the host's
the loud refusal
a role="status" notice on the list names every id that resolves nowhere or has no list location, and a non-id value. It is never drawn while the lookup is in flight (ablation: removing that guard reddens exactly the in-flight control), and the resolvable entries still render
red first
10 of 12 red at base, then 12 of 12
the parity ledger
the record:related_list.actions exemption becomes a MEMBER_PINS entry, and NO_READ_SITE_TO_PIN is deleted. MEMBER_PIN_EXEMPTION_CEILING goes 5 → 4, not the card's 1 → 0. The review verified this against main's history: 1 → 7 at objectui#11073 after the card was written, 7 → 5 at objectui#11168; this diff only lowers it
measured, not changed
the bridge has no per-list channel, and the registration already declared actions. So index.tsx, the bridge and RelatedList.tsx are untouched
semver
@object-ui/plugin-detail minor: the accept set is unchanged, and a published block now honours a key it ignored. Clause-②: yes (the claim)
CI
head 95a8cd520: 43 runs, 40 success, 3 expected skips, 0 failure; Spec Main Shape Gate and all eight Test shards success
main since the merge base
the branch merged main (af9e9572c7) once, after PR objectui#11246 landed; the net diff is exactly the PR's 6 files. A test merge onto current main is clean
scope / governed
6 files, +676 / −47; check-governed-merges.mjs: not governed. Fixes #11163. On landing, objectstack#20665's renderer half is met
The bridge supplies row and toolbar handlers only for non-empty derived surfaces, and the authored channel follows the same rule → Acceptance notes. RelatedToolbarButton's visible gate stays with objectui#11244.
PR objectui#11263 (Fixes #11163) merged through the merge queue as f4ed2387e9, which is on origin/main. The merge closed the card by its Fixes keyword. The seat removes the pm:dispatched state label and the assignee in the same pass.
It merged at 2026-09-30T20:54:46Z. Verified by content: all 6 of its files on origin/main are blob-identical to the landing head 95a8cd520, and the merge's first-parent diff is exactly those 6 files (+676 / −47).
What ships: record:related_list reads its declared actions (the ENFORCE ruling on objectstack#20665):
absent, the host bridge's list_toolbar / list_item actions stay as they were;
authored, the list replaces the default, in authored order. Each id resolves through the existing record:quick_actions.actionNames lookup, is placed by its own locations, and runs on the bridge's executor;
[] means no actions.
An id that resolves nowhere, or has no list location, is named in a role="status" notice on the list. The parity ledger's exemption became a MEMBER_PINS entry, and MEMBER_PIN_EXEMPTION_CEILING went 5 → 4.
The record is 5919231109 (at-tier PASS on the landing head), and the ACCEPT is 5919287238.
Activity
objectstack-fleet commentedon Sep 30, 2026
Claim: PM loop round 1
Session:
session_0122Knsowci76D2rBWReCzzZAccount:
os-warren(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-11163-related-list-actionsWorktree:
objectui-issue-11163Domain:
domain:uiSeat:
domain:ui#1File surface:
packages/plugin-detail/src/renderers/record-related-list.tsx: the renderer readsschema.actionsand resolves each ID through the existing action registry. Host-bridge actions stay the default whenactionsis absent.packages/plugin-detail/src/index.tsx: therecord:related_listregistration'sinputs, only ifactionsmust be declared there.packages/plugin-detail/src/RelatedRecordActionsBridge*/RelatedList.tsx: only where the authored list replaces the bridge default.apps/console/src/__tests__/registry-inputs-spec-parity.test.ts: therecord:related_list.actionsNO_READ_SITE_TO_PINexemption becomes a member pin, andMEMBER_PIN_EXEMPTION_CEILINGgoes to 0..changeset/11163-*.md.⛔ Not
RelatedToolbarButton'svisibletruthiness gate (objectui#11244, afindingawaiting triage). ⛔ NotDetailView.tsx(PR objectui#11246, seat 2). The dev stops on a breach and explains it in the report.Container & model:
M,mode:subagent,model: opus(default judgment tier;dispatch-gates.mjs --tieranswers no path-derived mandate for objectui paths)Clause-②: yes
Thread-read: none
Serial constraints cleared: read 2026-09-30T18:58Z at objectui
origin/main. Open PR objectui#11246 (seat 2, objectui#9843) touchesplugin-detail'sDetailView.tsx,package.jsonandREADME.md, not the related-list files. No open PR touchesrecord-related-list.tsx,RelatedList.tsx,RelatedRecordActionsBridgeor the parity ledger. PR objectui#11237 (objectui#11212), which last editedRelatedList.tsx, merged as8bab1571d9.area:records: no other card on this axis is in flight on these files.Scope: the maintainer's ruling ENFORCE on objectstack-ai/objectstack#20665 (batch #247, 「业务上需要支持,ENFORCE」), as the card body records it, and the card body's build list: authored actions render in order; absent
actionsrenders the host default; an unresolvable ID is refused loudly; the parity ledger holds no exemption. PR saysFixes #11163.Clause-②: yes— why: a published block starts honouring a declared key it ignored (a behaviour change for every document that authorsactions), and its registration may declare a new input. Unsure ⇒yes.domain:uiseat 1 · claim · 2026-09-30T18:58ZGenerated by Claude Code
objectstack-fleet commentedon Sep 30, 2026
os-dev-report
{
"issue": 11163,
"status": "done",
"branch": "claude/issue-11163-related-list-actions",
"pr": "#11263",
"session": "session_0122Knsowci76D2rBWReCzzZ",
"premise_still_valid": true,
"summary": "record:related_list now reads its declared
actions(ENFORCE ruling on objectstack-ai/objectstack#20665). Composition rule, stated in the PR and pinned: absent = the host bridge's list_toolbar/list_item actions unchanged, with no lookup; authored = the authored list replaces the default, in authored order, each id resolved against the related object's registered actions (useMetadataItem + resolveDeclaredActionIds, the record:quick_actions.actionNames lookup, no second registry) and placed by its own locations (list_toolbar = header, list_item = row menu), run by the bridge's executor; [] = no actions (New/Edit/Delete/View are not action ids and stay the host's). An unresolvable id, an id with no list location, or a non-id array is named in a role=status notice on the list (never while the lookup is in flight; the resolvable entries still render). Measured: the bridge has NO per-list channel (resolve is keyed on the child object), and the registration already declaredactions, so index.tsx and the bridge are untouched. Parity ledger: the NO_READ_SITE_TO_PIN exemption becomes a MEMBER_PINS entry and the constant is deleted; MEMBER_PIN_EXEMPTION_CEILING goes 5 → 4, not 1 → 0 as the card says, because the objectui#11111 bookings owed to objectui#11168 (4 units) landed in between.","tests": "RED FIRST at ae0b9d3 (renderer unmodified): vitest run packages/plugin-detail/src/tests/RecordRelatedListRenderer.authoredActions-11163.test.tsx → 'Tests 10 failed | 2 passed (12)', e.g. "expected [ 'invite', 'export_csv' ] to deeply equal [ 'export_csv', 'invite' ]". After the fix, same file → 'Tests 12 passed (12)'. ABLATION (fix committed at 0de68bb, via objectstack scripts/ablation-replace.mjs, anchor hit x1 → x0, blob 35704b30774d → e4cbb940b1ef): removing the in-flight guard → 'Tests 1 failed | 11 passed (12)', exactly 'CONTROL: no refusal is drawn while the lookup is still in flight'; restore: 'ok restored: blob == HEAD (35704b30774d) and git diff HEAD is empty'. No dist in the path (tests import the renderer relatively). FINAL head 95a8cd5 (branch merged with main af9e957 after PR objectui#11246 landed; pnpm install + deps rebuilt): build pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-detail^...' build → 'VERDICT command-exit 0'; pnpm --filter @object-ui/plugin-detail type-check (script name echoed) → 'VERDICT command-exit 0'; tsc -p tsconfig.test.json --listFiles lists the new test, relatedListActions.ts and record-related-list.tsx; vitest run packages/plugin-detail/src/tests/ → 'Test Files 144 passed | 1 skipped (145)', 'Tests 1296 passed | 8 skipped (1304)'; vitest run over the other 83 plugin-detail test files → 'Test Files 83 passed (83)', 'Tests 962 passed (962)'; vitest run over the 25 suites outside plugin-detail that git grep -l 'record:related_list' finds (incl. apps/console registry-inputs-spec-parity.test.ts) → 'Test Files 25 passed (25)', 'Tests 1020 passed (1020)'. Gates exit 0: check:action-forward-parity, check:component-surface-parity (REPORT-ONLY, no record:related_list row), check:handler-key-reads, check:new-line-citations ('VERDICT new-cross-file-line-citations: 0 new citation(s)'), check:control-bytes, check:doc-fences, docs:check-links, check-changeset-presence ('1 changeset(s): .changeset/11163-related-list-actions.md'), markdown-test-inputs --audit, check:doc-types, check:doc-example-ids, check:docs-route-closure, check:doc-example-readers, check:changeset-claims, check:pending-changeset-literals, check:test-path-roots, check:unreferenced-sources, check:spec-symbols, check:phantom-deps, check:element-data-source-declaration, check:action-ref-convention, check:self-import. eslint --no-inline-config on the 4 changed TS files: 0 errors, 17 warnings all on pre-existing lines of record-related-list.tsx (a narrowed run, not a measurement of the lint population). NOT MEASURED: check:doc-snippets and check:doc-examples (exit 2 PRECONDITION NOT MET, 34 packages unbuilt; they read TS fences / @example, the diff adds a json fence); check:sdui-registration-pins (exit 2, no console build; no registration changed); apps/console type-check and repo-wide pnpm lint (CI). CI on 95a8cd5 at report time: 42 check runs, 20 success, 3 skipped, 19 in_progress, 0 failed.",
"mcp_calls": "0 - no MCP GitHub tool called",
"api_writes": "3 - all through the fleet-write relay (POST /repos/objectstack-ai/objectstack/dispatches, landing as objectstack-fleet[bot]): (1) pr_create → POST /repos/objectstack-ai/objectui/pulls (draft, PR 11263); (2) label-write --assign os-warren → POST /repos//issues/11263/assignees; (3) this os-dev-report comment → POST /repos//issues/11163/comments. git push x4 (not REST).",
"gates": {
"build_deps": "exit 0",
"type_check_plugin_detail": "exit 0",
"vitest_plugin_detail": "228 files: 227 passed, 1 skipped; 2258 passed, 8 skipped",
"vitest_outside_suites": "25 files passed, 1020 tests passed",
"check:action-forward-parity": 0,
"check:component-surface-parity": 0,
"check:handler-key-reads": 0,
"check:new-line-citations": 0,
"check:control-bytes": 0,
"check:doc-fences": 0,
"docs:check-links": 0,
"check-changeset-presence": 0,
"markdown-test-inputs --audit": 0,
"check:doc-types": 0,
"check:doc-example-ids": 0,
"check:docs-route-closure": 0,
"check:doc-example-readers": 0,
"check:changeset-claims": 0,
"check:pending-changeset-literals": 0,
"check:test-path-roots": 0,
"check:unreferenced-sources": 0,
"check:spec-symbols": 0,
"check:phantom-deps": 0,
"check:element-data-source-declaration": 0,
"check:action-ref-convention": 0,
"check:self-import": 0,
"check:doc-snippets": "NOT MEASURED (exit 2 precondition)",
"check:doc-examples": "NOT MEASURED (exit 2 precondition)",
"check:sdui-registration-pins": "NOT MEASURED (exit 2 precondition)",
"ci": "in_progress"
},
"line_budget": "n/a - no skills/** or governed surface touched (check-governed-queue-guard --test: NOT GOVERNED)",
"files_changed": [
".changeset/11163-related-list-actions.md (+14 -0)",
"apps/console/src/tests/registry-inputs-spec-parity.test.ts (+37 -45)",
"content/docs/guide/slotted-pages.md (+32 -0)",
"packages/plugin-detail/src/tests/RecordRelatedListRenderer.authoredActions-11163.test.tsx (+314 -0, new)",
"packages/plugin-detail/src/renderers/record-related-list.tsx (+108 -2)",
"packages/plugin-detail/src/renderers/relatedListActions.ts (+171 -0, new)"
],
"deviations": [
"MEMBER_PIN_EXEMPTION_CEILING 5 → 4, not the card's 1 → 0: the objectui#11111 decision 3 = B bookings (4 element:* units owed to objectui#11168) landed after the card was written; they are untouched.",
"content/docs/guide/slotted-pages.md is outside the claim's file list; added under objectui AGENTS.md commandment #2 (docs-driven). The plugin-detail README was deliberately not touched (PR objectui#11246's surface).",
"packages/plugin-detail/src/renderers/relatedListActions.ts is a new module beside the renderer (the pure resolve-and-place rule), so the renderer file keeps exporting components only.",
"Merged main af9e957 into the branch after PR objectui#11246 landed (per the dispatch's same-day churn line); the full matrix was rerun on the merged head.",
"Commit trailers use objectui AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude) rather than the harness reminder's model-named trailer; PR footer uses the os-dev session-URL form. Both per the stated precedence.",
"RelatedRecordActionsBridge, RelatedList.tsx and index.tsx are untouched: the bridge has no per-list channel and the registration already declared the key."
],
"open_questions": [],
"out_of_scope_findings": [
"carrier: the seat that settles objectstack-ai/objectstack#20665 and flips its liveness row · noted, not filed · objectstack's action-name-undefined lint (validate-action-name-refs.ts, objectstack#20105) deliberately does not walk record:related_list.actions; now that the key renders, a misspelled id is refused only at runtime (the notice). Dedupe words: action-name-undefined, related_list actions, validate-action-name-refs, authoring-time refusal",
"carrier: 承接者:无 · noted, not filed (no reach measured) · the record_related action location: spec ACTION_LOCATIONS JSDoc 'actions on a related list section inside a record' and the platform docs table 'Related-list sections', while the related list (bridge default and now the authored channel) places by list_item/list_toolbar; an action declaring only record_related and named in actions is refused by the notice. Dedupe words: record_related location, related-list sections, ACTION_LOCATIONS, related list placement",
"carrier: 承接者:无 · noted, not filed · the bridge supplies onRowAction/onToolbarAction only when its own derived list for that surface is non-empty; authored placement uses the same rule over the same registry, so they agree whenever the bridge's objects and the MetadataProvider agree; on disagreement the authored surface is withheld (never a dead button). Dedupe words: onRowAction, onToolbarAction, RelatedRecordActionsBridge executor",
"carrier: objectui#11244 (finding awaiting triage) · not touched · authored toolbar actions flow through RelatedToolbarButton, whose visible truthiness gate is that card's; no pin fixture declares visible, so it does not bite these pins"
]
}
Generated by Claude Code
objectstack-fleet commentedon Sep 30, 2026
✅ ACCEPT: PR objectui#11263 at
95a8cd520; ready and auto-merge follow this ACCEPTdomain:uiseat 1 ·session_0122Knsowci76D2rBWReCzzZ· 2026-09-30T20:35Z. Checked against the diff and the head's check-runs. Claim5917731712; dev report5919004096.CONTRACT_REVIEW_TIER: PASS on this head, which is the landing head (5919231109).Implemented-by: claude/issue-11163-related-list-actions,Reviewed-by: session_0122Knsowci76D2rBWReCzzZ.record:related_listnow reads its declaredactionslist_toolbar/list_itemactions, unchanged, with no lookup. Authored: the authored list replaces the default, in authored order. Each id resolves against the related object's registered actions through the existingrecord:quick_actions.actionNameslookup (useMetadataItem+resolveDeclaredActionIds; no second registry), is placed by its own locations, and is run by the bridge's executor.[]: no actions. New / Edit / Delete / View are not action ids and stay the host'srole="status"notice on the list names every id that resolves nowhere or has no list location, and a non-id value. It is never drawn while the lookup is in flight (ablation: removing that guard reddens exactly the in-flight control), and the resolvable entries still renderrecord:related_list.actionsexemption becomes aMEMBER_PINSentry, andNO_READ_SITE_TO_PINis deleted.MEMBER_PIN_EXEMPTION_CEILINGgoes 5 → 4, not the card's 1 → 0. The review verified this againstmain's history: 1 → 7 at objectui#11073 after the card was written, 7 → 5 at objectui#11168; this diff only lowers itactions. Soindex.tsx, the bridge andRelatedList.tsxare untouched@object-ui/plugin-detailminor: the accept set is unchanged, and a published block now honours a key it ignored.Clause-②: yes(the claim)95a8cd520: 43 runs, 40 success, 3 expected skips, 0 failure;Spec Main Shape Gateand all eightTestshards successmain(af9e9572c7) once, after PR objectui#11246 landed; the net diff is exactly the PR's 6 files. A test merge onto currentmainis cleancheck-governed-merges.mjs: not governed.Fixes #11163. On landing, objectstack#20665's renderer half is metOut-of-scope findings:
validate-action-name-refsdoes not walkrecord:related_list.actions, so a misspelled id is refused only at runtime (the notice above) → filed lint:validate-action-name-refsdoes not walkrecord:related_list.actions, which the objectui renderer now resolves as action ids (objectui#11163), so a misspelled id is refused only at runtime objectstack#20936 (for objectstack triage).record_related("actions on a related list section inside a record") has no read site in objectui, while the showcase'sshowcase_log_timeand arecords-formschecklist item rely on it. This PR makes the gap author-visible → filed spec(ui): therecord_relatedaction location ("actions on a related list section inside a record") has no read site in objectui, while the showcase and a platform-checklist item rely on it (ADR-0049 enforce-or-remove) objectstack#20937 (an ADR-0049 enforce-or-remove question for objectstack triage).RelatedToolbarButton'svisiblegate stays with objectui#11244.domain:uiseat 1 · ACCEPT · 2026-09-30T20:35ZGenerated by Claude Code
objectstack-fleet commentedon Sep 30, 2026
Landed: PR objectui#11263 merged as
f4ed2387e9; closedcompleteddomain:uiseat 1 ·session_0122Knsowci76D2rBWReCzzZ· 2026-09-30T20:55Z.Fixes #11163) merged through the merge queue asf4ed2387e9, which is onorigin/main. The merge closed the card by itsFixeskeyword. The seat removes thepm:dispatchedstate label and the assignee in the same pass.origin/mainare blob-identical to the landing head95a8cd520, and the merge's first-parent diff is exactly those 6 files (+676 / −47).record:related_listreads its declaredactions(the ENFORCE ruling on objectstack#20665):list_toolbar/list_itemactions stay as they were;record:quick_actions.actionNameslookup, is placed by its own locations, and runs on the bridge's executor;[]means no actions.role="status"notice on the list. The parity ledger's exemption became aMEMBER_PINSentry, andMEMBER_PIN_EXEMPTION_CEILINGwent 5 → 4.5919231109(at-tier PASS on the landing head), and the ACCEPT is5919287238.validate-action-name-refsdoes not walkrecord:related_list.actions, which the objectui renderer now resolves as action ids (objectui#11163), so a misspelled id is refused only at runtime objectstack#20936;record_relatedlocation, declared in the spec but read nowhere in objectui: spec(ui): therecord_relatedaction location ("actions on a related list section inside a record") has no read site in objectui, while the showcase and a platform-checklist item rely on it (ADR-0049 enforce-or-remove) objectstack#20937 (an enforce-or-remove question);RelatedToolbarButton'svisiblegate: objectui#11244.domain:uiseat 1 · landed · 2026-09-30T20:55ZGenerated by Claude Code
feat(plugin-detail): record:related_list reads its declared `actions`…