diff --git a/.changeset/appcontent-route-test-headers-3749.md b/.changeset/appcontent-route-test-headers-3749.md
new file mode 100644
index 000000000..a799d3beb
--- /dev/null
+++ b/.changeset/appcontent-route-test-headers-3749.md
@@ -0,0 +1,30 @@
+---
+---
+
+Comment-only change, no behaviour and no authoring-surface change (objectui#3749).
+
+Three docblock passages in the zero-app console routing tests enumerated
+`sys-datasources` / `sys-objects` in the present tense as the producers of
+`…/component/metadata/resource?type=datasource` and `…/system/metadata/object`.
+Both entries were re-pointed at the metadata-admin engine's canonical
+`…/metadata/:type` routes — `sys-datasources` by objectui#3660,
+`sys-objects` (and the home QuickActions "Manage Objects" card) by
+objectui#3739 — so the narration described a producer surface that no longer
+exists, while the assertions underneath it stayed correct and green.
+
+Rewritten as "history + current state" per objectui#3666: what was true at
+objectui#3610, then what is true now, with the current-state half stating
+positively what the two spellings are today (arrivals for bookmarks, external
+links and the host's own alias route) rather than denying where they used to
+point. The two `it` titles move off the producer names onto what they actually
+measure — each alias still resolving out of the zero-app branch in exactly one
+hop, named by its rewriter (`shell alias` / `host alias`).
+
+No package is declared because nothing published changed: `AppContent.tsx` is a
+JSX-comment edit with both `LegacyMetadataRedirect` route declarations and every
+other line of code untouched, and the two test files keep their assertions and
+case count byte for byte (43 passed before, 43 passed after). The reason this is
+worth a commit at all is that the same comment family has gone stale once before
+at a measured cost — objectui#3661 / #3669, where a transcription that had
+drifted left two cases silently measuring a redirect chain production had
+stopped emitting.
diff --git a/packages/app-shell/src/console/AppContent.tsx b/packages/app-shell/src/console/AppContent.tsx
index 8a958ada0..ef1bdaedb 100644
--- a/packages/app-shell/src/console/AppContent.tsx
+++ b/packages/app-shell/src/console/AppContent.tsx
@@ -655,9 +655,12 @@ export function AppContent({ extraRoutes, extraRoutesNoApp }: AppContentProps =
every one of them rendered a blank screen. #3610 mirrored the
routes rather than re-point that navigation, because inventing a
zero-app-only spelling would have given the alias a second
- canonical destination. #3660 re-pointed it anyway — at the shared
- `metadata/:type` routes above, so no second spelling was created —
- which leaves these two serving bookmarks and external links, the
+ canonical destination. #3660 re-pointed `sys-datasources` anyway —
+ at the shared `metadata/:type` routes above, so no second spelling
+ was created — and #3739 did the same for `sys-objects` and the
+ home "Manage Objects" card, whose chain had already left these two
+ routes at #3658, when the host stopped rewriting onto the alias.
+ What is left for these two is bookmarks and external links: the
arrivals that can never be re-pointed. */}
} />
} />
diff --git a/packages/app-shell/src/console/__tests__/AppContent.noAppComponentRoutes.test.tsx b/packages/app-shell/src/console/__tests__/AppContent.noAppComponentRoutes.test.tsx
index f8e0eebf7..f722a90db 100644
--- a/packages/app-shell/src/console/__tests__/AppContent.noAppComponentRoutes.test.tsx
+++ b/packages/app-shell/src/console/__tests__/AppContent.noAppComponentRoutes.test.tsx
@@ -4,20 +4,38 @@
* Zero-app console: the `component/metadata/*` destinations must resolve, and
* anything unmatched must say so (objectui#3610).
*
- * ## The defect
+ * ## The defect, as it stood at objectui#3610
*
- * With zero published apps, the system fallback sidebar offers two entries that
- * both land inside `AppContent`'s no-`activeApp` branch:
+ * With zero published apps, the system fallback sidebar offered two entries
+ * that both landed inside `AppContent`'s no-`activeApp` branch:
*
* sys-datasources -> /apps/setup/component/metadata/resource?type=datasource
* sys-objects -> /apps/setup/system/metadata/object
*
- * `isMetadataRoute` is a substring test (`pathname.includes('/metadata')`), so
- * both URLs pass the "no apps configured" guard and enter the no-`activeApp`
- * ``. That branch declared `create-app`, `system/marketplace*` and
- * `metadata*` only — no `component/…` at all — and, unlike the with-`activeApp`
- * branch, no trailing `path="*"`. A `` with no match renders `null`:
- * a fully blank screen, no 404, no error, no empty state.
+ * `isMetadataRoute` was a substring test (`pathname.includes('/metadata')`) at
+ * the time, so both URLs passed the "no apps configured" guard and entered the
+ * no-`activeApp` ``. That branch declared `create-app`,
+ * `system/marketplace*` and `metadata*` only — no `component/…` at all — and,
+ * unlike the with-`activeApp` branch, no trailing `path="*"`. A `` with
+ * no match renders `null`: a fully blank screen, no 404, no error, no empty
+ * state.
+ *
+ * ## What those two URLs are NOW (objectui#3660, #3739)
+ *
+ * Neither is anybody's navigation target any more. Both sidebar entries name
+ * the metadata-admin engine's canonical routes directly — `sys-datasources` ->
+ * `/apps/setup/metadata/datasource` (#3660), `sys-objects` ->
+ * `/apps/setup/metadata/object` (#3739) — as does the home QuickActions
+ * "Manage Objects" card. The two spellings above are ARRIVALS: bookmarks,
+ * external links, and, for the `system/metadata/:type` one, the host
+ * fragment's own alias route, which stays declared for exactly those.
+ *
+ * That is why this file still measures them, and why the `it` titles below name
+ * the alias URL and its rewriter rather than the sidebar entry that used to
+ * emit it: what is under test is that each alias still RESOLVES out of the
+ * zero-app branch, and still costs exactly one hop. `isMetadataRoute` is a
+ * segment test since #3638 (`pathSegments.includes('metadata')`), under which
+ * every URL here stays true.
*
* ## Which spelling is canonical — MEASURED, and the opposite of the guess
*
@@ -49,17 +67,18 @@
* `apps/console/src/AppContent.tsx` (`systemRoutes` + its `MetadataRedirect`).
* app-shell cannot import from `apps/` — a different Vitest project — so the
* rewrite is copied verbatim, including its `prefix` regex, and this comment is
- * the pointer back to the original. It is the `sys-objects` leg of the chain:
- * without it that URL's route into this branch is invisible here.
+ * the pointer back to the original. It is the `system/metadata/:type` leg of
+ * the chain: without it that URL's route into this branch is invisible here.
*
* ## Why the chain, not just the endpoint (objectui#3661)
*
* A transcription can go stale, and this one did. objectui#3658 re-pointed the
* host straight at the canonical routes; the copy here kept emitting the
- * deprecated alias, so the `sys-objects` case went on measuring a two-hop chain
- * that production had stopped producing. Nothing went red — the assertions
- * pinned only the final pathname, and that is identical either way. Green, for
- * a reason that no longer had anything to do with the code under test.
+ * deprecated alias, so the `system/metadata/object` case went on measuring a
+ * two-hop chain that production had stopped producing. Nothing went red — the
+ * assertions pinned only the final pathname, and that is identical either way.
+ * Green, for a reason that no longer had anything to do with the code under
+ * test.
*
* So `renderConsoleAt` now returns every location the router settles on, and
* all four redirect cases assert that list exactly. A stub that drifts back
@@ -265,15 +284,18 @@ describe('AppContent — zero-app component/metadata destinations (objectui#3610
vi.clearAllMocks();
});
- it('sys-datasources: /apps/setup/component/metadata/resource?type=datasource renders the resource page', async () => {
+ it('shell alias: /apps/setup/component/metadata/resource?type=datasource resolves in the zero-app branch and hops ONCE to the canonical page', async () => {
// The white screen this issue is about. The URL passes `isMetadataRoute`
- // (substring `/metadata`) and so enters the no-`activeApp` branch, which
- // used to declare nothing matching `component/…` and had no catch-all.
+ // (a `metadata` path segment; a substring test until #3638) and so enters
+ // the no-`activeApp` branch, which used to declare nothing matching
+ // `component/…` and had no catch-all.
//
// Unlike the two host-rewrite cases below, the alias here is the ENTRY, not
- // an intermediate stop — the zero-app fallback sidebar's `sys-datasources`
- // item still points straight at this spelling, so this chain is one this
- // deployment really produces.
+ // an intermediate stop: nothing rewrites it on the way in, so this branch's
+ // own route table is the whole story. The `sys-datasources` sidebar item is
+ // what emitted it at #3610; since #3660 that item names the canonical route
+ // and this spelling arrives from bookmarks and external links instead —
+ // which is precisely why the redirect has to keep working.
const chain = renderConsoleAt('/apps/setup/component/metadata/resource?type=datasource');
const page = await screen.findByTestId('metadata-resource-list-page');
@@ -294,17 +316,20 @@ describe('AppContent — zero-app component/metadata destinations (objectui#3610
expect(screen.queryByTestId('root-landing')).not.toBeInTheDocument();
});
- it('sys-objects: /apps/setup/system/metadata/object reaches this branch\'s metadata/:type in ONE hop', async () => {
+ it('host alias: /apps/setup/system/metadata/object reaches this branch\'s metadata/:type in ONE hop', async () => {
// The non-obvious half, pinned on its own because it would regress
// silently: this URL is rewritten by the HOST (`MetadataRedirect`) onto the
// canonical route, which the zero-app branch declares itself. Two route
// tables, one redirect, zero apps.
//
// It used to be two redirects — the host aimed at the legacy alias and the
- // shell forwarded that on. objectui#3658 removed the middle stop; this case
- // now measures what production actually does, and objectui#3661 is what it
- // cost to notice that it had stopped doing so (the endpoint never moved, so
- // nothing failed).
+ // shell forwarded that on. objectui#3658 removed the middle stop, and
+ // objectui#3661 is what it cost to notice that the transcribed stub had not
+ // followed (the endpoint never moved, so nothing failed). Since #3739 no
+ // click in this repo emits this URL either — `sys-objects` and the home
+ // "Manage Objects" card name the canonical route — so what is pinned here
+ // is the arrival path the host still declares for bookmarks and external
+ // links.
const chain = renderConsoleAt('/apps/setup/system/metadata/object');
const page = await screen.findByTestId('metadata-resource-list-page');
diff --git a/packages/app-shell/src/console/__tests__/AppContent.pseudoRouteSegments.test.tsx b/packages/app-shell/src/console/__tests__/AppContent.pseudoRouteSegments.test.tsx
index 45072c277..5df9143fc 100644
--- a/packages/app-shell/src/console/__tests__/AppContent.pseudoRouteSegments.test.tsx
+++ b/packages/app-shell/src/console/__tests__/AppContent.pseudoRouteSegments.test.tsx
@@ -38,14 +38,27 @@
* metadata,metadata/:type,metadata/:type/:name}`
* (`developer/*` and `docs/*` are in the same
* fragment but flip NO flag — pinned below)
- * navigation AppSidebar / UnifiedSidebar `/apps/setup/system{,/apps,/marketplace,
- * /metadata/object,/users,/organizations,
- * /roles,/settings}`
- * `/apps/setup/component/metadata/resource?type=`
- * QuickActions / HomePage / `/apps/setup/system/{metadata/object,marketplace,
- * InboxPopover approvals}`
+ * navigation AppSidebar / UnifiedSidebar `/apps/setup/system{,/apps,/marketplace,/users,
+ * /organizations,/roles,/settings}`
+ * `/apps/setup/metadata/{object,datasource}`
+ * QuickActions `/apps/setup/metadata/object`, `/apps/setup/system`
+ * HomePage / InboxPopover `/apps/setup/system/{marketplace,approvals}`
* SystemRedirect (#3637) bare `/system` -> `/apps/setup/system`
*
+ * The metadata-admin entries moved after #3638 landed: the sidebars'
+ * `sys-objects` / `sys-datasources` items and the QuickActions "Manage Objects"
+ * card once spelled `…/system/metadata/object` and
+ * `…/component/metadata/resource?type=datasource`; #3739 and #3660 re-pointed
+ * all three at the engine's canonical `…/metadata/:type` routes. Those two
+ * older spellings are still in this input surface, as ARRIVALS rather than
+ * emissions — declared in the two rows above
+ * (`component/metadata/{directory,resource/*}` in the shell,
+ * `system/metadata{,/:type}` in the host) and reached from bookmarks and
+ * external links. `metadata` is a whole path segment either way, so the claim
+ * below is indifferent to the move; the `navigation` row is re-read here
+ * because a producer list naming URLs nothing emits any more is the stale
+ * pointer objectui#3661 was paid for.
+ *
* In EVERY one of them `system` / `metadata` is a whole path segment, so a
* segment test keeps all of them true. That is the claim this file's first two
* describes exist to falsify.