# Source Projection Settle Contract

## Scope Guard

This L0 slice adds one generic, opt-in invocation mode that delays the first
execution of a latest-by-source full-record route for a short source-settle
window. Existing Event and WorkItem facts remain durable and ordered; once the
window expires, the source projection executes once over its exact unexecuted
generation. That generation starts after the previous executed Event for the
source route and ends at the selected WorkItem Event's source-lane order key.
Generation membership follows the claim guard's pairwise comparison: fully
upgraded pairs use `(EnqueueOrdinal, Id)`, while a comparison involving an
`EnqueueOrdinal=0` rolling-upgrade row uses `(CreatedDate, DeliverySequence,
Id)`. That pairwise guard is not a sortable total order in a mixed lane, so
Flow input topologically replays its predecessor edges. A true mixed-version
cycle has no contract-consistent sequence; only that cycle is broken by the
immutable ingress key `(CreatedDate, DeliverySequence, Id)`.
`processed` and `dead` always end a generation. An executed `skipped` head also
ends one, identified by its retained claim token and no failure diagnostic;
collapsed skipped siblings remain inputs to the selected generation. This also
keeps trusted-base rows safe: its supersession path retained a failed row's
claim token but also retained `LastError`, so that historical row is not
mistaken for an executed skip. Current supersession explicitly clears its
obsolete lease identity before recording the collapsed skip.
When a dead Event is replayed, its replayed original remains that generation
checkpoint; it is excluded from the replacement Flow payload, while its fresh
replay row begins the next generation.

`DeliveryId` is a transport envelope, not the generation boundary. A provider
may split one logical source burst across deliveries, so a preserve-payload Flow
must receive those ordered raw Events together. It must not receive an earlier
terminal generation or a successor that arrived after the selected head.

Non-goals for this PR are pre-WorkItem row compaction, cross-event-kind
aggregation, HubSpot-specific parser or route metadata, new database columns,
selective multi-field mapping, and Flow audit retention policy.

## Research Evidence

- The current `latest_by_source_full_record_preserve_payload` route coalesces
  only after a worker claims the lane head. Events that arrive after the first
  Flow starts create another execution.
- The measured SC400 run produced 4,000 Event/WorkItem facts, 2,365 Flow
  executions, and 85,527 Flow audit rows.
- `_System_ConnectorEvent.NextAttemptAt` and
  `_System_ConnectorWorkItem.RunAfter` already provide a durable not-before
  primitive. `_System_ConnectorEvent.EnqueueOrdinal` plus the existing `Id`
  tiebreak provide the normal pairwise source-order boundary; a comparison with
  a zero ordinal retains the claim path's historical-order fallback. No schema
  change is required.

## Design Options

1. Add a durable aggregate WorkItem keyed by source and generation. This is the
   strongest long-term compaction model, but it requires new schema, migration,
   event-to-aggregate finalization, and replay contracts.
2. Add route columns for configurable quiet and maximum windows. This keeps
   policy in metadata, but requires coordinated host, schema-authority, and
   installer changes before an L1 route can adopt it.
3. Add one explicit settled invocation mode with a bounded L0 default window,
   backed by the existing not-before fields. This is the selected mergeable
   slice. L1 remains the opt-in authority.

## Selected Slice

- Primary axis: metadata authority for one new generic invocation-mode
  contract.
- Schema store: unchanged.
- Migration/backfill: none.
- Retry and replay semantics: unchanged.
- L1/L2 behavior: excluded from this PR and adopted by dependent PRs.
- Protocol exception: none.

## Invariant Inventory

1. Only the new settled invocation mode receives a future not-before time;
   every existing invocation mode keeps current behavior, and queue due metrics
   exclude settled rows until that time.
2. Event `NextAttemptAt` and WorkItem `RunAfter` carry the same timestamp on
   both bulk and fallback enqueue paths, and a pending event is not directly
   claimable before that timestamp.
3. Same-source siblings on the same route reuse the earliest still-open settle
   timestamp, including across separate deliveries within the window. The
   selected WorkItem restores every raw Event after the prior executed source
   Event through its selected source-order key. Membership follows the claim
   path's pairwise comparison, while mixed-version Flow input topologically
   replays that relation and uses the ingress key only to break a true cycle. A
   later successor
   and an earlier terminal generation are excluded without changing idempotency
   or retry-budget behavior. Collapsed skipped siblings stay in the generation;
   an executed skipped head (retained claim token and no failure diagnostic) is
   a boundary. A replayed
   processed/dead original is still the terminal boundary, but never a
   replacement Flow input.

## Acceptance

- Normalization accepts the new mode and keeps it incompatible with a Flow
  execution filter, like the existing full-record modes.
- Enqueue tests prove delayed Event and WorkItem timestamps for the new mode
  and unchanged timestamps for existing modes, including reuse of an open
  same-source settle timestamp across deliveries.
- Claim tests prove a future pending `NextAttemptAt` is not claimable and a due
  pending row is claimable.
- A cross-delivery projection test proves raw Event restoration is bounded by
  the terminal generation checkpoint and selected source-order key; it excludes
  a later successor.
- A replayed-dead to retry/backoff to later-successor test proves the replayed
  terminal remains the checkpoint, so prior skipped history cannot re-enter a
  later generation.
- Executed-skipped-head and trusted-base failed-skip tests prove the next
  generation excludes a prior executed skipped generation while retaining its
  own collapsed skipped siblings, including rows that predate lease cleanup.
- Mixed-version and equal-ordinal tests prove zero-ordinal membership retains
  historical queue order without admitting later positive-ordinal rows, while
  acyclic mixed lanes preserve every predecessor edge and a cyclic lane has a
  deterministic ingress-key fallback;
  equal positive ordinals use `Id` as the tiebreak.
- Existing coalescing and full repository tests pass.

## Successor Plan

- L1 opts the HubSpot Contact property-change route into the settled mode.
- A separate design slice may later replace one-Event/one-WorkItem execution
  accounting with a durable source-generation aggregate and may group creation
  plus property-change event kinds.
