diff --git a/docs/subsystems/session-projection.i18n.yaml b/docs/subsystems/session-projection.i18n.yaml index 714becf73d..bb2b34d2c8 100644 --- a/docs/subsystems/session-projection.i18n.yaml +++ b/docs/subsystems/session-projection.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/session-projection.md -session-projection.md: b241c7dbceab23850e9a3755076ee23f83d1ecda -session-projection.zh.md: 53cb8c251f54ee0343eccab57533d9a0d91f993a +session-projection.md: 5943281952def6e86f819e73c7822dc7f6ed4ed6 +session-projection.zh.md: 99009a0472ed40f418527848e91523d0ff0e2303 diff --git a/docs/subsystems/session-projection.md b/docs/subsystems/session-projection.md index b241c7dbce..5943281952 100644 --- a/docs/subsystems/session-projection.md +++ b/docs/subsystems/session-projection.md @@ -52,6 +52,18 @@ interface ProjectionDefinition< * @returns the whole current value for this unit's key. */ view(state: NoInfer): SessionProjectionMap[K] + /** + * Change-detection token for the served view: after a changed `apply`, + * the feed compares this token across the previous and next states with + * `Object.is` and stays quiet when identical, so `view` runs only for an + * actual push. Must be a cheap pure read (a state field, not a + * computation). Omitted, the raw `view` output itself is the token — + * correct for identity-stable views, but then `view` runs per changed + * state, and views building fresh objects per call push on every change. + * @param state - a state on either side of the comparison. + * @returns the token deciding whether the served view changed. + */ + viewKey?(state: NoInfer): unknown } : never /** * Persisted-cache invalidation version: bump whenever the serialized state fields or the @@ -86,9 +98,9 @@ interface ProjectionSnapshot { * Change-feed listener: one unit's served value changed for one session. * `value` is the schema-validated `view` output; `seq` is the unit's * watermark at emission (the seq of the event that caused the change). A - * changed state whose raw `view` output is `Object.is`-identical to the - * unit's previous projection does not fire, so a unit can buffer working - * fields in state behind an identity-stable projection. + * changed state whose `viewKey` token (default: the raw `view` output) is + * `Object.is`-identical to the previous state's does not fire, so a unit can + * buffer working fields in state behind an identity-stable projection. */ type ProjectionChangeListener = ( session: Session, diff --git a/docs/subsystems/session-projection.zh.md b/docs/subsystems/session-projection.zh.md index 53cb8c251f..99009a0472 100644 --- a/docs/subsystems/session-projection.zh.md +++ b/docs/subsystems/session-projection.zh.md @@ -52,6 +52,18 @@ interface ProjectionDefinition< * @returns the whole current value for this unit's key. */ view(state: NoInfer): SessionProjectionMap[K] + /** + * Change-detection token for the served view: after a changed `apply`, + * the feed compares this token across the previous and next states with + * `Object.is` and stays quiet when identical, so `view` runs only for an + * actual push. Must be a cheap pure read (a state field, not a + * computation). Omitted, the raw `view` output itself is the token — + * correct for identity-stable views, but then `view` runs per changed + * state, and views building fresh objects per call push on every change. + * @param state - a state on either side of the comparison. + * @returns the token deciding whether the served view changed. + */ + viewKey?(state: NoInfer): unknown } : never /** * Persisted-cache invalidation version: bump whenever the serialized state fields or the @@ -86,9 +98,9 @@ interface ProjectionSnapshot { * Change-feed listener: one unit's served value changed for one session. * `value` is the schema-validated `view` output; `seq` is the unit's * watermark at emission (the seq of the event that caused the change). A - * changed state whose raw `view` output is `Object.is`-identical to the - * unit's previous projection does not fire, so a unit can buffer working - * fields in state behind an identity-stable projection. + * changed state whose `viewKey` token (default: the raw `view` output) is + * `Object.is`-identical to the previous state's does not fire, so a unit can + * buffer working fields in state behind an identity-stable projection. */ type ProjectionChangeListener = ( session: Session,