OSS-first docs
These docs teach the open system first: contracts, generated surfaces, runtimes, governance, and incremental adoption. Studio shows up as the operating layer on top, not as the source of truth.
In-memory registry for navigation surface items with persona- and group-aware queries and capability binding validation.
Overview
`NavRegistry` mirrors the `CapabilityRegistry` API and provides:
•
**Registration**: `register(spec)` with duplicate + capability validation
•
**Queries**: `get(key, version?)`, `list()`, `indexByPersona()`, `indexByGroup()`
•
**Role-aware resolution**: `resolveForRoleMorph(roleMorph, preferences)`
Registration Flow
1.
Create `NavSurfaceItemSpec` entries using `defineNavSurfaceItem()`
2.
Optionally pass a `CapabilityRegistry` to the `NavRegistry` constructor
3.
Call `register(spec)` for each entry
•
Throws if `meta.key + version` is duplicate
•
Throws if capability is not registered with `surface: 'navigation'` (when `CapabilityRegistry` is provided)
1.
Use queries to retrieve filtered nav items
resolveForRoleMorph Semantics
`resolveForRoleMorph(roleMorph, preferences)` filters the registry to:
1.
**Persona intersection**: Keep entries where `personaVisibility` overlaps with `roleMorph.personas`
2.
**Group hiding**: Remove entries in `preferences.hiddenGroups`
3.
**De-duplication**: By `meta.key` (latest version wins)
Returns a flat array of visible `NavSurfaceItemSpec` in insertion order.
CapabilityRegistry Binding Validation
If a `CapabilityRegistry` is provided at construction, `register()` validates that:
•
`spec.capability.key` is registered in capabilities with `surface: 'navigation'`
•
If not, throws: `"Nav item {id} references capability {key} which is not registered with surface 'navigation'"`
This ensures all nav items map to real capabilities at build time.
Index Caching
Both persona and group indexes are lazy-built and cached; they invalidate on `register()`.
Example Usage
const registry = new NavRegistry({ capabilities: capabilityRegistry });
registry.register(inboxNavSpec);
registry.register(workflowNavSpec);
registry.register(analyticsNavSpec);
// Get entries visible to a persona
const founderNav = registry.indexByPersona('founder_approver');
// Resolve for a role-morph with hidden groups
const visibleNav = registry.resolveForRoleMorph(
{ personas: ['founder_approver', 'operations_manager'] },
{ hiddenGroups: ['experimental'] }
);
// Build a NavGraphSpec from the registry
const graph = defineNavGraph({
meta: { /* ... */ },
nodes: registry.list(),
edges: [ /* hand-curated */ ],
});