Skip to content

fix(stream): key stream metadata by namespace-qualified name (#46) - #48

Merged
oreofeolurin merged 3 commits into
devfrom
fix/46-stream-metadata-namespace
Aug 30, 2026
Merged

fix(stream): key stream metadata by namespace-qualified name (#46)#48
oreofeolurin merged 3 commits into
devfrom
fix/46-stream-metadata-namespace

Conversation

@oreofeolurin

Copy link
Copy Markdown
Contributor

Fixes #46. Found while verifying #42 items 2/3.

The bug

Stream metadata — partition count plus all three retention settings — was keyed by the bare stream name, while stream_names was already keyed by the namespace-qualified one. Two namespaces holding a same-named stream shared a single metadata entry, so creating the second silently rewrote the first's configuration:

$ flo stream create solo --partitions 4 -n ns1
$ flo stream info solo -n ns1
  Partitions: 4

$ flo stream create solo --partitions 1 -n ns2      # unrelated namespace

$ flo stream info solo -n ns1
  Partitions: 1        ← silently changed

Partition count drives routing, so a tenant could re-route another tenant's stream just by picking the same name — no error, no log line. Retention collided the same way, letting one namespace shorten another's and delete its data.

The fix

Metadata is qualified at every read and write, matching what the name registry already does.

Two distinct read paths needed it, not one. Qualifying the key fixed stream info, but stream list still reported the wrong count — it strips the namespace prefix before looking metadata back up, and it's served by the ShardWalker (serializeWalkStreamNames), not by handleList. Both serializers now take the namespace and re-qualify, the same shape queue_list, processing_list and action_list already use. I'd have shipped a half-fix if I'd only checked info.

deleteStream removes the qualified key and still sweeps the raw one, so entries written by earlier builds don't leak.

Verified

$ flo stream create solo --partitions 4 -n ns1
$ flo stream create solo --partitions 1 -n ns2

$ flo stream info solo -n ns1     → Partitions: 4
$ flo stream ls          -n ns1     → solo  4
$ flo stream info solo -n ns2     → Partitions: 1
$ flo stream ls          -n ns2     → solo  1

$ flo stream alter solo --retention 24 -n ns1
$ flo stream info solo -n ns1     → Retention: Age: 86400s
$ flo stream info solo -n ns2     → (no retention)

Tests

Three e2e tests: partition count via info, partition count via list (the separate path), and retention isolation. All three fail against the unfixed code.

  • test-unit ✅ · test-integration
  • test-e2e 576/580 — the 4 failures are the kv/cluster set, confirmed failing identically on a stashed baseline.

Note on stacking

Branched off dev, independent of #45 and #47. It touches src/stream/handler.zig near #45's handleInfo change, so expect a small conflict depending on merge order — happy to rebase whichever lands second.

Stream metadata — partition count and all three retention settings — was keyed
by the bare stream name while `stream_names` was already keyed by the
namespace-qualified one. Two namespaces holding a same-named stream therefore
shared a single metadata entry, and creating the second silently rewrote the
first's configuration:

    flo stream create solo --partitions 4 -n ns1   # info: Partitions: 4
    flo stream create solo --partitions 1 -n ns2
    flo stream info solo -n ns1                    # Partitions: 1

Partition count drives routing, so a tenant could re-route another tenant's
stream by picking the same name, with no error and no log line. Retention
collided identically, letting one namespace shorten another's and delete its
data.

Metadata is now qualified at every read and write, matching the name registry.

Two distinct read paths needed it, not one. Qualifying the key fixed
`stream info`, but `stream list` still reported the wrong partition count: it
strips the namespace prefix before looking metadata back up, and it is served
by the ShardWalker (`serializeWalkStreamNames`) rather than by `handleList`.
Both serializers now take the namespace and re-qualify — the same shape
`queue_list`, `processing_list` and `action_list` already use.

`deleteStream` removes the qualified key and still sweeps the raw one, so
entries written by earlier builds do not leak.

Three e2e tests cover partition count via `info`, partition count via `list`
(the separate path), and retention. All three fail against the unfixed code.

test-unit and test-integration pass. test-e2e: 576/580, the 4 failures being
the `kv/cluster` set that fails identically on a stashed baseline.
Same pass as #60 and #45: comments state the constraint that still applies
rather than what used to be broken, and issue numbers no longer stand in for
reasons. Test names lose their issue tags.

Nothing behavioural.
@oreofeolurin
oreofeolurin force-pushed the fix/46-stream-metadata-namespace branch from 55eba9a to 3e6c091 Compare August 30, 2026 13:16
@oreofeolurin
oreofeolurin merged commit dc2dc20 into dev Aug 30, 2026
4 of 5 checks passed
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.

Stream metadata is keyed by raw name — a same-named stream in another namespace silently overwrites it

1 participant