fix(objectql): apply D7 setup-nav contributions in the protocol serving path (empty Setup menu)#1457
Merged
Conversation
Propose retiring the hand-written namespace-prefix authoring rule (only objects are protected today; ~23 other metadata kinds collide silently, e.g. connectors last-wins-overwrite) in favor of: - namespace as an identity dimension (short authored names; identity = (namespace, type, name)) - physical table names derived at the storage boundary, invisible to authors/AI (inverting the existing StorageNameMapping pass-through) - namespace as an addressing segment at transport surfaces (data API, metadata API, generated GraphQL/OData/SDK/MCP) - app sandboxing: no cross-app references (security boundary); only app -> kernel references are legal - a single unified reserved kernel namespace (sys) whose contract is unified but whose object ownership is distributed across first-party capability plugins (single-owner-per-object), decomposing the platform-objects monolith Grounded in a codebase scan (current-state findings + kernel cross-reference graph) and mainstream platform practice (Salesforce 2GP / ServiceNow scoped apps / Dataverse). Includes a phased, non-breaking migration plan. https://claude.ai/code/session_01Tv6F1Ub6bhCedrx3r8sZM4
ADR-0004 is "Cloud Control Plane", not the object-namespace-prefix rule (which lives only in manifest.zod.ts / stack.zod.ts, with no standalone ADR). Replace the broken ./0004-object-namespace-prefix.md link with a Supersedes note pointing at the actual source files. https://claude.ai/code/session_01Tv6F1Ub6bhCedrx3r8sZM4
Rework the migration section around three compatibility mechanisms so existing templates are never broken in a flag-day cutover: - per-package `namingMode: 'literal' | 'short'` manifest flag (old and new packages coexist in one instance; migration is opt-in per package) - idempotent, namespace-aware `resolveTableName` (dual-read) so adding derivation does not turn `crm_account` into `crm_crm_account` - sealed artifacts are never force-republished (codemod rewrites source templates only) Each phase (P0 foundations → P5 remove-legacy) now has an explicit exit gate; the only breaking step (P4) is per-package opt-in and driven by an `os migrate namespace` codemod. Kernel refactor (P2) is decoupled and template-transparent. https://claude.ai/code/session_01Tv6F1Ub6bhCedrx3r8sZM4
…reference it Carve the kernel-decomposition concern out of ADR-0028 into its own ADR: first-party capabilities become plugins that own their sys_* objects + behavior (correcting the platform-objects monolith where plugins declare namespace:'sys' but the objects are defined centrally). ADR-0029: - small core (identity/org hub + metadata) vs capability plugins (audit/jobs/email/approvals/sharing/ai/webhooks) that each own their objects - shared reserved `sys` namespace, single-owner-PER-OBJECT (not per-namespace, not a monolith owner) - hub + dependencies/loadOrder instead of centralization - decompose platform-objects behind a re-export facade - template-transparent, independently shippable, sequenced BEFORE the 0028 naming flip; phased K0-K4 with exit gates ADR-0028: Phase 2 now delegates to ADR-0029; header gains it as a prerequisite; D5 points to ADR-0029 as the authoritative source for the ownership mechanics (0028 keeps only the naming/contract decision). https://claude.ai/code/session_01Tv6F1Ub6bhCedrx3r8sZM4
…etup app (D7) Decomposing platform-objects breaks the premise that lets the `setup` admin app be a static monolith (it hard-references every sys_* object; its own comment notes it was made static *because* the objects were centralized, and the runtime-assembling plugin-setup was deleted). manifest.contributes.menus exists but is consumed nowhere, and there is no app-extension analog to objectExtensions. Add D7: setup becomes a base-owned "shell + group slots"; each capability plugin contributes its nav entries via a declarative navigation contribution (the UI analog of objectExtensions), merged by group + priority, each entry gated by the existing requiresObject / requiredPermissions nav fields (which doubles as the disable mechanism). Wire it through the migration plan (K1 builds the shell + mechanism; K2 moves each domain's nav entries out as contributions) and record the schema choice as an open question. https://claude.ai/code/session_01Tv6F1Ub6bhCedrx3r8sZM4
…ta-naming-conflicts-nrnaT # Conflicts: # docs/adr/0029-kernel-object-ownership-and-platform-objects-decomposition.md
The Setup app is a shell of empty group anchors (ADR-0029 D7); menu
entries are injected as navigation contributions and merged lazily on
read. `SchemaRegistry.getApp` / `getAllApps` did the merge, but the REST
app endpoints read through `protocol.getMetaItems` / `getMetaItem`, which
returned the raw shell — so every Setup menu group rendered empty.
Apply the contribution merge in both protocol read paths (list + single)
for the `app`/`apps` types, mirroring `getApp`/`getAllApps`. The stored
app is never mutated (structuredClone), so reads stay idempotent.
`SchemaRegistry.applyNavContributions` is promoted from private to public
so the protocol can reach the same merge logic.
Adds regression tests covering both `getMetaItems({type:'app'})` and
`getMetaItem({type:'app'})`.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The Setup menu is completely empty. After ADR-0029 D7 reduced
setup.app.tsto a shell of empty group anchors and moved menu entries into navigation contributions (merged lazily on read), the contributions never reached the rendered app.Root cause
The merge logic (
applyNavContributions) lived only inSchemaRegistry.getApp/getAllApps. But the REST app endpoints don't read through those helpers — they read throughprotocol.getMetaItems/getMetaItem, which return raw registry items vialistItems/getItem. So the served Setup app was the bare shell → every group rendered empty.Fix
Apply the contribution merge in both protocol read paths for the
app/appstypes, mirroringgetApp/getAllApps:getMetaItems(list) — maps each served app throughregistry.applyNavContributions.getMetaItem(single-app fetch,GET /meta/app/<name>) — same, after the item is resolved.The stored app is never mutated (
structuredClone), so reads stay idempotent.SchemaRegistry.applyNavContributionsis promotedprivate → publicso the protocol can reach the same logic.Tests
Adds a regression
describeblock (app navigation contributions (ADR-0029 D7)) inprotocol-meta.test.tscovering bothgetMetaItems({type:'app'})andgetMetaItem({type:'app'}), including the idempotency assertion that the stored shell is not mutated. Fullprotocol-metasuite green (64 passed).https://claude.ai/code/session_01Tv6F1Ub6bhCedrx3r8sZM4
Generated by Claude Code