3.7 KiB
Agent Note: Session projections as a required reader seam
Status: implemented
English | 中文
Problem
An optional projection registry lets a plugin whose host behavior reads projected state activate without that state. Unless the reader rejects the missing registry or key, the host behavior or subagent catalog fields can silently disappear. Batch-only reads also materialize every client view when a consumer needs one host value. Some contributor sites intentionally retain optional ctx.inject registration, so their readers need an explicit missing-state rule.
Decision
This decision builds on the split between host projection state and client views in Session projection state and client views.
Every host reader treats the projection registry and its required key as mandatory state. A plugin either declares sessionProjections as a required injection or resolves the registry and key explicitly and throws on the first dependent access. Official compositions mount the registry before those plugins. ApiProxyService follows the required-injection form; the lower-level createApiProxy factory remains tolerant for isolated tests and diagnostics.
A domain contributor may register its unit through ctx.inject(['sessionProjections'], ...). Optional registration controls the child lifecycle only; it does not authorize a reader to substitute a default when the registry or key is absent.
The registry provides stateOf(session, key) for one typed host state and keeps snapshot() for batch carriers. Client views contain only consumed fields; host readers use stateOf for richer state.
onChanged publishes client-visible value changes only. Unit registration and removal remain effect-scoped registry lifecycle; register() returns the exact Cordis disposer so a composite domain owner can finish cleanup against projected state before removing its unit. Registration changes do not create a second Host event stream or client tombstone protocol. A later authoritative history or list baseline reflects the active key set.
Alternatives considered
- Default missing projected state. This preserves more partial compositions but makes missing host state indistinguishable from a valid empty value. Rejected because official profiles mount the registry and configuration errors must fail explicitly.
- Require every contributor at activation. This makes the key set uniform but unnecessarily couples contribution lifecycle to service activation. Explicit first-access failure preserves the optional registration form without allowing silent degradation.
- Use
snapshot()for every read. This keeps one method but computes unrelated wire views and encourages consumers to depend on batch transport data for host logic. Rejected in favor of typed single-key state reads. - Send full host values to clients. This avoids separate view types but exposes provenance and policy knobs that no client consumes. Rejected in favor of explicit cropped views.
- Broadcast registry additions and removals across Host and mux streams. The streams have no shared ordering, so clients need tombstones, buffered frames, and baseline retries to reconcile them. Rejected because plugin-key churn does not justify a second synchronization protocol.
Consequences
- Missing projection composition fails either during activation or at the first dependent host access; it never degrades to a default value.
- Host consumers avoid repeated whole-registry snapshots and log scans.
- Wire payloads exclude host-only fields and per-key watermark wrappers; ordinary baselines communicate the active key set.