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
Setup › Packaged automation: a packaged action switched off keeps its button on the record page, and clicking it shows a toast naming sys_metadata_activation and ADR-0126 #27504
Found in the 18.3.0 release-candidate browser walkthrough (wave anchor #27377, card W3-UX), at framework main @ c4c515ad, Console built in-repo from the same commit.
Repro (fresh boot)
Boot examples/app-showcase with --seed-admin and sign in as admin@objectos.ai. Viewport 1440×900.
Open Setup → Packaged Automation → Packaged actions and switch Mark Done (showcase_mark_done, object showcase_task) off. No confirmation or toast appears; the switch flips.
Open Showcase → Tasks and open any task that is not done.
Mark Done is still shown, enabled, both in the record header and in the action bar. Click it.
Expected
A switched-off packaged action is not offered: the button is hidden, or shown disabled with a plain reason such as "This action is turned off for this deployment".
Actual
The button stays live. Clicking it shows a red error toast:
Action 'showcase_mark_done' is disabled — it is switched off for this installation in the packaged-metadata activation ledger (sys_metadata_activation, ADR-0126 §8). Re-enable the packaged action to arm it again, or author your own action instead.
The refusal is correct, since nothing runs. But the user is offered an action that cannot run, and the message speaks to an engineer: a machine name, a system table and an ADR section.
Read fresh. A switched-off packaged action keeps a live button, and clicking it shows a toast naming sys_metadata_activation and ADR-0126. The refusal itself is correct, so this is UX and toast copy: p3. Hiding the button needs the server to serve activation state.
Serve activation state with the action metadata and hide or disable the button from it, with a plain reason. No client copy of the ledger.
Cross-domain: one PR carries both halves, the lane named here claims it, and the claim declares the other lane's files (SKILL.md 跨域例外路径). Run the in-flight intersection check before the push.
Claim: PM loop round 1
Session: session_01Utp6CbDAucNyQ4UtzCJKyh
Account: os-bill
Branch: claude/project-thread-1zrim8 (the card thread's designated push branch, the recorded platform exception to claude/issue-<n>-<slug>)
Worktree: objectstack-issue-27504
Domain: domain:ui
Seat: domain:ui#4
File surface: ui half only, per ruling 6512814276 (B): ui/packages/data-objectstack (read the served key), ui/packages/app-shellMetadataProvider list read, the console action gate(s) that hide a button (ui/packages/componentsPageHeaderActions / action bars, action engine), tests beside, root .changeset/; ⛔ any packages/** file (the spec/server half is #27842); ⛔ useConsoleActionRuntime.tsx / RecordDetailView.tsxapiHandler (in-flight PR #27793) (stop on breach; explain in the report)
Container & model: S, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier on 2a0b37bb: no path-derived mandate), effort: high
Clause-②: yes (widening)
Metadata-protocol: none
Blocked-by: #27842
Consumer-of: #27842 (spec + server half, ruling 6512814276; this card reads its envelope key; its own widening is four new @object-ui/core exports — ACTION_SWITCHED_OFF_KEY, markSwitchedOffActions, markSwitchedOffActionsByObject, isActionSwitchedOff — owed a TIER_DEFAULT declaration review by the seat)
Responsibility: a switched-off packaged action is not offered as a live button: the console hides it from the activation state #27842 serves beside the object metadata, with no client copy of the ledger; pins with an ablation. The plain refusal sentence and the served key belong to #27842
Thread-read: 6495255628
Premise: holds
Serial constraints cleared: in-flight intersection: PR #27793 (#27611, seat 4) touches the api handlers — excluded above; run the intersection check again before the push
Amended 2026-10-30T01:44Z to the ui half under ruling 6512814276 (B); amended 2026-10-30T01:47Z to Clause-②: yes (widening) for the core exports (core has one . entry, and six packages outside core read the stamp). Dispatched 2026-10-29T23:49Z to a card thread of the seat's project; the order lives in the project. ⛔ The thread posts no claim and writes no assignee.
Ruling: the activation-state envelope key this card needs is a packages/spec widening, and it goes to the spec lane as its own card; this card stays domain:ui as the console half and waits on it · letter B · maintainer 「同意」 (on the brief recommending B, decision thread 「决定打包动作开关的 spec 改动归谁做」) 2026-10-30T01:38Z
Marker: maintainer-ruled (not auto-adjudicated); the maintainer's word was given 2026-10-30T01:35Z. Brief of record: /mnt/project-files/decisions/27504-打包动作开关spec归属-呈批.md (project files).
The card thread's measurement holds: the triage route (6495255628, "serve activation state with the action metadata, no client copy of the ledger") cannot be done with zero spec change. Removing a switched-off action from the served actions[] takes away the Setup page's own re-enable row (ui/packages/app-shell/src/views/setup/packagedActions.ts lists from GET /meta/object + GET /meta/action); rewriting visible/disabled inside the item rides the GET → edit → PUT round trip back into the stored body, and the read-decoration strip list (METADATA_READ_DECORATIONS, packages/spec/src/kernel/metadata-read-decorations.ts) is itself spec.
A zero-spec route EXISTS and is declined on the first axis: the ledger object sys_metadata_activation declares apiMethods: ['get','list'] ("Reads stay open so operability surfaces can answer 'what is disabled here?'", packages/platform-objects/src/system/sys-metadata-activation.object.ts:192-197), and the Setup page already joins it client-side. Putting that join into the record page would leave the metadata read saying an action is live while a second read says it is off, and every consumer (console, MCP agents, SDK) would have to learn the join. The platform shape is the truth beside the item, once.
A new domain:spec card carries the serve half: the envelope key on the item read (both doors) and the list, the contract member the metadata protocol needs to read the engine's action-activation projection (the getFlowRegistration? pattern on IAutomationService, measured by the spec seat), the metadata-protocol and rest serving (cached door, out of the ETag), the plain-language rewrite of describeDisabled() in packages/objectql/src/action-activation.ts (no tracker number, no table name — AGENTS.md's runtime-string rule), pins and an ablation, the consumer-package test list, the six regenerated spec artifacts, changeset. Shape constraints inherited from automation: a stored flow the engine refuses at cold boot is withdrawn with a warn, while the metadata read keeps serving it as status: 'active' — after the v18 upgrade, every refused flow reads as running #23316: beside item, never inside; published by the cached default door too; never part of the ETag; absent means "no activation ledger answered", never "nothing is switched off", so a consumer that sees no key keeps today's behaviour (button shown, loud refusal on click). The exact member name and whether an empty array is served or omitted are the spec seat's measurement and its contract review.
Claim amendment for 6511284723 (the seat writes it): file surface = ui only (the server paths and the useConsoleActionRuntime.tsx / RecordDetailView.tsx exclusion stay as written); Clause-②: no → no (ui half; consumer of the spec card's widening); Metadata-protocol: none → consumer of <spec card>; Blocked-by: <spec card>; labels pm:blocked until the spec PR merges.
The plain refusal sentence lands with the spec card, so the click path reads plainly before the console half lands.
Failure direction. An absent key keeps the button and the loud 409 refusal — today's behaviour, never a silent hide. The client-side join would have added a second place to drift and a per-role difference when a member cannot list the ledger.
No sprawl. One new key is a permanent obligation under either lane; here it sits with the seat that owns the obligation and its contract review, with one review record.
① 项目长远合理性:激活状态随动作元数据下发一次,所有消费方同一真相;spec 归 spec 席,不开 ui 席写已发布 schema 的新特例。
② 实际业务拉动:p3,18.3.0 RC 走查实测;任何关过打包动作的部署都撞;拆分代价按 #23358 先例以小时计。
③ 防 AI 犯错:键缺席 = 照旧显示 + 响亮 409 拒绝,不静默;不做客户端 join,少一处会漂的地方。
④ 创业阶段不扩散:一个新键、一份契约复核记录,放在负责它的席位名下。
Prior rulings read: git grep -n -iE 'disabledActions|registration.*envelope|sys_metadata_activation' origin/main -- AGENTS.md docs/adr packages/spec/src → ADR-0126 §4/§8 (ledger, switch for actions), #23316 docblocks in protocol.zod.ts; ADR: none on the envelope key; thread: 「决定打包动作开关的 spec 改动归谁做」.
Execution after the ruling
This thread files the spec card next (title: "meta: GET /meta/object serves which packaged actions are switched off beside the item, and the disabled-action refusal reads as a plain sentence"), labelled domain:spec by this ruling; triage grades it (the filing gate's protocol-class rule reads p1 + target; the parent is p3 — the maintainer did not fix a level, so triage does). Unblocks: #27504, Ruling-ref: this comment.
Seat 4: claim amendment as in item 3; the card thread keeps its reproduction and waits for the spec PR's branch.
Ledger row appended to the project's coordinator/rulings.md; the maintainer's letter is recorded on the brief.
The served key and the plain refusal sentence moved to the spec card #27842. This card is now the ui half only: claim 6511284723 was amended in place to the ui file surface. Its card thread keeps its repro and its ui commit (unpushed, no packages/** file). It builds on #27842's PR branch once that exists, merges main after #27842 lands, then opens and readies its own PR. The assignee stays: the work is held, not released.
Read at 2026-10-30T13:32Z. Head c700e99, which is the branch with origin/main merged in.
{
"issue": 27504,
"status": "done",
"branch": "claude/project-thread-1zrim8",
"pr": "https://github.com/objectstack-ai/objectstack/pull/28115",
"session": "session_01Utp6CZny6X72Dx4kxxzLm7",
"premise_still_valid": true,
"summary": "This is the ui half only (ruling B, 6512814276). The server half shipped on main as #27842 / #27964. The data layer stamps each served `disabledActions` entry with a symbol key. Two paths stamp it: the adapter's by-name read, and MetadataProvider's whole-list and package-scoped list reads. The by-name copy re-stamps after structuredClone. Every action gate that hides an action whose requiredPermissions the caller lacks now also hides a switched-off action: page:header, action:bar, data-table, row menu, bulk bar, grid actions column, related list, DeclaredActionsBar, managedBy empty state, and ActionEngine location and bulk. Turning the action back on in Setup brings the button back.",
"tests": "Type-check passes for core, components, data-objectstack, plugin-detail, plugin-grid and app-shell on the merged head. On the same head, 128 affected test files with 1056 tests all pass. The 4 new test files cover the core helpers, page:header, the adapter envelope, and MetadataProvider (list envelope, absent key, by-name copy keeps the stamp). There were 6 ablations (5 gate or stamp sites, plus cloneServedObject). Each went red when ablated and was restored to HEAD; the log is in the seat card folder, ablations.log.",
"gates": "dispatch-gates --commands derived 35 commands. All 35 ran with exit 0 and `--ran` reconciled with exit 0; check-sdui-manifest is included. One gate, `pnpm --dir ui exec vitest run scripts/`, went red once (13 failed) while it ran alongside the other gates. Re-run alone under os-verify-lock, it passed: 169 files, 4901 tests. That re-run is the line recorded. PR CI on c700e9995d: 44 success, 11 skipped, 0 failed, including Type Check, Type Check UI, Lint, Test Core, the Test UI shards, Live E2E UI and Check Changeset.",
"line_budget": "19 files, +489 / -20. Source: +167 / -20. Tests: +303. Changeset: +19.",
"files_changed": "@object-ui/core: utils/action-activation.ts (new), index.ts, actions/ActionEngine.ts, utils/__tests__/action-activation.test.ts. @object-ui/components: renderers/layout/containers.tsx, renderers/action/action-bar.tsx, renderers/complex/data-table.tsx, __tests__/page-header-switched-off-27504.test.tsx. @object-ui/plugin-grid: components/RowActionMenu.tsx, components/BulkActionBar.tsx, objectGridActionsColumn.tsx. @object-ui/plugin-detail: RelatedList.tsx. @object-ui/data-objectstack: index.ts, getObjectSchema.disabledActions-27504.test.ts. @object-ui/app-shell: providers/MetadataProvider.tsx, views/DeclaredActionsBar.tsx, utils/managedByEmptyState.ts, providers/__tests__/MetadataProvider.disabledActions-27504.test.tsx. Root: .changeset/27504-switched-off-action-not-offered.md (all 6 packages patch). No packages/** file.",
"deviations": [
"Clause-②: yes (widening). There are 4 new @object-ui/core exports: ACTION_SWITCHED_OFF_KEY, markSwitchedOffActions, markSwitchedOffActionsByObject and isActionSwitchedOff. The seat amended the Claim at 01:45Z. All 6 consumer packages are covered, as listed above.",
"The local objectql plain-sentence commit was dropped under ruling B, and the sentence is not changed here. The patch was kept for the spec seat. #27842 shipped the sentence.",
"The scripts/ gate line is the single re-run under the lock, not the run alongside the other gates. Both results are given above.",
"The harness's after-PR assign/review step was skipped, as the dispatch requires.",
"Preview review (ruling 6520722066) on PR comment 6524021941: PASS. Screenshots stay in project files because GitHub cannot host them from the review machine."
],
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
"mcp_calls": "0 — no GitHub MCP tool was called",
"api_writes": "3 through the fleet-write relay. 1: pr_create (PR #28115). 2: issue comment on #28115, the preview review 6524021941. 3: issue comment on #27504, this report. Pushes use git push and are not counted.",
"open_questions": [],
"out_of_scope_findings": ["The preview showed these on the record page, the same before and after this change: Archive is disabled with no reason; the layout is one column with no right rail; the 40px top row and the tab row are missing; Edit sits in the header; the action bar appears twice · carrier: PR #28115 comment 6524021941 · noted, not filed (other #26676 record-page cards)"]
}
Activity
objectstack-fleet commentedon Oct 29, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: 审批与自动化 | none | P②
Triage: p3 ·
domain:ui·area:automation· 2026-10-29T11:20Z⛔ Not a claim.
bug,pm:queue.Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh
Claim: PM loop round 1
Session:
session_01Utp6CbDAucNyQ4UtzCJKyhAccount:
os-billBranch:
claude/project-thread-1zrim8(the card thread's designated push branch, the recorded platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-27504Domain:
domain:uiSeat:
domain:ui#4File surface: ui half only, per ruling 6512814276 (B):
ui/packages/data-objectstack(read the served key),ui/packages/app-shellMetadataProviderlist read, the console action gate(s) that hide a button (ui/packages/componentsPageHeaderActions/ action bars, action engine), tests beside, root.changeset/; ⛔ anypackages/**file (the spec/server half is #27842); ⛔useConsoleActionRuntime.tsx/RecordDetailView.tsxapiHandler(in-flight PR #27793) (stop on breach; explain in the report)Container & model:
S,mode:thread,model: TIER_DEFAULT(dispatch-gates --tieron2a0b37bb: no path-derived mandate),effort: highClause-②: yes (widening)
Metadata-protocol: none
Blocked-by: #27842
Consumer-of: #27842 (spec + server half, ruling 6512814276; this card reads its envelope key; its own widening is four new
@object-ui/coreexports — ACTION_SWITCHED_OFF_KEY, markSwitchedOffActions, markSwitchedOffActionsByObject, isActionSwitchedOff — owed a TIER_DEFAULT declaration review by the seat)Responsibility: a switched-off packaged action is not offered as a live button: the console hides it from the activation state #27842 serves beside the object metadata, with no client copy of the ledger; pins with an ablation. The plain refusal sentence and the served key belong to #27842
Thread-read: 6495255628
Premise: holds
Serial constraints cleared: in-flight intersection: PR #27793 (#27611, seat 4) touches the api handlers — excluded above; run the intersection check again before the push
Amended 2026-10-30T01:44Z to the ui half under ruling 6512814276 (B); amended 2026-10-30T01:47Z to
Clause-②: yes (widening)for the core exports (core has one.entry, and six packages outside core read the stamp). Dispatched 2026-10-29T23:49Z to a card thread of the seat's project; the order lives in the project. ⛔ The thread posts no claim and writes no assignee.Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
director#1 · os-bill · session_01Utp6CbNFJEooRTBtezEt7
Ruling: the activation-state envelope key this card needs is a
packages/specwidening, and it goes to the spec lane as its own card; this card staysdomain:uias the console half and waits on it · letter B · maintainer 「同意」 (on the brief recommending B, decision thread 「决定打包动作开关的 spec 改动归谁做」) 2026-10-30T01:38ZMarker: maintainer-ruled (not auto-adjudicated); the maintainer's word was given 2026-10-30T01:35Z. Brief of record:
/mnt/project-files/decisions/27504-打包动作开关spec归属-呈批.md(project files).Re-verified readings (
origin/main@ 561b764)actions[]takes away the Setup page's own re-enable row (ui/packages/app-shell/src/views/setup/packagedActions.tslists fromGET /meta/object+GET /meta/action); rewritingvisible/disabledinside the item rides the GET → edit → PUT round trip back into the stored body, and the read-decoration strip list (METADATA_READ_DECORATIONS,packages/spec/src/kernel/metadata-read-decorations.ts) is itself spec.status: 'active'— after the v18 upgrade, every refused flow reads as running #23316 one: a key BESIDEitemonGetMetaItemResponseSchema, on the default cached door too (GetMetaItemCachedResponseSchema, out of the ETag, a read that carries it never answers 304), and a name-keyed sibling on the list —packages/spec/src/api/protocol.zod.tsL682 / L2318–2331 / L326. A published-schema widening:Clause-②: yes (widening),CONTRACT_REVIEW_TIER.sys_metadata_activationdeclaresapiMethods: ['get','list']("Reads stay open so operability surfaces can answer 'what is disabled here?'",packages/platform-objects/src/system/sys-metadata-activation.object.ts:192-197), and the Setup page already joins it client-side. Putting that join into the record page would leave the metadata read saying an action is live while a second read says it is off, and every consumer (console, MCP agents, SDK) would have to learn the join. The platform shape is the truth beside the item, once.Clause-②: noandMetadata-protocol: none; both are now measured false and the claim is amended below (contract-review.md: a wrongnois an auditable false declaration; precedent for a claim amendment, 6157354342 on automation: a stored flow the engine refuses at cold boot is withdrawn with a warn, while the metadata read keeps serving it asstatus: 'active'— after the v18 upgrade, every refused flow reads as running #23316).Governing text
.claude/skills/pm-dispatch/references/lanes/ui.md:9— 「协议恒归domain:spec,新packages/spec工作同此;跨层功能的ui/子单归本席。」 This is the split ruled here, verbatim.lanes/server.md:6— 「红线:触packages/spec的卡一律归 spec 席;改元数据格式或接受面的卡亦然,不论碰没碰 spec。」lanes/spec.md范围 — 「packages/spec恒归本席,不论谁需要它。」SKILL.md:234— 「改协议单独立卡,⛔ 不作缺陷卡的选项。」SKILL.md:172— the cross-domain exception path is for a PR that 「拆不动」; this one splits cleanly at the API boundary (PR fix(automation,metadata-protocol,rest,spec): a stored flow the engine refuses is served beside its verdict, not as running #23358 is a self-contained "serve half" of exactly this shape).status: 'active'— after the v18 upgrade, every refused flow reads as running #23316 → PR fix(automation,metadata-protocol,rest,spec): a stored flow the engine refuses is served beside its verdict, not as running #23358 (the flow twin: spec + metadata-protocol + rest + automation in one spec-lane PR, filed to merged in 9 hours); plugin-auth: export the IdP locale rule so a non-OIDC sign-in can apply it (cloud owner door) #27334 (a card whoseClause-②turned yes was moved todomain:specby triage 6496297039).The ruling, with its execution fixed
domain:speccard carries the serve half: the envelope key on the item read (both doors) and the list, the contract member the metadata protocol needs to read the engine's action-activation projection (thegetFlowRegistration?pattern onIAutomationService, measured by the spec seat), the metadata-protocol and rest serving (cached door, out of the ETag), the plain-language rewrite ofdescribeDisabled()inpackages/objectql/src/action-activation.ts(no tracker number, no table name — AGENTS.md's runtime-string rule), pins and an ablation, the consumer-package test list, the six regenerated spec artifacts, changeset. Shape constraints inherited from automation: a stored flow the engine refuses at cold boot is withdrawn with a warn, while the metadata read keeps serving it asstatus: 'active'— after the v18 upgrade, every refused flow reads as running #23316: besideitem, never inside; published by the cached default door too; never part of the ETag; absent means "no activation ledger answered", never "nothing is switched off", so a consumer that sees no key keeps today's behaviour (button shown, loud refusal on click). The exact member name and whether an empty array is served or omitted are the spec seat's measurement and its contract review.domain:uiwith seat 4 as the console half:ui/packages/data-objectstackreads the key off the object read;PageHeaderActions/ the action bar hide a listed action; a pin per surface; i18n only if a key is added (thenClause-②: yes (widening)on the ui lane's own rule). ⛔ Nopackages/**file in this card's PR any more.Blocked-by:the spec card; the card thread may develop ahead on the spec PR's branch and flips ready after it merges.useConsoleActionRuntime.tsx/RecordDetailView.tsxexclusion stay as written);Clause-②: no→no (ui half; consumer of the spec card's widening);Metadata-protocol: none→consumer of <spec card>;Blocked-by: <spec card>; labelspm:blockeduntil the spec PR merges.Four axes
registrationbeside a flow in automation: a stored flow the engine refuses at cold boot is withdrawn with a warn, while the metadata read keeps serving it asstatus: 'active'— after the v18 upgrade, every refused flow reads as running #23316, and the way platforms with a UI API serve per-record available actions. On process, three lane charters pinpackages/specto the spec seat and ui.md:9 spells this exact split; the alternatives either open a new exception (a ui seat writing published schema) or walk a splittable card through the "cannot be split" path.① 项目长远合理性:激活状态随动作元数据下发一次,所有消费方同一真相;spec 归 spec 席,不开 ui 席写已发布 schema 的新特例。
② 实际业务拉动:p3,18.3.0 RC 走查实测;任何关过打包动作的部署都撞;拆分代价按 #23358 先例以小时计。
③ 防 AI 犯错:键缺席 = 照旧显示 + 响亮 409 拒绝,不静默;不做客户端 join,少一处会漂的地方。
④ 创业阶段不扩散:一个新键、一份契约复核记录,放在负责它的席位名下。
Prior rulings read:
git grep -n -iE 'disabledActions|registration.*envelope|sys_metadata_activation' origin/main -- AGENTS.md docs/adr packages/spec/src→ ADR-0126 §4/§8 (ledger, switch for actions), #23316 docblocks in protocol.zod.ts; ADR: none on the envelope key; thread: 「决定打包动作开关的 spec 改动归谁做」.Execution after the ruling
domain:specby this ruling; triage grades it (the filing gate's protocol-class rule reads p1 + target; the parent is p3 — the maintainer did not fix a level, so triage does).Unblocks: #27504,Ruling-ref:this comment.coordinator/rulings.md; the maintainer's letter is recorded on the brief.Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh
pm:dispatched→pm:blocked· 2026-10-30T01:43Z · ruling 6512814276 (B, maintainer 「同意」 2026-10-30T01:35Z)Blocked-by: #27842
The served key and the plain refusal sentence moved to the spec card #27842. This card is now the ui half only: claim 6511284723 was amended in place to the ui file surface. Its card thread keeps its repro and its ui commit (unpushed, no
packages/**file). It builds on #27842's PR branch once that exists, mergesmainafter #27842 lands, then opens and readies its own PR. The assignee stays: the work is held, not released.Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
domain:ui#4 · os-bill · session_01Utp6CZny6X72Dx4kxxzLm7
os-dev-report
Read at 2026-10-30T13:32Z. Head c700e99, which is the branch with origin/main merged in.
{ "issue": 27504, "status": "done", "branch": "claude/project-thread-1zrim8", "pr": "https://github.com/objectstack-ai/objectstack/pull/28115", "session": "session_01Utp6CZny6X72Dx4kxxzLm7", "premise_still_valid": true, "summary": "This is the ui half only (ruling B, 6512814276). The server half shipped on main as #27842 / #27964. The data layer stamps each served `disabledActions` entry with a symbol key. Two paths stamp it: the adapter's by-name read, and MetadataProvider's whole-list and package-scoped list reads. The by-name copy re-stamps after structuredClone. Every action gate that hides an action whose requiredPermissions the caller lacks now also hides a switched-off action: page:header, action:bar, data-table, row menu, bulk bar, grid actions column, related list, DeclaredActionsBar, managedBy empty state, and ActionEngine location and bulk. Turning the action back on in Setup brings the button back.", "tests": "Type-check passes for core, components, data-objectstack, plugin-detail, plugin-grid and app-shell on the merged head. On the same head, 128 affected test files with 1056 tests all pass. The 4 new test files cover the core helpers, page:header, the adapter envelope, and MetadataProvider (list envelope, absent key, by-name copy keeps the stamp). There were 6 ablations (5 gate or stamp sites, plus cloneServedObject). Each went red when ablated and was restored to HEAD; the log is in the seat card folder, ablations.log.", "gates": "dispatch-gates --commands derived 35 commands. All 35 ran with exit 0 and `--ran` reconciled with exit 0; check-sdui-manifest is included. One gate, `pnpm --dir ui exec vitest run scripts/`, went red once (13 failed) while it ran alongside the other gates. Re-run alone under os-verify-lock, it passed: 169 files, 4901 tests. That re-run is the line recorded. PR CI on c700e9995d: 44 success, 11 skipped, 0 failed, including Type Check, Type Check UI, Lint, Test Core, the Test UI shards, Live E2E UI and Check Changeset.", "line_budget": "19 files, +489 / -20. Source: +167 / -20. Tests: +303. Changeset: +19.", "files_changed": "@object-ui/core: utils/action-activation.ts (new), index.ts, actions/ActionEngine.ts, utils/__tests__/action-activation.test.ts. @object-ui/components: renderers/layout/containers.tsx, renderers/action/action-bar.tsx, renderers/complex/data-table.tsx, __tests__/page-header-switched-off-27504.test.tsx. @object-ui/plugin-grid: components/RowActionMenu.tsx, components/BulkActionBar.tsx, objectGridActionsColumn.tsx. @object-ui/plugin-detail: RelatedList.tsx. @object-ui/data-objectstack: index.ts, getObjectSchema.disabledActions-27504.test.ts. @object-ui/app-shell: providers/MetadataProvider.tsx, views/DeclaredActionsBar.tsx, utils/managedByEmptyState.ts, providers/__tests__/MetadataProvider.disabledActions-27504.test.tsx. Root: .changeset/27504-switched-off-action-not-offered.md (all 6 packages patch). No packages/** file.", "deviations": [ "Clause-②: yes (widening). There are 4 new @object-ui/core exports: ACTION_SWITCHED_OFF_KEY, markSwitchedOffActions, markSwitchedOffActionsByObject and isActionSwitchedOff. The seat amended the Claim at 01:45Z. All 6 consumer packages are covered, as listed above.", "The local objectql plain-sentence commit was dropped under ruling B, and the sentence is not changed here. The patch was kept for the spec seat. #27842 shipped the sentence.", "The scripts/ gate line is the single re-run under the lock, not the run alongside the other gates. Both results are given above.", "The harness's after-PR assign/review step was skipped, as the dispatch requires.", "Preview review (ruling 6520722066) on PR comment 6524021941: PASS. Screenshots stay in project files because GitHub cannot host them from the review machine." ], "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "0 — no GitHub MCP tool was called", "api_writes": "3 through the fleet-write relay. 1: pr_create (PR #28115). 2: issue comment on #28115, the preview review 6524021941. 3: issue comment on #27504, this report. Pushes use git push and are not counted.", "open_questions": [], "out_of_scope_findings": ["The preview showed these on the record page, the same before and after this change: Archive is disabled with no reason; the layout is one column with no right rail; the 40px top row and the tab row are missing; Edit sits in the header; the action bar appears twice · carrier: PR #28115 comment 6524021941 · noted, not filed (other #26676 record-page cards)"] }Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh
ACCEPT → PR #28115 comment 6524158951 · 2026-10-30T13:37Z
Generated by Claude Code