Files
hapi/shared/fixtures/pagination/fetch-older-before-cursor.json
T
weishu e1bfdd6265 feat(fixtures): SSE patch + pagination scenario fixtures (K7)
Two new golden-fixture suites, expectations machine-generated from the web
implementation (same source-of-truth principle as the chat suite):

- shared/fixtures/sse/ (12 cases): session-updated versioned-patch
  application via applySessionDetailPatch — strict version gates for
  metadata/agentState/todos/teamState, out-of-order arrival, teamState:null
  clear, max-monotonic updatedAt, flat last-write-wins fields, sub-minute
  activeAt keep-alive drop, scratchlistUpdatedAt trigger, and the pinned
  actual behavior that activeTurnStartedAt is NOT applied by the patch path.
  Inputs are stored schema-normalized and validated against SessionSchema /
  strict SessionPatchSchema at generation time; per-patch applied/unchanged
  verdicts are part of the contract.

- shared/fixtures/pagination/ (11 cases): op scripts driving the real
  message-window store with a scripted ApiClient — latest page + SSE ingest,
  before-cursor older pages, epoch-mismatch reset (window discard + recorded
  internal latest request), reset:true replace preserving optimistic rows,
  localId echo reconciliation, messages-consumed invokedAt stamping (no
  cursor advance), message-cancelled removal, cancel-too-late invoked-row
  ingest, hidden-row cursor advance, 400-row trim preserving queued rows,
  and queued-state gap recovery. Documents pin the exact requests the store
  issued, older-load outcomes, reconcile candidates, and a minimal window
  projection (ids/order, queued/optimistic flags, hasMore, epoch, viewMode,
  compound cursors).

Generator: web/scripts/fixtures/{sse,pagination}/ extend the K5 framework
(canonical serialization reused; suites pruned of stale files). Web
self-conformance tests replay every fixture against the real implementation
in bun run test:web. README documents schemas, projections, replay
contracts, and native consumption for both suites.

No time injection needed: the store's only Date.now() reads gate
notification throttling, which never reaches persisted or projected state.
2026-08-17 12:06:57 +08:00

136 lines
4.4 KiB
JSON

{
"description": "Older pagination sends the compound (beforeAt, beforeSeq) pair from the current older cursor, prepends the rows, and adopts the response page.nextBefore as the new older cursor and page.hasMore as the exhaustion flag.",
"expectedState": {
"epoch": 4,
"hasMore": false,
"messages": [
{
"createdAt": 9000,
"id": "a-9",
"invokedAt": 9000,
"localId": null,
"optimistic": false,
"queued": false,
"seq": 9
},
{
"createdAt": 10000,
"id": "a-10",
"invokedAt": 10000,
"localId": null,
"optimistic": false,
"queued": false,
"seq": 10
}
],
"newestCursor": {
"at": 10000,
"seq": 10
},
"olderCursor": {
"at": 9000,
"seq": 9
},
"viewMode": "tail"
},
"fixtureVersion": 1,
"name": "fetch-older-before-cursor",
"ops": [
{
"expectedRequests": [
{
"limit": 200
}
],
"op": "sync-tail",
"responses": [
{
"messages": [
{
"content": {
"content": {
"data": {
"message": "a-10",
"type": "message"
},
"type": "codex"
},
"role": "agent"
},
"createdAt": 10000,
"id": "a-10",
"invokedAt": 10000,
"localId": null,
"seq": 10
}
],
"page": {
"direction": "latest",
"epoch": 4,
"hasMore": true,
"limit": 200,
"nextAfterAt": null,
"nextAfterSeq": null,
"nextBeforeAt": 10000,
"nextBeforeSeq": 10,
"reset": false,
"snapshotHeadAt": 10000,
"snapshotHeadSeq": 10
}
}
]
},
{
"expectedOutcome": {
"addedRenderableCount": 1,
"hasMore": false,
"kind": "applied"
},
"expectedRequests": [
{
"beforeAt": 10000,
"beforeSeq": 10,
"limit": 200
}
],
"op": "fetch-older",
"responses": [
{
"messages": [
{
"content": {
"content": {
"data": {
"message": "a-9",
"type": "message"
},
"type": "codex"
},
"role": "agent"
},
"createdAt": 9000,
"id": "a-9",
"invokedAt": 9000,
"localId": null,
"seq": 9
}
],
"page": {
"direction": "before",
"epoch": 4,
"hasMore": false,
"limit": 200,
"nextAfterAt": null,
"nextAfterSeq": null,
"nextBeforeAt": 9000,
"nextBeforeSeq": 9,
"reset": false,
"snapshotHeadAt": null,
"snapshotHeadSeq": null
}
}
]
}
]
}