Skip to content

EmbeddedTransport ignores recordedSince's cursor and returns the whole journal#178

Merged
EtaCassiopeia merged 1 commit into
masterfrom
fix/rift-175-embedded-cursor
Jul 23, 2026
Merged

EmbeddedTransport ignores recordedSince's cursor and returns the whole journal#178
EtaCassiopeia merged 1 commit into
masterfrom
fix/rift-175-embedded-cursor

Conversation

@EtaCassiopeia

Copy link
Copy Markdown
Collaborator

What

EmbeddedTransport now overrides recordedSince (delegated unconditionally) and the scoped clearRecorded(int, List<MatchClause>), routing both to the lazily-started in-process admin server — the pattern #174/#177 established for events(). The unfiltered clearRecorded(int) deliberately stays on the direct C-ABI.

Two different failures on one transport, from one missing override:

| Call | Before | After |
|---|---|
| Imposter#recordedPage / recordedSince | whole journal, since ignored, empty cursor (silent) | real paged read, real cursor |
| Space#recordedPage / recordedSince | UnsupportedOperationException (loud) | works |
| Imposter#clearRecorded(match) | UnsupportedOperationException | works, genuinely scoped |

Why recordedSince delegates unconditionally but clearRecorded does not

recordedSince has an observable return the C-ABI cannot supply — the cursor. Answering the bare recordedPage() baseline from the C-ABI would report no cursor on the first read and a real one on the second, which is exactly the signal a tail is written to treat as "this transport cannot tail". RecordedCursorIT's "0 is a cursor, not an absence" assertion fails under a conditional split.

clearRecorded is void — no observable difference — so the empty-clause case stays on the C-ABI and never starts a server it does not need. Both arms mean the same thing: an empty clause list makes the admin form emit DELETE .../savedRequests with no query, which is rift_clear_recorded's own behaviour, and one ImposterManager backs both routes.

Gate

Confirmed red first on the EMBEDDED conformance lane — 5 distinct failures, Skipped 0, one per acceptance criterion — by flipping the gates before implementing:

MatchClauseIT is the one that matters most: it proves the whole clause grammar survives the delegation — clause intersection, header wire-encoding with a space and an =, method/path clauses, case-sensitivity, and that a filtered tail's cursor advances past entries the filter rejected. Without it, "embedded can filter" would only have been proven for single-clause cases.

EMBEDDED coverage: 7 → 12 tests. Both lanes 12/12, Skipped 0. Full mvn verify green on JDK 17 and JDK 21; javadoc:javadoc clean.

Stale claims retired

This gap was asserted as fact in nine places. All corrected: docs/events.md (reconcile warning, transport table, start-up-cost line), docs/spaces.md, docs/design/sdk-api.md (§8.1, §8.2, FFI-mapping list), and javadoc on RiftTransport.recordedSince, Imposter, Space, EmbeddedTransport, plus three "like the in-process FFI one" glosses in core tests and a doubly-stale comment in EmbeddedTransportIT.

Known follow-up

engine()/gated() scaffolding is now duplicated across four conformance ITs. Extraction is a separate refactor, filed rather than bundled here.

Closes #175

`EmbeddedTransport` inherited `RiftTransport`'s cursor-less `recordedSince`
default, which discards the `since` argument and answers with the whole
journal when no clause is given, and refuses outright when one is. Because
`SpaceImpl` always prepends a flow-id clause, every Space cursor read threw
and every Imposter cursor read silently over-delivered.

Delegate `recordedSince` and the scoped `clearRecorded` to the same
in-process admin server the transport already starts for `replaceAllImposters`
and `events`; the C-ABI carries neither the cursor nor the clauses. The
unfiltered clear stays on the C-ABI so the common case never starts a server
it does not need.

Closes #175
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

EmbeddedTransport ignores recordedSince's cursor and returns the whole journal

1 participant