Skip to content

Commit 33737e3

Browse files
Marko Petzoldclaude
andcommitted
spec/plans: pin WAMP §14.4 message-ordering guarantee
Two plans pin the broker's per-publisher ordering contract: 035 Single publisher emits 10 sequence-numbered events fire-and-forget; subscriber reads them in strict publish order. Relies on the chain of FIFO queues (publisher outbound → broker → subscriber inbound) to preserve order without explicit acks. 036 Two publishers alternate publishes with acknowledge=true on the same topic. Each PUBLISH waits for PUBLISHED before the next is sent, serializing broker dispatch. Subscriber reads events in publish-completion order (A1, B1, A2, B2, A3, B3) — verifies both per-publisher ordering (A1 < A2 < A3, B1 < B2 < B3) and the broker's FIFO behavior. Existing plans (018 eligible/exclude, 024 publisher exclusion) covered ordering only as a side-effect of sequential queue reads on a single subscriber. These two pin it as the primary assertion. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 1a62435 commit 33737e3

2 files changed

Lines changed: 168 additions & 0 deletions

File tree

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
name: events-from-single-publisher-arrive-at-subscriber-in-publish-order
2+
spec_section: "Basic Profile §3.5 / Advanced §14.4 — message ordering"
3+
realm: realm1
4+
serializer: json
5+
6+
# WAMP §14.4: events from a single publisher session must be delivered
7+
# to any given subscriber in the order they were published. Pinned here
8+
# by publishing 10 sequence-numbered events fire-and-forget, then
9+
# reading the subscriber's queue in order. The matcher fails on the
10+
# first out-of-order payload because the runner reads peer queues
11+
# strictly FIFO.
12+
peers:
13+
- name: subscriber
14+
- name: publisher
15+
16+
steps:
17+
- peer: subscriber
18+
send: [1, "realm1", {roles: {subscriber: {}}}]
19+
- peer: subscriber
20+
expect: [2, "{{$sub_session:int}}", "_"]
21+
22+
- peer: subscriber
23+
send: [32, 35001, {}, "spec.test.order"]
24+
- peer: subscriber
25+
expect: [33, 35001, "{{$sub_id:int}}"]
26+
27+
- peer: publisher
28+
send: [1, "realm1", {roles: {publisher: {}}}]
29+
- peer: publisher
30+
expect: [2, "{{$pub_session:int}}", "_"]
31+
32+
# Fire 10 PUBLISHes back-to-back without acknowledge. The publisher's
33+
# outbound channel is FIFO, the broker processes messages from one
34+
# client in receive order, and the subscriber's inbound is FIFO —
35+
# together these chain a per-publisher order guarantee.
36+
- peer: publisher
37+
send: [16, 35101, {}, "spec.test.order", ["seq", 1]]
38+
- peer: publisher
39+
send: [16, 35102, {}, "spec.test.order", ["seq", 2]]
40+
- peer: publisher
41+
send: [16, 35103, {}, "spec.test.order", ["seq", 3]]
42+
- peer: publisher
43+
send: [16, 35104, {}, "spec.test.order", ["seq", 4]]
44+
- peer: publisher
45+
send: [16, 35105, {}, "spec.test.order", ["seq", 5]]
46+
- peer: publisher
47+
send: [16, 35106, {}, "spec.test.order", ["seq", 6]]
48+
- peer: publisher
49+
send: [16, 35107, {}, "spec.test.order", ["seq", 7]]
50+
- peer: publisher
51+
send: [16, 35108, {}, "spec.test.order", ["seq", 8]]
52+
- peer: publisher
53+
send: [16, 35109, {}, "spec.test.order", ["seq", 9]]
54+
- peer: publisher
55+
send: [16, 35110, {}, "spec.test.order", ["seq", 10]]
56+
57+
# Read events back in strict order. Each EVENT has a distinct
58+
# publication id (captured under unique placeholder names so the
59+
# matcher confirms they're all integers) and the payload sequence
60+
# number must match the publish order.
61+
- peer: subscriber
62+
expect: [36, "{{$sub_id:int}}", "{{$pub1:int}}", "_", ["seq", 1]]
63+
- peer: subscriber
64+
expect: [36, "{{$sub_id:int}}", "{{$pub2:int}}", "_", ["seq", 2]]
65+
- peer: subscriber
66+
expect: [36, "{{$sub_id:int}}", "{{$pub3:int}}", "_", ["seq", 3]]
67+
- peer: subscriber
68+
expect: [36, "{{$sub_id:int}}", "{{$pub4:int}}", "_", ["seq", 4]]
69+
- peer: subscriber
70+
expect: [36, "{{$sub_id:int}}", "{{$pub5:int}}", "_", ["seq", 5]]
71+
- peer: subscriber
72+
expect: [36, "{{$sub_id:int}}", "{{$pub6:int}}", "_", ["seq", 6]]
73+
- peer: subscriber
74+
expect: [36, "{{$sub_id:int}}", "{{$pub7:int}}", "_", ["seq", 7]]
75+
- peer: subscriber
76+
expect: [36, "{{$sub_id:int}}", "{{$pub8:int}}", "_", ["seq", 8]]
77+
- peer: subscriber
78+
expect: [36, "{{$sub_id:int}}", "{{$pub9:int}}", "_", ["seq", 9]]
79+
- peer: subscriber
80+
expect: [36, "{{$sub_id:int}}", "{{$pub10:int}}", "_", ["seq", 10]]
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
name: per-publisher-ordering-preserved-across-two-publishers
2+
spec_section: "Basic Profile §3.5 / Advanced §14.4 — message ordering"
3+
realm: realm1
4+
serializer: json
5+
6+
# Stronger ordering guarantee: with two distinct publishers writing to
7+
# the same topic, the WAMP spec only mandates per-publisher order
8+
# (A1 < A2 < … from publisher A, B1 < B2 < … from publisher B), not
9+
# any cross-publisher interleaving.
10+
#
11+
# To make this deterministically testable in the wire harness, we
12+
# alternate publishes with `acknowledge: true` and wait for PUBLISHED
13+
# before issuing the next. That serializes the broker's processing
14+
# through one publish-cycle at a time, so the subscriber's queue ends
15+
# up in the publish-completion order: A1, B1, A2, B2, A3, B3.
16+
# This still verifies the strong contract (each publisher's stream
17+
# arrives in order) and additionally pins the broker's FIFO behavior.
18+
peers:
19+
- name: subscriber
20+
- name: pubA
21+
- name: pubB
22+
23+
steps:
24+
- peer: subscriber
25+
send: [1, "realm1", {roles: {subscriber: {}}}]
26+
- peer: subscriber
27+
expect: [2, "{{$sub_session:int}}", "_"]
28+
- peer: subscriber
29+
send: [32, 36001, {}, "spec.test.order.multi"]
30+
- peer: subscriber
31+
expect: [33, 36001, "{{$sub_id:int}}"]
32+
33+
- peer: pubA
34+
send: [1, "realm1", {roles: {publisher: {}}}]
35+
- peer: pubA
36+
expect: [2, "{{$a_session:int}}", "_"]
37+
38+
- peer: pubB
39+
send: [1, "realm1", {roles: {publisher: {}}}]
40+
- peer: pubB
41+
expect: [2, "{{$b_session:int}}", "_"]
42+
43+
# Round 1.
44+
- peer: pubA
45+
send: [16, 36101, {acknowledge: true}, "spec.test.order.multi", ["A", 1]]
46+
- peer: pubA
47+
expect: [17, 36101, "{{$a1:int}}"]
48+
49+
- peer: pubB
50+
send: [16, 36201, {acknowledge: true}, "spec.test.order.multi", ["B", 1]]
51+
- peer: pubB
52+
expect: [17, 36201, "{{$b1:int}}"]
53+
54+
# Round 2.
55+
- peer: pubA
56+
send: [16, 36102, {acknowledge: true}, "spec.test.order.multi", ["A", 2]]
57+
- peer: pubA
58+
expect: [17, 36102, "{{$a2:int}}"]
59+
60+
- peer: pubB
61+
send: [16, 36202, {acknowledge: true}, "spec.test.order.multi", ["B", 2]]
62+
- peer: pubB
63+
expect: [17, 36202, "{{$b2:int}}"]
64+
65+
# Round 3.
66+
- peer: pubA
67+
send: [16, 36103, {acknowledge: true}, "spec.test.order.multi", ["A", 3]]
68+
- peer: pubA
69+
expect: [17, 36103, "{{$a3:int}}"]
70+
71+
- peer: pubB
72+
send: [16, 36203, {acknowledge: true}, "spec.test.order.multi", ["B", 3]]
73+
- peer: pubB
74+
expect: [17, 36203, "{{$b3:int}}"]
75+
76+
# Subscriber reads in publish-completion order.
77+
- peer: subscriber
78+
expect: [36, "{{$sub_id:int}}", "{{$a1:int}}", "_", ["A", 1]]
79+
- peer: subscriber
80+
expect: [36, "{{$sub_id:int}}", "{{$b1:int}}", "_", ["B", 1]]
81+
- peer: subscriber
82+
expect: [36, "{{$sub_id:int}}", "{{$a2:int}}", "_", ["A", 2]]
83+
- peer: subscriber
84+
expect: [36, "{{$sub_id:int}}", "{{$b2:int}}", "_", ["B", 2]]
85+
- peer: subscriber
86+
expect: [36, "{{$sub_id:int}}", "{{$a3:int}}", "_", ["A", 3]]
87+
- peer: subscriber
88+
expect: [36, "{{$sub_id:int}}", "{{$b3:int}}", "_", ["B", 3]]

0 commit comments

Comments
 (0)