feat(verify): the readiness observer names its tenant, and Summarisable is inlined (#125)
## Summary
Two changes to `Verify`, one per commit.
**The readiness observer names the tenant it fired for.** Readiness is
stored per owner and domain,
but `Verify.ReadinessChanged` carried only `domain`, `readiness`, and
`cause`. An observer provided
with `Layer.succeed(Verify.Observer, ...)` over `DomainKit.layer` is
bound to the layer, not to one
request, so a host serving several tenants could not tell whose
readiness had been written when the
same domain name is attached in two of them. The event now carries
`ownerId`, read from the
`Principal` the write ran as, for both causes. Only the owner is
carried: readiness is scoped by
owner, not by actor, and the observer is a projection seam rather than
an audit trail.
**`Verify.Summarisable` is inlined.** It was a public interface that
existed only to type
`summary`'s parameter so core `Readiness` and the wire shape both fit.
Its shape is now written
structurally at the signature. `summary`'s behaviour and tests are
unchanged.
## API
```ts
interface ReadinessChanged {
/** The tenant the row was written under, from the `Principal` the write ran as. */
readonly ownerId: string
readonly domain: string
readonly readiness: Readiness
readonly cause: Cause
}
const summary: (
readiness: {
readonly requirements: ReadonlyArray<{ readonly status: Storage.RequirementStatus }>
} | null,
) => Summary
```
Keying a host projection by owner and domain, from
`examples/core/host-observation.ts`:
```ts
const observer = Layer.succeed(Verify.Observer, {
readinessChanged: ({ cause, domain, ownerId, readiness }) =>
Effect.gen(function* () {
if (readiness.overall === "ready") return yield* markReady({ ownerId, domain })
// A pending domain carries its own schedule, so the host sleeps on it rather than polling.
if (readiness.nextCheckAt !== null && cause === "observe") {
yield* wake({
ownerId,
domain,
at: new Date(DateTime.toEpochMillis(readiness.nextCheckAt)),
})
}
}),
})
```
## Surfaces
Core API, snippet gallery (`examples/core/host-observation.ts`),
documentation
(`core/verification`, `reference/core`), and release notes
(`.tegami/observer-owner.md`, patch on
`domainkit`). No React, registry, provider, or transport surface is
touched: the observer is a
server seam and `summary`'s call signature is unchanged, so
`@domainkit/react`'s
`Verify.summary` re-export still compiles.
## Verification
- `bun run release:check`
- `bun run typecheck:examples`
- `apps/docs`: `reference:check`, `typecheck`, `test`, `build`, `blume
validate --strict`,
`audit --strict`
- `git diff --check` S
Saatvik Arya committed
3bb0e0aa88fa21ab0a4d56386b315bb0d1b5d80d
Parent: b974123
Committed by GitHub <noreply@github.com>
on 9/19/2026, 4:57:14 AM