docs(persistence): teach the segment-wildcard grammar in the README - #241
Merged
Conversation
`PersistenceBackend::query` moved from a prefix glob to the MQTT-style grammar subscriptions use, but the README still keyed every example with `::` and queried it with `::*`. A wildcard is a whole dot-separated segment, so `accuracy::vienna` is a single segment no pattern can partition and `accuracy::*` is a literal key that matches nothing — a reader copying the examples got zero rows and no error. Migrate the example keys to dot-separated form, then fix the patterns over them, and state the grammar once where the reader has to choose: `*` for a known depth, `#` where it varies. `query_raw` takes `#` because it feeds the AimX `record.query` handler, whose callers key at their own depth. Refs #214
Same defect as the aimdb-persistence README, smaller surface: the quickstart persisted `accuracy::vienna` and queried it with `accuracy::*`, which matches nothing under the segment-wildcard grammar. CHANGELOG.md's `"temp::*"` stays as written — it is the historical entry describing this break, not an example to copy. Refs #214
`query_latest` taught the old grammar directly — `"accuracy::*"` as the pattern example, `"accuracy::vienna"` as its contrast. The first matches nothing now and the second is no longer a contrast, just a wildcard-free pattern. `query_range` and `query_raw` said "pattern" without defining it. State the grammar once on the trait, referring to `PersistenceBackend::query` where the crate-level statement lives, and let each method describe only what it does with the matches. `query_raw` names `QUERY_ALL_PATTERN` since that is what the AimX handler passes it. `StoredValue::record_name`'s example key loses its `::` for the same reason, and now says it is always concrete — it is the type a third-party backend author reads the contract from. Refs #214
`MockBackend::query` took `_record_pattern` and returned every row, so no test in the crate proved a pattern ever reached a backend — let alone that it was read under the segment-wildcard grammar. The six existing tests pass today and would have kept passing through a careless key rename, which is the gap review named. Filter the mock's rows through the re-exported `topic_matches`, the same matcher `PersistenceBackend::query` obliges a real backend to decide with, and dot-separate the fixture keys so a pattern can address them. `QueryParams` stays ignored: row-level filtering is `AimDbQueryExt`'s job and remains what the original six tests are about. Three cases pin the grammar at the backend-contract level, where a third-party backend author looks (aimdb-persistence-sqlite covers it against real SQLite, but only there): - `sensor.*` must not return `sensor.deep.nested` — the regression #201 was made for. Fails if the mock goes pattern-blind again. - `sensor.#` reaches that row, so the exclusion above is the pattern's doing and not a missing fixture. - a key with no dots is one segment no wildcard can address. Refs #214
The client-facing doc promised the marker always arrives ("the engine
reserves a sink slot for this update, so it arrives even from a burst that
overran"). The reservation is real, but it only defends against overrun.
The marker rides the final snapshot's frame, so a burst with no final
snapshot ends without one:
- **Empty burst.** `snapshots()` filters through `try_latest_as_json`, so a
pattern matching nothing — or only records with no value yet — leaves
`total == 0`, the loop body never runs and nothing is sent. Ordinary on a
fresh database.
- **Tail failed to encode.** The frame is logged and skipped, and `last`
goes with it.
- **Exact-topic subscribe.** Takes no snapshots at all, by design.
A consumer following the old text reads "no `snapshot_end` yet" as "the
burst is still arriving" and waits forever. Say instead that the marker
appears when the burst produced at least one encodable snapshot, that its
absence carries no information, and that `skipped` is still the loss signal.
Documentation only. Making the marker unconditional needs a
record-independent terminator frame — a new frame kind, `SubUpdate::data`
becoming `Option`, a reservation refactor — and still could not promise
delivery, since an unrecognized frame is skipped by design, which is the
same property that keeps new frame kinds backward-compatible. That was
considered and rejected as disproportionate.
`Delivery::BurstEnd` gets the same correction internally: its "guaranteed
delivery into the slot `BurstBody` kept free" holds only once a `BurstBody`
has run. A single-snapshot burst rests on ordering instead — the sink
predates the subscribe reply and the server sends snapshots before
registering the event pump — which is what a future reader would build on.
Refs #214
The `[Unreleased]` entry carried the same overstatement the rustdoc did — "a burst closes even when it overran the sink and even when no live event ever follows" reads as an unconditional guarantee. Unlike the historical `"temp::*"` note in aimdb-persistence-sqlite, this describes the contract about to ship, so it is corrected in place rather than left as a record. The reservation defends against overrun and that half stands; what it never covered is a burst with no final snapshot to carry the marker. aimdb-core's entry already says the flag is not an unconditional promise, and design 047 already tells consumers not to loop until it. Neither needs a change. Refs #214
Same content, less of it: the grammar rule and the `snapshot_end` conditions were each stated once and then restated in different words. Trims ~30 lines across the READMEs, the query rustdoc, the mock's comment and the `snapshot_end` sites without dropping a fact — every case that leaves the marker unset is still named, and `*` vs `#` is still contrasted where the reader picks one. Refs #214
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PersistenceBackend::querymoved from a prefix glob to the MQTT-stylegrammar subscriptions use, but the README still keyed every example with
::and queried it with::*. A wildcard is a whole dot-separatedsegment, so
accuracy::viennais a single segment no pattern canpartition and
accuracy::*is a literal key that matches nothing — areader copying the examples got zero rows and no error.
Migrate the example keys to dot-separated form, then fix the patterns over
them, and state the grammar once where the reader has to choose:
*for aknown depth,
#where it varies.query_rawtakes#because it feedsthe AimX
record.queryhandler, whose callers key at their own depth.Issue §6 — the out-of-scope
::keys stay, deliberately. The keys inexamples/remote-access-demo/src/server.rsandaimdb-wasm-adapter/tests/transform_join_integration_tests.rsare unchanged.They are exact-match only — the demo subscribes to one literal key
(
client.rs:179) and exact lookup is separator-agnostic — and nothing in therepo pairs a
::key with a wildcard outside the historical CHANGELOG entriesand the superseded design 022. The
::there qualifies a Rust type name ratherthan addressing a topic, which is a coherent separate convention, not the same
mistake. Revisit if the demo ever grows a wildcard subscribe: those four
server::*records are a set under a common prefix, which is the shape thatwould want one.
Closes #214