Harness 0.1.1-rc.* ships dsh-client-ui-layout, whose client entry provides
the same process-wide "layout" service and registers the same root slot as
the desktop advanced shell. When both entries load, whichever applies second
fails on the duplicate registration and cordis rolls back every effect it
had already installed. When the losing entry is dsh-plugin-desktop, that
rollback removes every stylesheet the entry had installed, leaving pages
such as Settings > Desktop rendered as unstyled markup (#517):
Error: failed to apply loader entry (dsh-plugin-desktop):
service "layout" has been registered at <z5>
Rebased onto current master, where the shell surface covers three modes; the
race is resolved for all of them:
- claimDesktopLayout takes ownership through a guarded provide; when an
external owner wins, it degrades to false instead of throwing. Ownership
is detected through the provide failure itself - reading the store via
reflect.get during application creates a cross-fiber trace dependency
that intermittently deadlocks the page.
- applyAdvancedShell keeps only its mode markers when upstream owns the
service: no theme presenter, no desktop-owned chrome, no root-slot
takeover, so upstream keeps presenting.
- applyExtendedOwnedShell degrades the same way; the independent framed
chrome still layers over whatever presents the root.
- apply() guards against re-application while a previous fiber still lives.
Marker claim/clear live in apply-guard.ts; the markers are claimed
synchronously before any effect walk so a concurrent application observes
them immediately, and any startup failure clears them again inside one try
block - a stale marker would otherwise make the guard swallow every loader
restart of this entry until a full page reload.
- tests/client-layout-service.spec.ts covers ownership, marker rollback, and
per-mode presentation outcomes without importing the full client index:
marker helpers are exercised directly, keeping the module-declaration
surface of the test program identical to master's (#517 follow-up).