Skip to content

[eval] [FIXED] Fix subject tree intersection to match literals when followed by additional wildcards#1

Open
Uzay-G wants to merge 2 commits intoeval/base-pr-6827from
eval/upstream-pr-6827
Open

[eval] [FIXED] Fix subject tree intersection to match literals when followed by additional wildcards#1
Uzay-G wants to merge 2 commits intoeval/base-pr-6827from
eval/upstream-pr-6827

Conversation

@Uzay-G
Copy link
Copy Markdown

@Uzay-G Uzay-G commented Feb 21, 2026

Mirror of nats-io#6827 (MERGED) for Orpheus review evaluation.

Upstream: nats-io#6827


Original PR description:

The subject tree intersection could miss non-wildcard matches if they were followed up by further extended wildcards in other sublist filters. This is now fixed.

Fixes nats-io#6824.

Signed-off-by: Neil Twigg neil@nats.io
Co-authored-by: Maurice van Veen github@mauricevanveen.com

neilalexander and others added 2 commits April 24, 2025 10:33
…tional wildcards

Signed-off-by: Neil Twigg <neil@nats.io>
Signed-off-by: Maurice van Veen <github@mauricevanveen.com>
@orpheus-by-fulcrum-dev-uzay-g
Copy link
Copy Markdown

Review started.

Copy link
Copy Markdown

@orpheus-by-fulcrum-dev-uzay-g orpheus-by-fulcrum-dev-uzay-g bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All checks passed.

Expected behavior

  • A JetStream consumer with filter subjects ["stream.A", "stream.A.>"] delivers all messages on stream.A (the literal) and stream.A.* / stream.A.> (the wildcard children)
  • The IntersectStree function finds literal subject matches even when the sublist level also contains wildcard (fwc/pwc) children
  • No duplicate messages are delivered when filter subjects overlap structurally (literal + extended wildcard at the same prefix)
  • Existing sublist intersection behavior (literals, PWC, FWC, overlapping patterns) is preserved without regressions

What happens

  • ✅ Happy path works: consumer with ["stream.A", "stream.A.>"] delivers all 10 messages on stream.A and all 8 messages on child subjects, with no duplicates (18 total)
  • ✅ Bug confirmed on pre-fix build: same consumer shows 0 unprocessed messages on the old code, proving the fix resolves the issue
  • ✅ No duplicates: consumer pending count matches exactly the number of published messages across all tested patterns (["stream.A", "stream.A.>"], ["stream.A", "stream.A.>", "stream.B"], ["stream.A", "stream.B"])
  • ✅ Real-time delivery works: messages published after consumer creation are also correctly delivered through overlapping filters
  • ✅ All 61 sublist tests and the new TestJetStreamConsumerDeliverAllOverlappingFilterSubjects test pass with no regressions
Detailed evidence

Setup

export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin

# Build the fixed server
go build -o /home/agent/nats-server/nats-server .
# → nats-server: v2.11.2-RC.2

# Build the pre-fix server for comparison
git checkout 82cb3edb0^ -- server/sublist.go
go build -o /tmp/nats-server-old .
git checkout HEAD -- server/sublist.go

Demo 1: Happy path — overlapping literal + FWC filters

# Start fixed server with JetStream
/home/agent/nats-server/nats-server -js -sd /tmp/nats-data -p 4222 &

# Create stream
nats stream add TEST --subjects "stream.>" --storage memory ...
# → Stream TEST was created

# Publish 10 messages to stream.A
for i in $(seq 1 10); do nats pub stream.A "message-$i"; done

# Create consumer with overlapping filter subjects
nats consumer add TEST OVERLAP_CONSUMER \
  --deliver all \
  --filter "stream.A" --filter "stream.A.>" \
  --ack explicit --pull --defaults
# → Unprocessed Messages: 10   ← correct, all 10 found

# Fetch all messages
nats consumer next TEST OVERLAP_CONSUMER --count 10 --timeout 5s
# → 10 messages received on stream.A, cons seq 1-10, str seq 1-10

Demo 2: Child subject delivery via FWC

# Publish to child subjects
for i in $(seq 1 5); do nats pub stream.A.child "child-msg-$i"; done
for i in $(seq 1 3); do nats pub stream.A.deep.nested "deep-msg-$i"; done

# Fetch from consumer
nats consumer next TEST OVERLAP_CONSUMER --count 10 --timeout 5s
# → 8 messages received: 5 on stream.A.child (cons seq 11-15), 3 on stream.A.deep.nested (cons seq 16-18)

Demo 3: No duplicates

# Create new consumer with ack=none to verify total count
nats consumer add TEST DEDUP_CHECK \
  --deliver all \
  --filter "stream.A" --filter "stream.A.>" \
  --ack none --pull --defaults
# → Unprocessed Messages: 18   ← exactly 10+5+3, no duplicates

# Fetch and verify unique stream sequences
nats consumer next TEST DEDUP_CHECK --count 20 --timeout 5s | grep "subj:" | sort
# → 18 lines, each with unique str seq 1-18

Demo 4: Bug confirmed on pre-fix build

# Start OLD server (built from parent commit before fix)
pkill -9 nats-server
/tmp/nats-server-old -js -sd /tmp/nats-data-old -p 4222 &

# Same setup: create stream, publish 10 messages to stream.A
nats stream add TEST --subjects "stream.>" --storage memory ...
for i in $(seq 1 10); do nats pub stream.A "message-$i"; done

# Create same consumer
nats consumer add TEST BUG_CHECK \
  --deliver all \
  --filter "stream.A" --filter "stream.A.>" \
  --ack none --pull --defaults
# → Unprocessed Messages: 0   ← BUG: should be 10, but the old intersection misses the literal

Demo 5: Mixed complex filters

# Restart fixed server, create stream, publish various messages

# stream.A (literal) + stream.A.> (fwc) + stream.B (literal)
nats consumer add TEST MIXED_COMPLEX \
  --deliver all \
  --filter "stream.A" --filter "stream.A.>" --filter "stream.B" \
  --ack none --pull --defaults
# → Unprocessed Messages: 19   ← 10+5+3+1, correct

# Overlapping PWC+literal correctly rejected by server
nats consumer add TEST PWC_LITERAL \
  --filter "stream.*" --filter "stream.A" ...
# → error: consumer subject filters cannot overlap (10138)

Demo 6: Real-time delivery

# Fresh server, create consumer FIRST, then publish
nats consumer add TEST PUSH_OVERLAP \
  --deliver all \
  --filter "stream.A" --filter "stream.A.>" \
  --ack explicit --pull --defaults
# → Unprocessed Messages: 0

# Publish after consumer creation
for i in $(seq 1 5); do nats pub stream.A "realtime-$i"; done
for i in $(seq 1 3); do nats pub stream.A.child "realtime-child-$i"; done

nats consumer info TEST PUSH_OVERLAP | grep Unprocessed
# → Unprocessed Messages: 8

nats consumer next TEST PUSH_OVERLAP --count 10 --timeout 3s | grep "subj:"
# → 5 stream.A messages + 3 stream.A.child messages, all delivered

Test suite

# Sublist intersection tests (including new FWCExtended)
go test -v -run "TestSublistInterestBasedIntersection" ./server/
# → PASS (all 10 subtests)

# JetStream consumer overlapping filter test
go test -v -run "TestJetStreamConsumerDeliverAllOverlappingFilterSubjects" ./server/
# → PASS

# All sublist tests (regression check)
go test -v -run "TestSublist" ./server/
# → PASS (61 tests, 0.034s)

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.

3 participants