|
632 | 632 | "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)", |
633 | 633 | "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", |
634 | 634 | "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 <main>, no 'no actions configured' placeholder", |
635 | | - "Setup detail: confirm each settings URL entry (nav_settings_* → /apps/setup/system/settings/<namespace>) 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", |
| 635 | + "Setup detail: confirm each settings URL entry (nav_settings_* → /apps/setup/system/settings/<namespace>) opens the settings namespace form — the 10 namespaces of a stock single-posture boot, localization/company/branding/auth/mail/sms/storage/ai/knowledge/lifecycle: 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", |
636 | 636 | "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/<pkg>/<pillar> and are covered by area studio-authoring. What THIS item asserts about Studio is the absence itself, per clause 6", |
637 | 637 | "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", |
638 | 638 | "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)", |
|
785 | 785 | "fixtures": { |
786 | 786 | "app": "showcase", |
787 | 787 | "requires": [ |
788 | | - "the 11 open-framework settings namespaces a stock boot serves: the 10 in builtinSettingsManifests (packages/services/service-settings/src/manifests: localization, company, branding, auth, mail, sms, storage, ai, knowledge, feature_flags) PLUS lifecycle (5 specifiers), which is NOT in that aggregate — ObjectQLPlugin registers it at kernel:ready whenever a SettingsService is present (packages/objectql/src/lifecycle/lifecycle-settings.ts). Enumerating only the manifests directory undercounts by one", |
| 788 | + "the 10 open-framework settings namespaces a stock boot serves: the 9 in builtinSettingsManifests (packages/services/service-settings/src/manifests: localization, company, branding, auth, mail, sms, storage, ai, knowledge) PLUS lifecycle (5 specifiers), which is NOT in that aggregate — ObjectQLPlugin registers it at kernel:ready whenever a SettingsService is present (packages/objectql/src/lifecycle/lifecycle-settings.ts). Enumerating only the manifests directory undercounts by one", |
789 | 789 | "the settings service wired with a data engine so it swaps from in-memory to the sys_setting table, and with the sys_secret store + auditWriter (SettingsServicePlugin binds these on kernel:ready; the showcase stack mounts the engine)" |
790 | 790 | ], |
791 | 791 | "knownGaps": [ |
792 | 792 | "HONORING the ai.json caveat: a saved settings FORM is NOT proof of effect — the AI namespace's test action is a stub validator until @objectstack/service-ai is mounted, and a saved ai.provider does nothing observable without it. The effect clause therefore uses localization, whose consumer (resolve-authz-context.ts reads localization.timezone/locale/currency onto every ExecutionContext) is stock and observable; branding.workspace_name in the shell is the browser fallback. Never tick effect off a persisted form." |
793 | 793 | ] |
794 | 794 | }, |
795 | 795 | "steps": [ |
796 | | - "as admin, GET /api/settings — capture the visible manifests (the 11 open-framework namespaces above; the route is the SettingsService REST surface in settings-routes.ts)", |
| 796 | + "as admin, GET /api/settings — capture the visible manifests (the 10 open-framework namespaces above; the route is the SettingsService REST surface in settings-routes.ts)", |
797 | 797 | "pick localization (an OBSERVABLE-CONSUMER namespace — packages/core/src/security/resolve-authz-context.ts reads localization.timezone/locale/currency onto ExecutionContext). GET /api/settings/localization — capture {manifest, values}; note the timezone value and its source. On an `os dev --seed-admin` boot the dev seed has ALREADY written the host's zone (UTC in these containers) at tenant scope (packages/plugins/plugin-auth/src/auth-plugin.ts, #23175), so source reads 'tenant' before any PUT; only a boot without the dev seed starts at 'default'", |
798 | 798 | "change it: PUT /api/settings/localization { timezone: 'Asia/Tokyo' }; re-read GET /api/settings/localization and confirm the value persists and source is the scope, 'tenant' (localization scope is 'tenant'): on a dev-seeded boot the source already read 'tenant', so the value is what round-trips; on an unseeded boot the source flips from 'default'. For the console badge (steps[5]) pick a localization key the dev seed did NOT write (e.g. default_country), so its source starts at 'default'", |
799 | 799 | "prove EFFECT (not just the saved form): re-derive an ExecutionContext-dependent output and confirm it now resolves against the saved zone, not UTC. Two stock consumers serve: GET /api/v1/auth/me/localization (the resolved timezone the session carries), and a datetime the console renders — e.g. showcase_field_zoo's f_datetime on its record page, which shifts by exactly the zone offset. ⛔ The analytics date bucket has no stock observable (the only date-typed time dimension is due_date, and the seeded admin holds no export grant), so do not reach for it. If no localization effect is observable at all, fall back to branding.workspace_name visible in the console shell — but never tick effect off the form alone", |
|
882 | 882 | "evidence": "the two 401 bodies" |
883 | 883 | }, |
884 | 884 | { |
885 | | - "clause": "each of the 11 open-framework namespaces resolves GET /api/settings/:ns with its manifest + values — no namespace 500s or serves an empty manifest", |
| 885 | + "clause": "each of the 10 open-framework namespaces resolves GET /api/settings/:ns with its manifest + values — no namespace 500s or serves an empty manifest", |
886 | 886 | "oracle": "api", |
887 | 887 | "verify": "one GET per variant in variants[]; each returns {manifest, values} with the manifest's specifiers", |
888 | 888 | "evidence": "the per-namespace responses" |
|
907 | 907 | "sms", |
908 | 908 | "storage", |
909 | 909 | "ai", |
910 | | - "knowledge", |
911 | | - "feature_flags" |
| 910 | + "knowledge" |
912 | 911 | ], |
913 | 912 | "traps": ["stale-console-bundle", "dispatcher-vs-hono-route"], |
914 | 913 | "source": [ |
|
0 commit comments