# Resource Governance Runtime + CRM Detail Pages + Service-Context Rename

## Why this note exists

The 2026-05-09 release train extends the clients-domain ship with three additional bodies of work that affect template-derived projects:

1. **Resource Governance runtime cutover.** The shared resource-governance validator now defaults to **strict** mode. The OM Resources/Systems descriptor catalog is the source of truth for resource identity. Operations bundles must bind workflows, agents, and integrations to descriptors via `defineResource(s)` + descriptor binding helpers; raw `resourceId` literals in `DeploymentSpec` no longer pass strict validation.
2. **CRM detail-page surface expansion.** `@elevasis/ui` now publishes `ContactDetailPage` (new) and `CompanyDetailPage` (now exported from `sdk-barrel`) under `@elevasis/ui/features/crm`. The lead-gen flow no longer renders detail modals on row click — both pages are reached via TanStack Router routes (`/crm/contacts/$contactId`, `/crm/companies/$companyId`). The legacy `CompanyDetailModal` and `ContactDetailModal` exports were removed from `@elevasis/ui/features/lead-gen/shared`.
3. **`ElevasisServiceContext` field rename.** `useElevasisServices().organizationId` is renamed to `useElevasisServices().workOSOrganizationId` to make the WorkOS-vs-Supabase distinction loud at call sites. The old `organizationId` field is preserved as a back-compat alias on both `ElevasisServiceContextValue` and `ElevasisServiceProviderProps` for one release cycle, so existing template consumers continue to work without immediate migration.

Companion items already covered elsewhere:

- Scaffold/agent guidance for descriptor-first authoring → see `2026-05-08-resource-governance-scaffold-guidance.md`.
- Clients domain (new sidebar pillar, write operations, project/client linkage) → see `2026-05-09-clients-domain.md`.

## Applies to

Any template-derived project (e.g. `nirvana-marketing`, `ZentaraHQ`) that:

- Deploys workflows, agents, or integrations through `operations/src/index.ts` (resource-governance validator).
- Renders contacts/companies in any feature surface, including custom CRM views (CRM detail pages + modal removal).
- Uses `useElevasisServices()` from `@elevasis/ui` in custom hooks, components, or test fixtures (service-context rename).

## Required actions

### 1. Resource Governance — descriptor-backed deployment

- Confirm `core/config/organization-model.ts` declares your tenant's resources in the id-keyed `organizationModel.resources` map (single-author resource IDs).
- In `operations/src/index.ts`, bind your workflow/agent/integration definitions to those descriptors via the helpers exported from `@elevasis/sdk` instead of authoring raw `resourceId` strings inline in `DeploymentSpec`.
- Run `pnpm -C operations check`. The default validator mode is now strict; missing descriptors, raw-ID authoring, runtime/OM type mismatches, and missing Systems will fail the build. Set `ELEVASIS_RESOURCE_VALIDATOR=warn-only` only as a temporary emergency escape hatch — do not let normal CI silently depend on it.
- New SDK CLI commands are available: `elevasis-sdk agent:list`, `elevasis-sdk agent:get \<id>`, `elevasis-sdk session:list`, `elevasis-sdk session:get \<id>`, `elevasis-sdk session:end \<id>`. Existing `resources` / `describe` / `exec` / `executions` / `execution` are unchanged.

### 2. CRM detail pages

- If your project imports `CompanyDetailModal` or `ContactDetailModal` from `@elevasis/ui/features/lead-gen/shared`, those exports were removed. Replace modal-on-row-click patterns with `useNavigate` to `/crm/contacts/$contactId` or `/crm/companies/$companyId`.
- If you need detail-page UI in custom routes, import `ContactDetailPage` and `CompanyDetailPage` from `@elevasis/ui/features/crm`. Both are part of the published `sdk-barrel` and accept `contactId` / `companyId` props.
- The `extend-lead-gen.md` recipe in `node_modules/@elevasis/sdk/reference/scaffold/recipes/` was updated — it no longer documents the modal helpers.

### 3. `workOSOrganizationId` field rename

- New idiomatic destructure: `const { apiRequest, workOSOrganizationId, isReady } = useElevasisServices()`.
- The old `organizationId` field still resolves correctly through the back-compat alias, so existing template code compiles and runs without changes. New code in this project should use `workOSOrganizationId`.
- If your project uses `<ElevasisServiceProvider organizationId={...}>`, that prop also accepts both names. Provider's resolver is `workOSOrganizationId ?? organizationId ?? null` — passing both names is supported but unnecessary.
- For test fixtures that mock `useElevasisServices` via `vi.mock`, return `workOSOrganizationId` rather than `organizationId` when authoring NEW mocks; existing mocks will continue to work via the alias but should be migrated opportunistically. The runtime trap is: `vi.mock(...)` is untyped — TypeScript will not catch a mock that returns the deprecated key, but the resolver bypass means downstream `services.workOSOrganizationId` reads `undefined`.

## Verification

After reconciling local project guidance and writing any descriptor / service-context updates:

```bash
pnpm -C operations check
pnpm -C operations check-types
pnpm -C ui check-types
pnpm -C ui test
```

If your project deploys to production and you author runtime resources directly:

```bash
pnpm -C operations exec elevasis-sdk deploy
```

Expect strict-mode validator output. Investigate any "OM resource missing for code resource" or "raw resourceId authoring detected" errors as descriptor-binding work, not as test bypass.

## Not handled by /git-sync

- `/git-sync` pulls the new `@elevasis/sdk`, `@elevasis/ui`, and `@elevasis/core` versions and template-owned files, but it does **not** rewrite existing project-owned `operations/src/**` workflow/agent/integration files to use descriptor-backed binding. Maintainers must migrate raw `resourceId` literals to descriptor lookups intentionally.
- `/git-sync` does **not** rewrite custom UI routes that import `CompanyDetailModal` / `ContactDetailModal` from `@elevasis/ui/features/lead-gen/shared`. Replace those imports with `useNavigate` to detail-page routes manually.
- `/git-sync` does **not** rename `useElevasisServices().organizationId` reads in project-owned code. The back-compat alias keeps existing code working; proactive renaming is a manual cleanup.
