# CLAUDE.md — `web/src/lib/`

Shared server utilities for the ONE web worker. Thin callers over `schema/roles.tql`.

## Critical rule: ctx.ownerSlug, never body fields

Authorization MUST use only attested sources:

- `locals.slug` — session-attested caller slug
- `locals.workspaceContext?.workspace` — middleware-attested workspace
- `locals.staffRole` — attested staff flag

**Never authorize off `data.actorId`, `body.slug`, or any request-body field.** Body fields are spoofable. This is the IDOR pattern that produced the CRITICAL stream.ts finding.

## Key files

| File | What |
|------|------|
| `authority.ts` | `hasAuthorityOver(env, actorSlug, targetGid)` — thin TypeDB caller; treat null as 503 |
| `analytics/authz.ts` | `authorizeWorkspace(locals, slug, db)` — the tenant-isolation guard; use this on every route that reads a workspace slug from the request |
| `viewer.ts` | Viewer vantage ladder: `platform → agency → client → end_user` |
| `menu.ts` | `getMenu` / `getUserMenu` — workspace nav source of truth (C8: Paths in main, Moderation in bottom) |
| `substrate.ts` | `writeSignal`, `mark`, `pollOutcome`, `isToxic` |
| `receiver-resolvers.ts` | Receiver dispatch barrel (87 lines) — imports from `resolvers/{family}.ts` |
| `resolvers/` | 9 family modules + `_shared.ts` (Env, Resolver types, auth helpers `canReWalk`, `callerControlsWorkspace`) |

## Adding a route that reads a slug param

```ts
const slug = url.searchParams.get('slug') ?? ''
const authz = await authorizeWorkspace(locals, slug, env.DB)
if (!authz.ok) return Response.json({ error: authz.error }, { status: authz.status })
```

## Don't

- Don't call `hasAuthorityOver` in place of `authorizeWorkspace` for route-level guards — `authorizeWorkspace` handles viewer tier, self-check, descendants, and D1 parentage
- Don't add a third auth helper — compose the two that exist
- Don't re-implement the walk — `schema/roles.tql` is the source

## See also

- `text/roles-authority-plan.md` — the walk-up authority model
- `schema/roles.tql` — `can()`, `self-or-ancestors-of`, `delegation`
- `.claude/rules/api.md` — route-level contract
