# Capability Spec Delta: api-auth-static-principal (api-auth-static-principal) **Package**: `@suaveplan/api-auth-static-principal` **Status**: PROPOSED ## ADDED Requirements ### Requirement: resolveSession returns the configured Principal verbatim The package SHALL return the exact `Principal` from `options.principal` on every `resolveSession()` call, regardless of request shape. The returned Principal MUST deep-equal the configured one (no mutation, no reference-leak across calls). #### Scenario: every request resolves to the configured Principal - **WHEN** the adapter is configured with `principal: { id: "u1", scopes: ["x:write"], tenantId: "acme" }` AND two distinct requests are processed - **THEN** both `resolveSession()` calls return Principals that deep-equal the configured one #### Scenario: returned Principal is not the same reference each call - **WHEN** two `resolveSession()` calls are made - **THEN** the returned objects are deep-equal AND callers cannot mutate one and affect the other (defensive clone OR documented frozen reference — pin one) **Verified by:** `src/factory/create-static-principal-resolver.test.ts::"every request resolves to the configured Principal"` AND `src/factory/create-static-principal-resolver.test.ts::"returned Principal is isolated across calls"` --- ### Requirement: nullForPaths overrides specific routes When `options.nullForPaths` is set, `resolveSession()` SHALL return `null` for requests whose path matches any entry (exact match or glob). Used to test `publicRoutes` behaviour without changing adapter wiring. #### Scenario: matching path returns null - **WHEN** `nullForPaths: ["/webhooks/*"]` is configured AND the request path is `/webhooks/stripe` - **THEN** `resolveSession()` returns `null` #### Scenario: non-matching path returns the Principal - **WHEN** `nullForPaths: ["/webhooks/*"]` is configured AND the request path is `/billing/invoices` - **THEN** `resolveSession()` returns the configured Principal **Verified by:** `src/factory/create-static-principal-resolver.test.ts::"matching path in nullForPaths returns null"` AND `src/factory/create-static-principal-resolver.test.ts::"non-matching path returns the configured Principal"` --- ### Requirement: Conforms to AuthSession contract #### Scenario: conformance suite passes - **WHEN** `runAuthSessionConformance("static-principal-direct", () => createStaticPrincipalResolver({ principal: P }))` runs - **THEN** every invariant passes **Verified by:** `src/factory/create-static-principal-resolver.spec-conformance.test.ts::"static-principal-direct conforms to AuthSession contract"` --- ### Requirement: Options Zod-validated #### Scenario: missing principal.id throws - **WHEN** `createStaticPrincipalResolver({ principal: { scopes: [], claims: {} } as never })` - **THEN** a `SuaveplanError` with code `AUTH_STATIC_PRINCIPAL_INVALID_OPTIONS` is thrown synchronously **Verified by:** `src/options/static-principal-resolver-options.test.ts::"throws when principal.id is missing"` --- ### Requirement: Registered in `api-host/testing` adapter table #### Scenario: createTestHost resolves the kind sentinel - **WHEN** `createTestHost({ adapters: { "auth.session": { kind: "static-principal", principal: P } } })` - **THEN** the resulting `host.auth` is an instance produced by this factory **Verified by:** `tests/integration/integration.test.ts::"createTestHost resolves kind:\"static-principal\" to this adapter"`