test(modules): hold every surface list against the surface map

Each family of ids must name a surface that exists (nav hrefs, sub-page
directories, section ids, widget ids, derived ids, Settings slugs,
correlation channels). Sub-pages, trend slots and correlation channels
must follow the owner of the types they plot, joined against the
dashboard's summary owners, and a pinned table covers the owners no
join can derive. The replaced per-surface keys and the redirecting page
guard are searched for in source, and the derived route's gate is
compared with the map entry by entry.

Broken on purpose before committing: dropping the sleep sub-page entry,
the mood trend entry or a nav entry, drifting a derived owner, and
reintroducing a per-destination key each fail by name.
This commit is contained in:
Marc-André Bombeck committed 2026-09-24 09:56:50 +02:00
1 parent 8ae0f75ecd
commit 2594045bef
3 files changed
+326 -7

No files matched your search

@@ -23,13 +23,13 @@ import type { ModuleKey } from "@/lib/modules/registry";
* diverges the initial render and cannot trigger a React #418 mismatch.
*
* Groups the surface map gives no owner (dashboard / insights / vorsorge)
* pass `moduleGate={undefined}` and always render.
* pass `moduleKey={undefined}` and always render.
*/
export function LayoutModuleGate({
moduleGate,
moduleKey,
children,
}: {
moduleGate?: ModuleKey;
moduleKey?: ModuleKey;
children: React.ReactNode;
}) {
const hydrated = useMounted();
@@ -37,9 +37,7 @@ export function LayoutModuleGate({
const router = useRouter();
const disabled =
hydrated &&
moduleGate !== undefined &&
user?.modules?.[moduleGate] === false;
hydrated && moduleKey !== undefined && user?.modules?.[moduleKey] === false;
React.useEffect(() => {
if (disabled) {