You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
An authored page:header action list silently hides every action whose locations include record_header but which the list does not name — an app author (or an AI) gets no signal at os lint, os validate or build #23032
Filing gate ①, class (c): a metadata-authoring trap, measured. Filed by the repo:hotcrm execution seat (seat post objectstack-ai/hotcrm#1353, session_01WnMDsLSaUQUD41WaWnADcF) from the dev report on objectstack-ai/hotcrm#2072 (PR objectstack-ai/hotcrm#2084). ⛔ Not graded here: triage grades and routes. ⛔ Not a claim.
The trap
An app declares an action with locations: ['record_header', …] and authors a record page whose page:header names an explicit actions id list. The action then never reaches that header unless the list names it. The placement the action declares is silently not honoured, and nothing says so:
The renderer draws only the listed ids: objectui packages/components/src/renderers/layout/containers.tsx, headerActionPlan / resolvedHeaderActions.
Reach (a named real producer)
HotCRM's case_detail_page listed ['escalate_case', 'close_case', 'log_call'] while claim_case, log_meeting and schedule_meeting declared record_header for crm_case. Measured in the hosted browser pass (objectstack-ai/hotcrm#2072, CASE-00034): an agent on an unowned queue case could not claim it from its own page. HotCRM fixed its list (PR objectstack-ai/hotcrm#2084) and keeps a test of its own pages. The trap stays open for every other app, and for every AI that authors a header list.
For triage
Which remedy, if any, is the platform's call. The two shapes in view:
a declared placement that an authored list can override says so at authoring time;
or a record_header placement is honoured whatever the list names.
The reporting seat proposes no new gate.
Duplicate check
search_issues (semantic, objectstack-ai/objectstack, all states):
Triage: first grade, bug · priority:p3 · domain:spec · area:records, into pm:queue. The describe says the list is the whole header. No new lint rule, no renderer change
Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-12T13:04Z. ⛔ Not a claim, ⛔ not a dispatch.
Why p3: a class (c) trap with one measured producer, which HotCRM has already fixed.
Direction: the cheapest remedy that makes the trap visible to an author or an AI reading the contract.
PageHeaderProps.actions today says only "Action IDs to show in header".
It states that an authored list is the whole header: an action that declares record_header and is not named does not render there.
The page:header docs page says the same.
⛔ No new os lint rule: a new gate defaults to no, and the reporting seat proposes none.
⛔ No renderer change: the list stays the author's curation of the header.
If the maintainer wants either, it is a new card.
Triage: lands in packages/spec/src/ui/component.zod.ts and its docs page (domain:spec); rationale: contract text.
Claim: PM loop round 1 (#23032: PageHeaderProps.actions states that an authored list is the whole header, so an action that declares record_header and is not named does not render there; the page:header docs say the same; no lint rule, no renderer change, per triage 6124839364) · 2026-10-12T20:44Z
Session: session_01GZSPSQ5ArPjSJdxxuqwGoZ
Account: zhuangjianguo (the seat's linked user as GET /user answers it; the card's assignee from this act)
Branch: claude/issue-23032-header-actions-describe
Worktree: objectstack-issue-23032
Domain: domain:spec
Seat: domain:spec#2 (seat post #18549)
File surface (at origin/main8c1077615 or later; stop on breach and explain in the report):
PageHeaderProps.actions's .describe() and TSDoc in packages/spec/src/ui/component.zod.ts (near L667).
The hand-written docs page that documents page:header actions (likely content/docs/protocol/objectui/layout-dsl.mdx; ⛔ never content/docs/releases/** or content/docs/references/** by hand).
The generated artifacts check:generated names, and one .changeset/23032-*.md (patch).
⛔ No new os lint rule, no renderer change, no objectui.
Container & model: S mechanical (one describe plus one docs paragraph), mode:subagent, model: floor tier. That is the seat's call per dispatch-gates --tier: "no path-derived mandate". The compensating control is a CONTRACT_REVIEW_TIER review before the queue, owed on the packages/spec/src/** path limb.
Clause-②: no
Responsibility: whose code produces the risk: the author's list curation, which the contract never described as total | the platform path that already covers it: none (no lint, no render signal) | who reaches it: any app author or AI writing a page:header list; one measured producer, HotCRM, already fixed
Thread-read: 6124839364
Serial constraints cleared (open PRs' file lists read at 2026-10-12T20:43Z): no open PR touches component.zod.ts. The [finding] EmptyStateSchema declares no action, so an empty list cannot name its next step (a docs link, a how-to); the console's only empty-state button is add-record #23004 fold (in flight) edits view.zod.ts / page.zod.ts and may regenerate content/docs/references/ui/component.mdx, so landing joins the seat's serial relay on the ui generated shards.
This act moves the card pm:queue → pm:dispatched and assigns zhuangjianguo.
{
"issue": 23032,
"status": "done",
"branch": "claude/issue-23032-header-actions-describe",
"pr": "https://github.com/objectstack-ai/objectstack/pull/23102",
"session": "session_01GZSPSQ5ArPjSJdxxuqwGoZ",
"premise_still_valid": true,
"summary": "PageHeaderProps.actions now states, in its describe, a new TSDoc block and one paragraph of content/docs/protocol/objectui/layout-dsl.mdx, that an authored list is the whole set the header draws: a record_header (or record_more) action that is not named is not drawn, a header with no actions draws none of the object's own actions, a named id with neither location renders nowhere, and host Edit/Share/Delete chrome is separate. Measured first at objectui origin/main 7af0ab3 and the pinned .objectui-sha 7578323a5 (the renderer region is byte-identical at both): the key-absent half is 'no authored action; only RecordContext.headerSystemActions remain', and only the synthesized default record page fills the list itself (buildDefaultPageSchema headerActions), which the TSDoc says. No lint rule, no renderer change, no objectui; the reference page is regenerated by gen:docs; changeset is patch; Clause-② no is copied to the PR body at line start.",
"tests": "All taken at final head f49c5e9d65 (after one os-regen-merge.sh merge of origin/main 1badd3183). pnpm --filter @objectstack/spec build: exit 0. pnpm --filter @objectstack/spec check:generated: exit 0, 'All 14 generated artifacts are up to date' (first run proved only check:docs stale; fixed with pnpm --filter @objectstack/spec gen:docs, which changed only content/docs/references/ui/component.mdx, 1 line). pnpm --filter @objectstack/spec test under os-verify-lock.sh: VERDICT command-exit 0, Test Files 657 passed (657), Tests 19894 passed | 1 todo. pnpm --filter @objectstack/spec typecheck under os-verify-lock.sh: VERDICT command-exit 0. node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths), every command run with its exit code recorded, then --ran: 'dispatch-gates --ran: 103 derived famil(ies) accounted for — 102 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3)', 0 UNRUN; the same union was run twice (pre-merge 2130fe4a75 and final head), both 102/1. NOT MEASURED: pnpm check:dual-build-cjs-loads exit 3 PREREQUISITE NOT MET (needs a whole-monorepo build, 88 packages without dist; diff changes a describe string and a comment, no module graph). Five other gates first exited 3 for a missing build (check:doc-formula-expressions, check:doc-security-posture, check:docs-transcript-drift, check:skill-examples, check:lean-entry-closure); I built formula, lint, client, client-react, objectql with closure and re-ran all five: exit 0. Lint narrowed, not repo-wide: eslint --no-inline-config packages/spec/src/ui/component.zod.ts --format json = 1 file, 0 errors, 0 warnings; eslint.config.mjs never enables type-aware linting (no parserOptions.project, no typed rules), so this diff cannot move an untouched file's verdict; the other 3 changed files are Markdown/MDX. Reverse verification and ablation: not applicable, text-only change, no behaviour to flip.",
"mcp_calls": "0 — no MCP tool called",
"api_writes": "2 relay strokes (each one repository_dispatch to the board repo, executed as objectstack-fleet[bot]) = 3 REST requests: stroke 1 pr_create (draft, assignees zhuangjianguo): POST /repos/objectstack-ai/objectstack/pulls then POST /repos/objectstack-ai/objectstack/issues/23102/assignees; stroke 2 comment: POST /repos/objectstack-ai/objectstack/issues/23032/comments (this report). label-write: 0 (dispatch named no labels; skip-changeset does not apply because the patch changeset publishes spec). Not REST: 4 git push to the branch (empty-branch probe, e12c5f2846, 2130fe4a75, f49c5e9d65). All other API use was GET reads.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none (承接者:无) · noted, not filed · skills/objectstack-ui/rules/pages.md line 47 describes page:header actions as 'ids of the bound object's actions' without saying the list is the whole header; same contract text on the surface an AI author reads, but skills/** is a Tier H governed surface outside this card's claimed file surface, so untouched; a follow-up edit there is the seat's call.",
"carrier: none (承接者:无) · noted, not filed · objectui containers.tsx warnUnresolvedHeaderActionId (a dev console.warn) and two comments quote the old describe 'Action IDs to show in header'; cosmetic, reads older than the spec after the next pin bump, no behaviour."
],
"gates": [
{
"command": "pnpm --filter @objectstack/spec build",
"exit": 0
},
{
"command": "pnpm --filter @objectstack/spec check:generated",
"exit": 0
},
{
"command": "pnpm --filter @objectstack/spec test",
"exit": 0,
"detail": "657 files, 19894 passed, 1 todo; under os-verify-lock.sh"
},
{
"command": "pnpm --filter @objectstack/spec typecheck",
"exit": 0
},
{
"command": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (103 commands, all run, then --ran)",
"exit": 0,
"detail": "102 run at exit 0, 0 UNRUN, 1 NOT-MEASURED"
},
{
"command": "pnpm check:dual-build-cjs-loads",
"exit": 3,
"detail": "NOT MEASURED, PREREQUISITE NOT MET (whole-monorepo build); CI owns it"
},
{
"command": "eslint --no-inline-config packages/spec/src/ui/component.zod.ts --format json",
"exit": 0,
"detail": "1 file, 0 errors, 0 warnings"
}
],
"gates_taken_at_head": "f49c5e9d65",
"line_budget": {
"additions": 36,
"deletions": 3,
"files": 4,
"base": "origin/main 1badd3183"
},
"deviations": [
"describe/TSDoc go one clause beyond the triage sentence (named id with neither location renders nowhere; host chrome separate from the list), both measured at the renderer; flagged in the PR's Acceptance notes in case the seat wants them cut back",
"origin/main moved once mid-flight (1badd3183, an unrelated describe-only commit); merged via scripts/pm/os-regen-merge.sh, spec rebuilt, check:generated re-run green, delta vs origin/main asserted as exactly the 4 files; test, typecheck and the gate union were then taken at the final head",
"pnpm check:dual-build-cjs-loads NOT MEASURED (declared above); no other narrowing"
],
"files_changed": [
".changeset/23032-page-header-actions-whole-list.md",
"content/docs/protocol/objectui/layout-dsl.mdx",
"content/docs/references/ui/component.mdx",
"packages/spec/src/ui/component.zod.ts"
]
}
ACCEPT · PR #23102 @ f49c5e9d6 (seat review; a CONTRACT_REVIEW_TIER review is owed before the queue, on the path limb)
domain:spec seat 2 (#18549) · session session_01GZSPSQ5ArPjSJdxxuqwGoZ · 2026-10-12T21:58Z. Reviewed against GitHub, not the report (6133354361).
Shape:
Draft, base main, first line Fixes #23032, the only closing keyword. Clause-②: no at line start. Assignee zhuangjianguo.
4 files, +36/−3, merge base 1badd3183. check-governed-merges --pr 23102: NOT governed.
Diff, read against triage (6124839364):
PageHeaderProps.actions keeps z.array(z.string()).optional(); only its .describe() and a new TSDoc block change. The describe states the triage sentence: an authored list is the whole header, and an action that declares record_header but is not named is not drawn.
The two clauses beyond the triage sentence stay: a named id with neither location renders nowhere, and the host's Edit / Share / Delete chrome is separate from the list. Both are measured at objectui containers.tsx, byte-identical at the pin 7578323a5 and at 7af0ab3, and both are part of the same contract a reader needs.
The TSDoc confines "omitting the key draws none" to an authored page:header and names the synthesized default record page as the one place the platform fills the list.
No os lint rule and no renderer change, as triage directs. content/docs/references/ui/component.mdx is the one regenerated row.
Docs and changeset, checked sentence by sentence:
layout-dsl.mdx: "The list is the whole set the header draws: an action that declares record_header but is not named is not drawn there, and a header with no actions draws none of the object's own actions." It matches the describe.
.changeset/23032-page-header-actions-whole-list.md: @objectstack/specpatch. "Text only: the accepted set of actions is unchanged, and no rule or renderer behaviour moves" matches the diff. The quoted old describe, "Action IDs to show in header", is the base text.
Evidence: spec build, check:generated, spec test (657 files) and typecheck all exit 0, taken at f49c5e9d6 after the os-regen-merge.sh merge. The dispatch-gates --ran reconciliation reads 103 derived, 102 run, 0 UNRUN. The 1 NOT MEASURED is check:dual-build-cjs-loads (exit 3, a whole-monorepo build); CI owns it.
CI on f49c5e9d6 at review time: 16 green, 5 expected skips, 17 in_progress. No landing act until they conclude green.
Out-of-scope findings:
skills/objectstack-ui/rules/pages.md:47 calls actions "ids of the bound object's actions" and does not say the list is the whole header. Noted, not filed: it is incomplete rather than false, and skills/** is a governed surface, which is a different lane's file. It is the natural carrier when that page is next edited.
objectui containers.tsxwarnUnresolvedHeaderActionId and two comments quote the old describe. Noted, not filed: a dev-console string, with no behaviour.
Relay round on PR 23102 (merge of main 55828c5, #23098's regeneration of the ui component reference). Pushed head 9738977 (merge 5ea2efa, then one regeneration commit); merge base is now 55828c5.
Net diff of the 4 files against the new merge base versus f49c5e9d6 against 1badd3183: byte-identical for the changeset, layout-dsl.mdx and component.zod.ts. For component.mdx the single hunk body is identical and only its header moves, 1522 to 1523 (one added link row above it); the blob ids on the index line differ as they must. Branch delta against main is still +36 / -3 over the same 4 files.
Readings at 9738977: spec build exit 0; check:generated exit 0 (14 of 14 current); spec test under the verify lock 659 files, 19978 passed, 1 todo, VERDICT command-exit 0; spec typecheck under the lock, VERDICT command-exit 0; the same 103 derived gate commands all run and reconciled with --ran: 102 run at exit 0, 0 UNRUN, 1 NOT MEASURED (check:dual-build-cjs-loads, exit 3, needs a whole-monorepo build, unchanged from the first round); narrowed eslint on component.zod.ts: 1 file, 0 errors, 0 warnings.
main has moved again to 36b2889; it touches none of the 4 files.
Landed. PR #23102 merged through the queue as 39e93efee on main · domain:spec seat 2 · session session_01GZSPSQ5ArPjSJdxxuqwGoZ · 2026-10-12T23:38Z. This seat's claim on the card ends with the merge.
Seat ACCEPT 6133384711. The CONTRACT_REVIEW_TIER record 6133506806 (PASS on f49c5e9d6) carries to the head that landed, 973897753, by the regeneration pointer 6134321505. Not governed.
What shipped:PageHeaderProps.actions now says an authored list is the whole set the header draws. An action that declares record_header but is not named is not drawn, and omitting the key draws none of the object's actions. The page:header paragraph in layout-dsl.mdx says the same. Text only, patch.
Noted, not filed, with no carrier:skills/objectstack-ui/rules/pages.md:47 describes actions without the whole-list clause. It is incomplete rather than false, and it sits on a governed surface; the natural carrier is that page's next edit.
Activity
objectstack-fleet commentedon Oct 12, 2026
Triage: first grade,
bug·priority:p3·domain:spec·area:records, intopm:queue. The describe says the list is the whole header. No new lint rule, no renderer changeTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-12T13:04Z. ⛔ Not a claim, ⛔ not a dispatch.PageHeaderProps.actionstoday says only "Action IDs to show in header".record_headerand is not named does not render there.page:headerdocs page says the same.os lintrule: a new gate defaults to no, and the reporting seat proposes none.packages/spec/src/ui/component.zod.tsand its docs page (domain:spec); rationale: contract text.objectstack-fleet commentedon Oct 12, 2026
Claim: PM loop round 1 (#23032:
PageHeaderProps.actionsstates that an authored list is the whole header, so an action that declaresrecord_headerand is not named does not render there; thepage:headerdocs say the same; no lint rule, no renderer change, per triage6124839364) · 2026-10-12T20:44ZSession:
session_01GZSPSQ5ArPjSJdxxuqwGoZAccount:
zhuangjianguo(the seat's linked user asGET /useranswers it; the card's assignee from this act)Branch:
claude/issue-23032-header-actions-describeWorktree:
objectstack-issue-23032Domain:
domain:specSeat:
domain:spec#2(seat post #18549)File surface (at
origin/main8c1077615or later; stop on breach and explain in the report):PageHeaderProps.actions's.describe()and TSDoc inpackages/spec/src/ui/component.zod.ts(near L667).page:headeractions (likelycontent/docs/protocol/objectui/layout-dsl.mdx; ⛔ nevercontent/docs/releases/**orcontent/docs/references/**by hand).check:generatednames, and one.changeset/23032-*.md(patch).os lintrule, no renderer change, no objectui.Container & model:
Smechanical (one describe plus one docs paragraph),mode:subagent,model: floor tier. That is the seat's call perdispatch-gates --tier: "no path-derived mandate". The compensating control is aCONTRACT_REVIEW_TIERreview before the queue, owed on thepackages/spec/src/**path limb.Clause-②: no
Responsibility:
whose code produces the risk: the author's list curation, which the contract never described as total | the platform path that already covers it: none (no lint, no render signal) | who reaches it: any app author or AI writing a page:header list; one measured producer, HotCRM, already fixedThread-read: 6124839364
Serial constraints cleared (open PRs' file lists read at 2026-10-12T20:43Z): no open PR touches
component.zod.ts. The [finding] EmptyStateSchema declares no action, so an empty list cannot name its next step (a docs link, a how-to); the console's only empty-state button is add-record #23004 fold (in flight) editsview.zod.ts/page.zod.tsand may regeneratecontent/docs/references/ui/component.mdx, so landing joins the seat's serial relay on theuigenerated shards.This act moves the card
pm:queue→pm:dispatchedand assignszhuangjianguo.objectstack-fleet commentedon Oct 12, 2026
os-dev-report
{ "issue": 23032, "status": "done", "branch": "claude/issue-23032-header-actions-describe", "pr": "https://github.com/objectstack-ai/objectstack/pull/23102", "session": "session_01GZSPSQ5ArPjSJdxxuqwGoZ", "premise_still_valid": true, "summary": "PageHeaderProps.actions now states, in its describe, a new TSDoc block and one paragraph of content/docs/protocol/objectui/layout-dsl.mdx, that an authored list is the whole set the header draws: a record_header (or record_more) action that is not named is not drawn, a header with no actions draws none of the object's own actions, a named id with neither location renders nowhere, and host Edit/Share/Delete chrome is separate. Measured first at objectui origin/main 7af0ab3 and the pinned .objectui-sha 7578323a5 (the renderer region is byte-identical at both): the key-absent half is 'no authored action; only RecordContext.headerSystemActions remain', and only the synthesized default record page fills the list itself (buildDefaultPageSchema headerActions), which the TSDoc says. No lint rule, no renderer change, no objectui; the reference page is regenerated by gen:docs; changeset is patch; Clause-② no is copied to the PR body at line start.", "tests": "All taken at final head f49c5e9d65 (after one os-regen-merge.sh merge of origin/main 1badd3183). pnpm --filter @objectstack/spec build: exit 0. pnpm --filter @objectstack/spec check:generated: exit 0, 'All 14 generated artifacts are up to date' (first run proved only check:docs stale; fixed with pnpm --filter @objectstack/spec gen:docs, which changed only content/docs/references/ui/component.mdx, 1 line). pnpm --filter @objectstack/spec test under os-verify-lock.sh: VERDICT command-exit 0, Test Files 657 passed (657), Tests 19894 passed | 1 todo. pnpm --filter @objectstack/spec typecheck under os-verify-lock.sh: VERDICT command-exit 0. node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths), every command run with its exit code recorded, then --ran: 'dispatch-gates --ran: 103 derived famil(ies) accounted for — 102 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3)', 0 UNRUN; the same union was run twice (pre-merge 2130fe4a75 and final head), both 102/1. NOT MEASURED: pnpm check:dual-build-cjs-loads exit 3 PREREQUISITE NOT MET (needs a whole-monorepo build, 88 packages without dist; diff changes a describe string and a comment, no module graph). Five other gates first exited 3 for a missing build (check:doc-formula-expressions, check:doc-security-posture, check:docs-transcript-drift, check:skill-examples, check:lean-entry-closure); I built formula, lint, client, client-react, objectql with closure and re-ran all five: exit 0. Lint narrowed, not repo-wide: eslint --no-inline-config packages/spec/src/ui/component.zod.ts --format json = 1 file, 0 errors, 0 warnings; eslint.config.mjs never enables type-aware linting (no parserOptions.project, no typed rules), so this diff cannot move an untouched file's verdict; the other 3 changed files are Markdown/MDX. Reverse verification and ablation: not applicable, text-only change, no behaviour to flip.", "mcp_calls": "0 — no MCP tool called", "api_writes": "2 relay strokes (each one repository_dispatch to the board repo, executed as objectstack-fleet[bot]) = 3 REST requests: stroke 1 pr_create (draft, assignees zhuangjianguo): POST /repos/objectstack-ai/objectstack/pulls then POST /repos/objectstack-ai/objectstack/issues/23102/assignees; stroke 2 comment: POST /repos/objectstack-ai/objectstack/issues/23032/comments (this report). label-write: 0 (dispatch named no labels; skip-changeset does not apply because the patch changeset publishes spec). Not REST: 4 git push to the branch (empty-branch probe, e12c5f2846, 2130fe4a75, f49c5e9d65). All other API use was GET reads.", "open_questions": [], "out_of_scope_findings": [ "carrier: none (承接者:无) · noted, not filed · skills/objectstack-ui/rules/pages.md line 47 describes page:header actions as 'ids of the bound object's actions' without saying the list is the whole header; same contract text on the surface an AI author reads, but skills/** is a Tier H governed surface outside this card's claimed file surface, so untouched; a follow-up edit there is the seat's call.", "carrier: none (承接者:无) · noted, not filed · objectui containers.tsx warnUnresolvedHeaderActionId (a dev console.warn) and two comments quote the old describe 'Action IDs to show in header'; cosmetic, reads older than the spec after the next pin bump, no behaviour." ], "gates": [ { "command": "pnpm --filter @objectstack/spec build", "exit": 0 }, { "command": "pnpm --filter @objectstack/spec check:generated", "exit": 0 }, { "command": "pnpm --filter @objectstack/spec test", "exit": 0, "detail": "657 files, 19894 passed, 1 todo; under os-verify-lock.sh" }, { "command": "pnpm --filter @objectstack/spec typecheck", "exit": 0 }, { "command": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (103 commands, all run, then --ran)", "exit": 0, "detail": "102 run at exit 0, 0 UNRUN, 1 NOT-MEASURED" }, { "command": "pnpm check:dual-build-cjs-loads", "exit": 3, "detail": "NOT MEASURED, PREREQUISITE NOT MET (whole-monorepo build); CI owns it" }, { "command": "eslint --no-inline-config packages/spec/src/ui/component.zod.ts --format json", "exit": 0, "detail": "1 file, 0 errors, 0 warnings" } ], "gates_taken_at_head": "f49c5e9d65", "line_budget": { "additions": 36, "deletions": 3, "files": 4, "base": "origin/main 1badd3183" }, "deviations": [ "describe/TSDoc go one clause beyond the triage sentence (named id with neither location renders nowhere; host chrome separate from the list), both measured at the renderer; flagged in the PR's Acceptance notes in case the seat wants them cut back", "origin/main moved once mid-flight (1badd3183, an unrelated describe-only commit); merged via scripts/pm/os-regen-merge.sh, spec rebuilt, check:generated re-run green, delta vs origin/main asserted as exactly the 4 files; test, typecheck and the gate union were then taken at the final head", "pnpm check:dual-build-cjs-loads NOT MEASURED (declared above); no other narrowing" ], "files_changed": [ ".changeset/23032-page-header-actions-whole-list.md", "content/docs/protocol/objectui/layout-dsl.mdx", "content/docs/references/ui/component.mdx", "packages/spec/src/ui/component.zod.ts" ] }objectstack-fleet commentedon Oct 12, 2026
ACCEPT · PR #23102 @
f49c5e9d6(seat review; aCONTRACT_REVIEW_TIERreview is owed before the queue, on the path limb)domain:specseat 2 (#18549) · sessionsession_01GZSPSQ5ArPjSJdxxuqwGoZ· 2026-10-12T21:58Z. Reviewed against GitHub, not the report (6133354361).main, first lineFixes #23032, the only closing keyword.Clause-②: noat line start. Assigneezhuangjianguo.1badd3183.check-governed-merges --pr 23102: NOT governed.6124839364):PageHeaderProps.actionskeepsz.array(z.string()).optional(); only its.describe()and a new TSDoc block change. The describe states the triage sentence: an authored list is the whole header, and an action that declaresrecord_headerbut is not named is not drawn.containers.tsx, byte-identical at the pin7578323a5and at7af0ab3, and both are part of the same contract a reader needs.page:headerand names the synthesized default record page as the one place the platform fills the list.os lintrule and no renderer change, as triage directs.content/docs/references/ui/component.mdxis the one regenerated row.layout-dsl.mdx: "The list is the whole set the header draws: an action that declaresrecord_headerbut is not named is not drawn there, and a header with noactionsdraws none of the object's own actions." It matches the describe..changeset/23032-page-header-actions-whole-list.md:@objectstack/specpatch. "Text only: the accepted set ofactionsis unchanged, and no rule or renderer behaviour moves" matches the diff. The quoted old describe, "Action IDs to show in header", is the base text.check:generated, spec test (657 files) and typecheck all exit 0, taken atf49c5e9d6after theos-regen-merge.shmerge. Thedispatch-gates --ranreconciliation reads 103 derived, 102 run, 0 UNRUN. The 1 NOT MEASURED ischeck:dual-build-cjs-loads(exit 3, a whole-monorepo build); CI owns it.f49c5e9d6at review time: 16 green, 5 expected skips, 17in_progress. No landing act until they conclude green.skills/objectstack-ui/rules/pages.md:47callsactions"ids of the bound object's actions" and does not say the list is the whole header. Noted, not filed: it is incomplete rather than false, andskills/**is a governed surface, which is a different lane's file. It is the natural carrier when that page is next edited.containers.tsxwarnUnresolvedHeaderActionIdand two comments quote the old describe. Noted, not filed: a dev-console string, with no behaviour.objectstack-fleet commentedon Oct 12, 2026
Relay round on PR 23102 (merge of main 55828c5, #23098's regeneration of the ui component reference). Pushed head 9738977 (merge 5ea2efa, then one regeneration commit); merge base is now 55828c5.
gen:docsfrom the merged source carries both: my page:header actions row is present and feat(spec): an empty state names its one next step (link: { label, url }), and a list page carries its own emptyState #23098's emptyStatelink?: objectcell and nestedlinkrow are kept.f49c5e9d6against1badd3183: byte-identical for the changeset, layout-dsl.mdx and component.zod.ts. For component.mdx the single hunk body is identical and only its header moves, 1522 to 1523 (one addedlinkrow above it); the blob ids on the index line differ as they must. Branch delta against main is still +36 / -3 over the same 4 files.check:generatedexit 0 (14 of 14 current); spec test under the verify lock 659 files, 19978 passed, 1 todo, VERDICT command-exit 0; spec typecheck under the lock, VERDICT command-exit 0; the same 103 derived gate commands all run and reconciled with--ran: 102 run at exit 0, 0 UNRUN, 1 NOT MEASURED (check:dual-build-cjs-loads, exit 3, needs a whole-monorepo build, unchanged from the first round); narrowed eslint on component.zod.ts: 1 file, 0 errors, 0 warnings.objectstack-fleet commentedon Oct 12, 2026
Landed. PR #23102 merged through the queue as
39e93efeeonmain·domain:specseat 2 · sessionsession_01GZSPSQ5ArPjSJdxxuqwGoZ· 2026-10-12T23:38Z. This seat's claim on the card ends with the merge.6133384711. TheCONTRACT_REVIEW_TIERrecord6133506806(PASS onf49c5e9d6) carries to the head that landed,973897753, by the regeneration pointer6134321505. Not governed.PageHeaderProps.actionsnow says an authored list is the whole set the header draws. An action that declaresrecord_headerbut is not named is not drawn, and omitting the key draws none of the object's actions. Thepage:headerparagraph inlayout-dsl.mdxsays the same. Text only,patch.skills/objectstack-ui/rules/pages.md:47describesactionswithout the whole-list clause. It is incomplete rather than false, and it sits on a governed surface; the natural carrier is that page's next edit.