From ae983d42aa9350c79ac532501445d099378bd178 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 4 Nov 2026 18:22:43 +0000 Subject: [PATCH 1/3] docs(qa): drop the stale dataset-editor parenthetical in dashboard-widget-and-filter-types Studio's New dataset entry sits beside the widget inspector's dataset picker and the New report dialog's (datasetCreate.tsx DatasetCreateEntry). The fixture stays API-written for a known shape. Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_017ihL2ebbZkr2QAEG1x7UC8 --- docs/qa/platform-checklist/areas/studio-authoring.json | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/qa/platform-checklist/areas/studio-authoring.json b/docs/qa/platform-checklist/areas/studio-authoring.json index 3bdd4baf304..339f065cd77 100644 --- a/docs/qa/platform-checklist/areas/studio-authoring.json +++ b/docs/qa/platform-checklist/areas/studio-authoring.json @@ -3439,7 +3439,7 @@ "title": "A package dashboard renders every widget type the spec declares — those Studio offers and those written through the API — and every global-filter type renders its control and re-scopes the widgets bound to it; Studio's two widget-type entries offer the same set", "since": "v18", "status": "active", - "revision": 6, + "revision": 7, "priority": "P2", "surface": "mixed", "personas": [ @@ -3450,7 +3450,7 @@ "requires": [ "a fresh boot of the showcase on its own port and DB (dogfood §0) with OS_PORT exported, signed in as the seeded admin, and a console built from this tree with `pnpm console:build` — the root `pnpm build` does not refresh packages/console/dist (QA run #26715 needed the console build on every card)", "a writable package with an app whose menu names one dashboard", - "a dataset over a package object, with at least one dimension and one measure, written with PUT /api/v1/meta/dataset/NAME?mode=draft&package=PKG and published — Studio has no dataset editor (expected: the Interfaces card read it no-entry), so reports and widgets bind to an API-written dataset. Give it several dimensions (a status-like category and a date) and a few measures over seeded multi-bucket rows — examples/app-showcase/src/ui/dashboards/chart-gallery.dashboard.ts is the model for each type's bindings. Sankey takes no source/target pair: it flows from one root node (the total) to each category of its first dimension; with a second dimension (two or more pivoted series) there is no root: each flow runs from a first-dimension category to a second-dimension value, two columns of nodes (ui/packages/plugin-charts/src/AdvancedChartImpl.tsx, the sankey arm and buildSankeyCellFlows, #27460; the gallery's sankey_flow binds dimensions ['status'])" + "a dataset over a package object, with at least one dimension and one measure, written with PUT /api/v1/meta/dataset/NAME?mode=draft&package=PKG and published — the fixture stays API-written for a known shape, though Studio can now create a dataset (the widget inspector's dataset picker and the New report dialog each carry a 'New dataset' button, ui/packages/app-shell/src/views/studio-design/datasetCreate.tsx DatasetCreateEntry, engine.studio.interfaces.newDataset.*), so reports and widgets bind to an API-written dataset. Give it several dimensions (a status-like category and a date) and a few measures over seeded multi-bucket rows — examples/app-showcase/src/ui/dashboards/chart-gallery.dashboard.ts is the model for each type's bindings. Sankey takes no source/target pair: it flows from one root node (the total) to each category of its first dimension; with a second dimension (two or more pivoted series) there is no root: each flow runs from a first-dimension category to a second-dimension value, two columns of nodes (ui/packages/plugin-charts/src/AdvancedChartImpl.tsx, the sankey arm and buildSankeyCellFlows, #27460; the gallery's sankey_flow binds dimensions ['status'])" ] }, "steps": [ @@ -3553,6 +3553,12 @@ "date": "2026-11-04", "change": "steps[5], acceptance[4].verify and fixtures.requires[2] corrected from QA run #29890 (W5-FAIL, at 589049b0): the wave-4 shape (Field filled, Options From begun; #29006, fixed by #29300) is its own case (d), and a two-dimension sankey draws no root node: its flows run from the first dimension's categories to the second's values (buildSankeyCellFlows). Read at base f68b47ca", "ref": "#29906" + }, + { + "revision": 7, + "date": "2026-11-04", + "change": "fixtures.requires[2]: the 'Studio has no dataset editor' parenthetical is stale, as #29906 found for interfaces-create-dialogs and report-authoring-options. Studio's New dataset entry (datasetCreate.tsx DatasetCreateEntry, objectstack#27518) sits beside the widget inspector's dataset picker (DashboardWidgetInspector.tsx) and the New report dialog's. The fixture stays API-written for a known shape. No clause changed. Read at base 232d3bb5ef", + "ref": "#30129" } ] }, From d815351ed6cdc11dca603893bd6c6018a2334ef7 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 4 Nov 2026 18:28:58 +0000 Subject: [PATCH 2/3] docs(qa): re-point the zh-CN template writes and the built-in nav walk email-template-render and meta-read-doors-v18 author the zh-CN member of showcase_task_done_email into com.example.showcase.custom with no overrides, the recipe measured on a fresh showcase boot: the package-less PUT and the declared override both answer 403 NOT_OVERRIDABLE, the undeclared pair member writes, is served by ?member=zh-CN and renders for a zh-CN recipient. builtin-apps-nav-render steps[5] carries 46 Setup and 8 Account destinations, re-read at base, and steps[2] unfolds the icon rail before expanding groups. Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_017ihL2ebbZkr2QAEG1x7UC8 --- docs/qa/platform-checklist/areas/api-backend.json | 10 ++++++++-- .../platform-checklist/areas/integration-system.json | 10 ++++++++-- docs/qa/platform-checklist/areas/platform-core.json | 12 +++++++++--- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/docs/qa/platform-checklist/areas/api-backend.json b/docs/qa/platform-checklist/areas/api-backend.json index 77367d34a55..3f4a0692380 100644 --- a/docs/qa/platform-checklist/areas/api-backend.json +++ b/docs/qa/platform-checklist/areas/api-backend.json @@ -3205,7 +3205,7 @@ "title": "/meta read doors on v18: GET /meta/app/PACKAGE_ID returns that package's app, `?member=` selects one bundle member on by-name doors, an unknown query parameter on any by-name door is refused 400, `?package=all` folds to the no-parameter answer, and the object definition marks an FLS-denied field unsortable for that caller", "since": "v18", "status": "active", - "revision": 4, + "revision": 5, "priority": "P2", "surface": "api", "personas": [ @@ -3216,7 +3216,7 @@ "app": "showcase", "requires": [ "a fresh boot of the showcase: `pnpm dev -- --fresh -p PORT --seed-admin` (ephemeral DB; the seeded admin is printed)", - "a showcase email template with two locale members: the showcase ships only the en-US member of showcase_task_done_email (examples/app-showcase/src/system/emails), so author the zh-CN member with PUT /api/v1/meta/email_template/showcase_task_done_email carrying `locale: 'zh-CN'` in the BODY — the save door's closed set is force, package, mode and surface, so ?member= is a READ parameter only" + "a showcase email template with two locale members: the showcase ships only the en-US member of showcase_task_done_email (examples/app-showcase/src/system/emails), so author the zh-CN member into the showcase's customization pair: POST /api/v1/packages/com.example.showcase/ensure-customization, then PUT /api/v1/meta/email_template/showcase_task_done_email?package=com.example.showcase.custom carrying `locale: 'zh-CN'` in the BODY and no `overrides` (the base ships no zh-CN member, so a declared override is refused 403 NOT_OVERRIDABLE, and a package-less PUT onto the shipped name is refused 403 NOT_OVERRIDABLE since ADR-0146 D11; packages/qa/dogfood/test/meta-read-doors-live.dogfood.test.ts authors it the same way) — the save door's closed set is force, package, mode and surface, so ?member= is a READ parameter only" ] }, "steps": [ @@ -3296,6 +3296,12 @@ "date": "2026-10-27", "change": "acceptance[1]–[4] are pinned at the layer their oracle names (the release-18.2.0 Tier 1 sweep #26468 scored a1–a4 partial: every pin but the data-sort dogfood stopped above the Hono adapter, and that one used a scratch permission set, not client_liaison). The new meta-read-doors-live.dogfood.test.ts drives each step through the HTTP stack of its own showcase boot, client_liaison bound through a sys_user_position row; automated.ref and acceptance[4].verify name it. Measured at base 74db43ef. No clause changed", "ref": "#26572" + }, + { + "revision": 5, + "date": "2026-11-04", + "change": "fixtures.requires[1] corrected: the bare PUT of a zh-CN member onto the shipped showcase_task_done_email is package-less, which ADR-0146 D11 refuses 403 NOT_OVERRIDABLE. The member is now authored into com.example.showcase.custom with no `overrides`, the shape meta-read-doors-live.dogfood.test.ts already uses. Measured on a fresh showcase boot at base 232d3bb5ef: package-less PUT 403; pair PUT with overrides 403 (the base ships no zh-CN member); pair PUT without overrides 200, then ?member=zh-CN serves it and ?member=en-US the shipped member. No clause changed", + "ref": "#30129" } ] }, diff --git a/docs/qa/platform-checklist/areas/integration-system.json b/docs/qa/platform-checklist/areas/integration-system.json index ca642d82630..1d4984a4750 100644 --- a/docs/qa/platform-checklist/areas/integration-system.json +++ b/docs/qa/platform-checklist/areas/integration-system.json @@ -897,7 +897,7 @@ "title": "Email templates resolve from the registry (no sys_email_template row since ADR-0131 D6/D10), resolve (name, locale) with en-US fallback, render {{path}} holes, gate on required variables and active:false, survive admin edits across redeploys — and the raw POST /api/v1/email/send door authenticates, requires manage_platform_settings, bounds sentBy, from, headers, organizationId and identityMail, refuses anonymous, and 400s malformed input", "since": "v15", "status": "active", - "revision": 14, + "revision": 15, "priority": "P2", "surface": "mixed", "fixtures": { @@ -905,7 +905,7 @@ "requires": [ "the shipped fixture: showcase_task_done_email (subject '✅ Task done: {{title}}', variables title required / project optional — examples/app-showcase/src/system/emails/index.ts). It declares no `category`: that key and `isSystem` are RETIRED (#22876, ADR-0049 — retiredKey() tombstones on the template schema), so a template authored with either is refused at parse with the prescription", "a capturable email channel (dev transport / log capture — no real SMTP needed)", - "a second-locale scratch copy (same name, locale zh-CN) for the i18n-bundle clause", + "a zh-CN member of the shipped template for the i18n-bundle clause, authored into the showcase's customization pair: POST /api/v1/packages/com.example.showcase/ensure-customization (201 the first time, 200 after), then PUT /api/v1/meta/email_template/showcase_task_done_email?package=com.example.showcase.custom with the shipped body carrying locale: 'zh-CN' and NO `overrides`. The base ships en-US alone, so a zh-CN member is the pair's own item, not an override: declaring `overrides` for it answers 403 NOT_OVERRIDABLE ('… ships no email_template named … with locale 'zh-CN'', declared_package_ships_no_such_item, packages/metadata-protocol/src/protocol-packaged-base-refusal.ts), and a package-less PUT of it answers 403 NOT_OVERRIDABLE since ADR-0146 D11. Reset it with DELETE /api/v1/meta/email_template/showcase_task_done_email?package=com.example.showcase.custom&member=zh-CN", "for acceptance[5]'s declared-source half a WRITABLE copy of the showcase (a scratch copy under /tmp, never the tree): the stock app is a read-only code package, so a run cannot edit its declared template source. QA run #23166 scored that half partial for want of one; the admin-edit half runs on stock" ], "knownGaps": [ @@ -1090,6 +1090,12 @@ "date": "2026-11-04", "change": "steps[3], [4], [6] and [9], acceptance[3].verify, acceptance[5].clause and acceptance[7].verify corrected from QA run #29890 (W5-FAIL, at 589049b0). (1) ADR-0146 D11: a package-less PUT of the shipped template answers 403 NOT_OVERRIDABLE, so the admin edit is an override saved in com.example.showcase.custom through the ensure door. (2) A non-string display name is 400 VALIDATION_FAILED since #29891, and every message the service refuses 400 VALIDATION_FAILED leaves a sys_email row 'failed' ('rejected before delivery: …'). (3) The clause's no-locale branch is unreachable over HTTP: the email channel always names the recipient's locale or the deployment default. (4) A member is read with ?member=, which ?locale= does not select. Read at base f68b47ca", "ref": "#29906" + }, + { + "revision": 15, + "date": "2026-11-04", + "change": "fixtures.requires[2] corrected: the 'same name, locale zh-CN' scratch copy was written package-less onto the shipped name, which ADR-0146 D11 refuses 403 NOT_OVERRIDABLE. The zh-CN member is now authored into com.example.showcase.custom with no `overrides`, since the base ships no zh-CN member and a declared override of one is refused 403 NOT_OVERRIDABLE (declared_package_ships_no_such_item). Measured on a fresh showcase boot at base 232d3bb5ef: package-less zh-CN PUT 403; ensure-customization 201; pair PUT with overrides 403; pair PUT without overrides 200, served by ?member=zh-CN; a scratch api notify flow then sent the zh-CN wording to a zh-CN-locale recipient and the en-US wording to an en-US one (sys_email 'sent'); DELETE ?package=…custom&member=zh-CN 200, then ?member=zh-CN 404. No clause changed", + "ref": "#30129" } ] }, diff --git a/docs/qa/platform-checklist/areas/platform-core.json b/docs/qa/platform-checklist/areas/platform-core.json index 01e6f9624c2..6ee51c2fd49 100644 --- a/docs/qa/platform-checklist/areas/platform-core.json +++ b/docs/qa/platform-checklist/areas/platform-core.json @@ -609,7 +609,7 @@ "title": "The built-in apps a stock boot REGISTERS (Setup / Account) render every merged-nav destination; app-level and entry-level gates are enforced, not errored — and Studio's deliberate absence is asserted, never hunted", "since": "v15", "status": "active", - "revision": 12, + "revision": 13, "priority": "P0", "surface": "browser", "personas": [ @@ -631,10 +631,10 @@ "steps": [ "as admin, GET /api/v1/meta/app?id=setup and extract every merged nav destination — Setup is a SHELL of empty group anchors (packages/platform-objects/src/apps/setup.app.ts: group_overview/apps/people_org/access_control/approvals/configuration/diagnostics/integrations/advanced) filled by SETUP_NAV_CONTRIBUTIONS (setup-nav.contributions.ts) plus capability-plugin contributions (plugin-security Positions/Permission Sets, plugin-sharing Sharing Rules/Record Shares, plugin-approvals, plugin-webhooks)", "GET /api/v1/meta/app with NO query first and record the names actually served — a stock boot answers exactly showcase_app, setup, account. Then GET /api/v1/meta/app?id=account (account.app.ts — Profile + Inbox/Security/Developer groups). ⚠️ GET /api/v1/meta/app?id=studio answers 200 {\"items\":[]} on every stock boot and that is the expected result (knownGap): record the absence as an assertion and move on — do NOT install @objectstack/studio to make the step runnable", - "as admin, hand-walk each destination in each app. EXPAND every nav group first: some render collapsed by default — Setup's Advanced group and Account's Developer group declare `expanded: false` (packages/platform-objects/src/apps/setup.app.ts, account.app.ts), and QA run #24557 found Setup's Configuration group collapsed as well — so a walk that never expands them never reaches their entries. Then navigate, wait for render, SCREENSHOT FIRST, then read the DOM — assert no pageerror, no 'failed to load', no blank
, no 'no actions configured' placeholder", + "as admin, hand-walk each destination in each app. At a window narrower than 1416 px (1280 px included) the console folds the sidebar to its icon rail, and Setup and Account open that way (ui/packages/app-shell/src/layout/consoleSidebarRail.ts CONSOLE_SIDEBAR_RAIL_BELOW_WIDTH, objectstack#27593; QA run #29877 met it at 1280 px): press the sidebar toggle at the app bar's left edge (Ctrl/⌘+B) to unfold it before expanding any group. EXPAND every nav group first: some render collapsed by default — Setup's Advanced group and Account's Developer group declare `expanded: false` (packages/platform-objects/src/apps/setup.app.ts, account.app.ts), and QA run #24557 found Setup's Configuration group collapsed as well — so a walk that never expands them never reaches their entries. Then navigate, wait for render, SCREENSHOT FIRST, then read the DOM — assert no pageerror, no 'failed to load', no blank
, no 'no actions configured' placeholder", "Setup detail: confirm each settings URL entry (nav_settings_* → /apps/setup/system/settings/) opens the settings namespace form — the 11 namespaces of a stock single-posture boot, localization/company/branding/auth/mail/sms/storage/ai/knowledge/lifecycle/feature_flags: the nav_settings_* entries of packages/platform-objects/src/apps/setup-nav.contributions.ts, plus nav_settings_branding, which packages/services/service-settings/src/settings-service-plugin.ts contributes only where no organization wall stands, and Users / Organization / Business Units / Teams / Sessions / OAuth Applications render. User preferences and identity links are not Setup destinations: open a user from Users and confirm the user page's Preferences and Linked Accounts tabs render that user's rows", "Studio detail is NOT walked from here — the app is not registered on a stock boot (knownGap), so there is no merged nav to render. Its metadata:resource lists and component surfaces (App Builder, All Metadata Types, Packages, API Console, Flow Runs, Public Forms) are reached through the console surface at /_console/studio// and are covered by area studio-authoring. What THIS item asserts about Studio is the absence itself, per clause 6", - "Account detail: confirm Profile (account:profile_card), Notifications (sys_inbox_message/mine), Approvals (nav_account_approvals, the approvals:inbox component, served as …/component/approvals/inbox — the Approvals Inbox, not the sys_approval_request grid; account.app.ts), Linked Accounts (sys_account), Active Sessions (sys_session/mine), API Keys (sys_api_key/mine), OAuth Applications (sys_oauth_application/mine) and Connect an Agent (nav_connect_agent) each render — 8 Account destinations and 50 Setup destinations for the admin on a stock single-org showcase boot, as QA run #28545 read them at eeec88d1 (GET /api/v1/meta/app leaves, which match the nav source minus its gates; 48 re-measured at 3fd80337 for #28338, QA run #27481 read 44 and 8, QA run #24557 read 42 at 5b14b7f3, 45 on 2026-10-01, and #9453 recorded 43 and 7). Recount from the payload each run", + "Account detail: confirm Profile (account:profile_card), Notifications (sys_inbox_message/mine), Approvals (nav_account_approvals, the approvals:inbox component, served as …/component/approvals/inbox — the Approvals Inbox, not the sys_approval_request grid; account.app.ts), Linked Accounts (sys_account), Active Sessions (sys_session/mine), API Keys (sys_api_key/mine), OAuth Applications (sys_oauth_application/mine) and Connect an Agent (nav_connect_agent) each render — 8 Account destinations and 46 Setup destinations for the admin on a stock single-org showcase boot, as QA run #29877 read them at 589049b0 and a fresh showcase boot re-read them at 232d3bb5ef (GET /api/v1/meta/app leaves, which match the nav source minus its gates). Since QA run #28545's reading Setup's Packaged automation page retired under ADR-0146 D11, leaving Packaged Actions (nav_packaged_actions, automation:packaged-actions; #28785), and its unfiltered Packages entry moved to Studio (#29547) (47 for #28927, 50 at eeec88d1 for QA run #28545, 48 re-measured at 3fd80337 for #28338, QA run #27481 read 44 and 8, QA run #24557 read 42 at 5b14b7f3, 45 on 2026-10-01, and #9453 recorded 43 and 7). Recount from the payload each run", "confirm the gated entries resolve to ABSENT-not-erroring for the admin: nav_organizations (requiresService org-scoping) is absent in single-org mode; nav_jwks Signing Keys is ABSENT for EVERY persona, admin included — the entry was removed in #7544 because sys_jwks declares apiEnabled:false, so its list answers OBJECT_API_DISABLED (404) for all callers and no permission gate could prune it; SSO Providers is absent unless OS_SSO_ENABLED (knownGap)", "sign in as the plain member: attempt to open Setup (app name setup) — capture the app-level refusal (App.requiredPermissions setup.access); open Account (declares no requiredPermissions) — capture it opening. Studio is not part of this comparison: it is absent for EVERY persona including the admin, so a member failing to reach it proves nothing about the gate (the same reasoning #7544 applied to nav_jwks)", "as the member, GET /api/v1/meta/app for a reachable app and confirm every manage_platform_settings-gated entry (API Keys, the manage_platform_settings settings URLs) is ABSENT from the member's payload — the server prunes, the client does not merely hide. JWKS is deliberately NOT in this list any more: it is absent for admins too, so finding it absent for a member proves nothing about the gate (#7544)", @@ -761,6 +761,12 @@ "date": "2026-11-01", "change": "Two QA run #28545 (W3-C1R) findings. negative[3], stale since #27507: the member's settings route no longer renders inside the app shell it was opened from. AppContent.tsx holds a Setup pseudo-route until Setup's access verdict, then draws the 'You don't have access to this app' screen above the layout, with no shell; the page never mounts, so the wire half is driven directly (GET /api/settings/NAMESPACE, 403 SETTINGS_FORBIDDEN, kept as the scored part). Counts: steps[4] lists the 11 namespaces a stock boot serves (sms and lifecycle added; setup-nav.contributions.ts plus the unwalled-only branding entry), and steps[5] carries #28545's 50 Setup and 8 Account destinations, which stay 'recount from the payload each run'. The namespace list is read from source; the 50 is #28545's live reading. No clause weakened. Read from source at base 6b9c1ca991. Wave anchor #27377, wave-3 accuracy slice S9 (#28641); finding parked in anchor comment 6554042054", "ref": "#28545" + }, + { + "revision": 13, + "date": "2026-11-04", + "change": "steps[2] and steps[5] corrected, two QA run #29877 (W5-P0, at 589049b0) findings parked in comment 6600018008 on #27377 that #29906 did not carry; revision 7's steps[2]/[5] row is an older, different fix. steps[5]: Setup serves 46 destinations (Account 8), not 50; Packaged automation retired under ADR-0146 D11 (#28785) and the unfiltered Packages entry left Setup (#29547). steps[2]: below 1416 px, 1280 px included, Setup and Account open on the icon rail (consoleSidebarRail.ts CONSOLE_SIDEBAR_RAIL_BELOW_WIDTH), so the walk unfolds the sidebar before it expands groups. The 46 / 8 re-read on a fresh showcase boot at base 232d3bb5ef (GET /api/v1/meta/app?id=setup / ?id=account, groups excluded); the rail threshold read from source, not driven live. No clause changed", + "ref": "#30129" } ] }, From ecccdedfea0252d3f155a8b8030c8d1a51d23cbc Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 4 Nov 2026 18:41:46 +0000 Subject: [PATCH 3/3] docs(qa): drop the stale dataset-editor reason in the no-entry property matrix Studio's New dataset writes only a name, an object, the seed's count measure, group-by dimensions and sum measures, so the dataset row's keys still have no Studio control; only the reason it gave was stale. Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_017ihL2ebbZkr2QAEG1x7UC8 --- .../platform-checklist/areas/studio-authoring.json | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/qa/platform-checklist/areas/studio-authoring.json b/docs/qa/platform-checklist/areas/studio-authoring.json index 339f065cd77..eeac31bcb3b 100644 --- a/docs/qa/platform-checklist/areas/studio-authoring.json +++ b/docs/qa/platform-checklist/areas/studio-authoring.json @@ -4239,7 +4239,7 @@ "title": "Authorable keys Studio has no control for still work when another door writes them: per metadata type, each key written into a package draft through the metadata API is stored, served after publish and takes its runtime effect", "since": "v18", "status": "active", - "revision": 6, + "revision": 7, "priority": "P2", "surface": "mixed", "personas": [ @@ -4325,7 +4325,7 @@ "view.list: searchableFields, userFilters, resizable, compactToolbar, selection, pagination, rowHeight, grouping, rowColor, hiddenFields, fieldOrder, rowActions, bulkActions, conditionalFormatting, inlineEdit, exportOptions (needs an export grant), appearance, addRecord, showRecordCount, allowPrinting, emptyState → each renders as its key describes; probe compactToolbar, showRecordCount and resizable at the value opposite to what the list does with the key unset, since at that default a stored key renders exactly like no key and proves nothing (gap-view card, 3fcafcd3)", "view.form: groups, subforms, submitBehavior, modalSize, allowSkip, showStepIndicator, buttons → render as described (buttons measured rendering, knownGaps[0]); splitDirection / splitSize / splitResizable → refused at parse (retired in @objectstack/spec 18.3.0 with the split form, ADR-0050); drawerSide / drawerWidth → refused at parse (retired in @objectstack/spec 18.3.0, ADR-0049: no form view opens in a drawer); defaults: partial (knownGaps[0]). layout, defaultTab and tabPosition are not rows: Studio offers a control for each (step 4, knownGaps[0]). modalSize acts only on the form view the record modal selects, the object's default form view, or for a create its `create` form view when one is declared (selectRecordFormView, ui/packages/app-shell/src/utils/recordFormNavigation.ts), so author it there", "dashboard.requiredPermissions → a viewer without the capability is refused the dashboard", - "dataset (Studio has no dataset editor): include, dimensions with nullLabel, measures count / sum / avg / filtered / ratio, currency format → a report bound to it shows the null bucket labelled and each measure's value", + "dataset (Studio's New dataset, ui/packages/app-shell/src/views/studio-design/datasetCreate.tsx DatasetCreateEntry, writes only a name, an object, the seed's count measure, group-by dimensions and sum measures, so it offers no control for the keys below): include, dimensions with nullLabel, measures count / sum / avg / filtered / ratio, currency format → a report bound to it shows the null bucket labelled and each measure's value", "permission.description / isDefault / allowExport / rowLevelSecurity[].positions → the Setup list shows the description; isDefault raises a suggestion; allowExport → export 200 with it, 403 EXPORT_NOT_PERMITTED without; positions limit the policy to holders of the position" ], "traps": [ @@ -4367,7 +4367,13 @@ "ref": "#28345" }, { "revision": 5, "date": "2026-11-03", "change": "the view.form row drops drawerSide, drawerWidth, layout, defaultTab and tabPosition as step 4 says, fixtures.knownGaps[0] records why, and the object titleFormat cell moves to a refusal. QA run #29672 read drawerSide and drawerWidth answer 422 (retired in spec 18.3.0, ADR-0049; their retiredKey tombstones in packages/spec/src/ui/view.zod.ts), so they are refused, not stored and inert; and Studio's form-view inspector now offers Layout, Columns, Default Tab and Tab Position (ViewVariantInspector.tsx hands the form variant's spec schema to SchemaForm), which step 4 moves out of the matrix. The run's layout:'horizontal' fail on the Studio canvas was #29676, fixed by #29759 (7ba8b11f52). The buttons cell follows revision 3's knownGaps[0] reading. titleFormat has been refused since 3557366c02 (title-format-retired); the run read the publish refuse it on studio-authoring.api-written-keys-survive-studio-save. The other view.form keys' Studio census was not re-read; the next run's step 4 decides it. The clauses are unchanged. Read at base 339f63da30. Card #29679, from QA run #29672", "ref": "#29679" }, - { "revision": 6, "date": "2026-11-04", "change": "fixtures.knownGaps[0], variants[25], [32] and [33] and acceptance[0].verify corrected from QA run #29890 (W5-FAIL, at 589049b0): a lockedBy-only list view shows its lock indicator since #29312, so it leaves the failing rows; sortable names its observables (header, Sort picker, 400 INVALID_SORT; #29896, #30024); compactToolbar, showRecordCount and resizable are probed at a non-default value; modalSize acts on the form view the record modal selects; a conditionalFormatting condition is stored as a CEL envelope. Read at base f68b47ca", "ref": "#29906" } + { "revision": 6, "date": "2026-11-04", "change": "fixtures.knownGaps[0], variants[25], [32] and [33] and acceptance[0].verify corrected from QA run #29890 (W5-FAIL, at 589049b0): a lockedBy-only list view shows its lock indicator since #29312, so it leaves the failing rows; sortable names its observables (header, Sort picker, 400 INVALID_SORT; #29896, #30024); compactToolbar, showRecordCount and resizable are probed at a non-default value; modalSize acts on the form view the record modal selects; a conditionalFormatting condition is stored as a CEL envelope. Read at base f68b47ca", "ref": "#29906" }, + { + "revision": 7, + "date": "2026-11-04", + "change": "variants[35]: the 'Studio has no dataset editor' parenthetical is stale, found while applying #30129 line 1 (dashboard-widget-and-filter-types). Studio's New dataset (datasetCreate.tsx DatasetCreateEntry, buildDatasetSkeleton) writes only a name, an object, the seed's count measure, group-by dimensions and sum measures, so include, nullLabel, the avg / filtered / ratio measures and a currency format still have no Studio control and the row stays in the matrix. No clause changed. Read at base 232d3bb5ef", + "ref": "#30129" + } ] }, {