SIGN IN SIGN UP

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