Skip to content

Commit 0aefb4d

Browse files
Marko Petzoldclaude
andcommitted
spec/plans: 29 wire-frame conformance plans + unskip 004
Plans organised by WAMP §: Basic Profile 004 Register → call → invocation → yield → result, two peers (was skipped pending multi-peer support) 006 Pub/sub fan-out across two distinct sessions 007 Call unknown procedure returns ERROR(no_such_procedure) 008 Subscribe → unsubscribe → unsubscribed roundtrip 009 Client GOODBYE → router echoes goodbye_and_out Advanced Profile 010 Pattern-based subscription (match=prefix), §14.4.7 011 Pattern-based subscription (match=wildcard), §14.4.7 012 Shared registration roundrobin distribution, §14.3.9 013 Progressive call results, §14.3.1.2 014 Standard error URIs reachable without auth (§13.6.2) 015 Cancel mode skip, §14.3.4 016 Cancel mode kill (callee receives INTERRUPT), §14.3.4 017 Cancel mode killnowait, §14.3.4 018 Publish with eligible/exclude session lists, §14.4.2 019 Pattern-based registration prefix, §14.3.7 020 Pattern-based registration wildcard, §14.3.7 021 Call timeout fires router-side, §14.3.3 022 Shared registration invoke=first, §14.3.9 023 Shared registration invoke=last, §14.3.9 024 Publisher exclusion (default-true and explicit-false), §14.4.5 025 Resubscribing to same topic returns existing id, §3.5.4 026 Shared registration invoke=random (option-acceptance smoke), §14.3.9 027 Shared registration invoke=random distribution via from_any, §14.3.9 Authentication 028 Anonymous welcome with explicit method + role, §13.2 029 Ticket auth happy path (challenge / authenticate / welcome), §13.5 030 Ticket auth with bad ticket aborts, §13.5 031 WAMP-CRA happy path (challenge / sign / authenticate / welcome), §13.4 032 WAMP-CRA with wrong signature aborts, §13.4 Disclosure 033 Caller disclosure adds caller_authid + caller_authrole, §14.3.5 034 Publisher disclosure adds publisher_authid + publisher_authrole, §14.4.4 Plans 028+ exercise the auth-aware router setup; plans 027 + 033/034 exercise the from_any / placeholder-peer substitution; plans 031/032 exercise the wampcra_sign compute step. All 34 plans pass on v4-contrib (the dealer fix in the previous commit unblocks 013 against this branch's spec-strict assertion). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 3b1a2ad commit 0aefb4d

30 files changed

Lines changed: 1306 additions & 11 deletions

spec/plans/basic/004_call_yield_result.yaml

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,49 @@ name: register-call-invocation-yield-result-roundtrip
22
spec_section: "Basic Profile §3.7"
33
realm: realm1
44
serializer: json
5-
skip: "register/call/result roundtrip needs two peers in the same plan; planned for the multi-peer extension of the runner"
5+
6+
# Two sessions: a callee that registers a procedure, and a caller that
7+
# invokes it. The router routes CALL → INVOCATION on the callee and
8+
# YIELD → RESULT back to the caller.
9+
peers:
10+
- name: callee
11+
- name: caller
12+
613
steps:
7-
- send: [1, "realm1", {roles: {callee: {}, caller: {}}}]
8-
- expect: [2, "{{$session_id:int}}", "_"]
9-
- send: [64, 2001, {}, "spec.test.proc"]
10-
note: "REGISTER"
11-
- expect: [65, 2001, "{{$reg_id:int}}"]
12-
note: "REGISTERED"
13-
- send: [48, 2002, {}, "spec.test.proc", [1, 2]]
14-
note: "CALL — same peer, currently routed to itself by single-peer plans"
15-
- expect: [68, "{{$inv_id:int}}", "{{$reg_id:int}}", "_", [1, 2]]
16-
note: "INVOCATION delivered back to this peer"
14+
# Callee handshake.
15+
- peer: callee
16+
send: [1, "realm1", {roles: {callee: {}}}]
17+
note: "HELLO"
18+
- peer: callee
19+
expect: [2, "{{$callee_session:int}}", "_"]
20+
note: "WELCOME"
21+
22+
# Caller handshake.
23+
- peer: caller
24+
send: [1, "realm1", {roles: {caller: {}}}]
25+
- peer: caller
26+
expect: [2, "{{$caller_session:int}}", "_"]
27+
28+
# Callee REGISTER → REGISTERED.
29+
- peer: callee
30+
send: [64, 2001, {}, "spec.test.proc"]
31+
note: "REGISTER request_id=2001"
32+
- peer: callee
33+
expect: [65, 2001, "{{$reg_id:int}}"]
34+
note: "REGISTERED carries registration id"
35+
36+
# Caller CALL → callee gets INVOCATION.
37+
- peer: caller
38+
send: [48, 2002, {}, "spec.test.proc", [1, 2]]
39+
note: "CALL request_id=2002 with positional args [1,2]"
40+
- peer: callee
41+
expect: [68, "{{$inv_id:int}}", "{{$reg_id:int}}", "_", [1, 2]]
42+
note: "INVOCATION delivered to callee, args preserved"
43+
44+
# Callee YIELD → caller gets RESULT.
45+
- peer: callee
46+
send: [70, "{{$inv_id:int}}", {}, [3]]
47+
note: "YIELD invocation_id, result=[3]"
48+
- peer: caller
49+
expect: [50, 2002, "_", [3]]
50+
note: "RESULT for request_id=2002 carries the yielded value"
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: pubsub-fan-out-across-two-sessions
2+
spec_section: "Basic Profile §3.5"
3+
realm: realm1
4+
serializer: json
5+
6+
# Verifies the broker fans an event from one publisher session to a
7+
# distinct subscriber session — without relying on the exclude_me=false
8+
# self-fan trick that 003 uses.
9+
peers:
10+
- name: subscriber
11+
- name: publisher
12+
13+
steps:
14+
# Subscriber handshake + SUBSCRIBE.
15+
- peer: subscriber
16+
send: [1, "realm1", {roles: {subscriber: {}}}]
17+
- peer: subscriber
18+
expect: [2, "{{$sub_session:int}}", "_"]
19+
20+
- peer: subscriber
21+
send: [32, 1101, {}, "spec.test.fanout"]
22+
note: "SUBSCRIBE"
23+
- peer: subscriber
24+
expect: [33, 1101, "{{$sub_id:int}}"]
25+
26+
# Publisher handshake + PUBLISH (with acknowledge).
27+
- peer: publisher
28+
send: [1, "realm1", {roles: {publisher: {}}}]
29+
- peer: publisher
30+
expect: [2, "{{$pub_session:int}}", "_"]
31+
32+
- peer: publisher
33+
send: [16, 1102, {acknowledge: true}, "spec.test.fanout", ["hello"]]
34+
- peer: publisher
35+
expect: [17, 1102, "{{$pub_id:int}}"]
36+
note: "PUBLISHED ack"
37+
38+
# Subscriber receives the EVENT.
39+
- peer: subscriber
40+
expect: [36, "{{$sub_id:int}}", "{{$pub_id:int}}", "_", ["hello"]]
41+
note: "EVENT carries publication id and payload"
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name: call-unknown-procedure-yields-no-such-procedure-error
2+
spec_section: "Basic Profile §3.7 / Errors §13.6.2"
3+
realm: realm1
4+
serializer: json
5+
6+
steps:
7+
- send: [1, "realm1", {roles: {caller: {}}}]
8+
- expect: [2, "{{$session_id:int}}", "_"]
9+
10+
- send: [48, 7001, {}, "no.such.procedure.exists", []]
11+
note: "CALL request_id=7001 to a never-registered URI"
12+
13+
# ERROR for CALL: [8, CALL=48, request_id, details, error_uri, args?, kwargs?]
14+
- expect: [8, 48, 7001, "_", "wamp.error.no_such_procedure"]
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: subscribe-unsubscribe-roundtrip
2+
spec_section: "Basic Profile §3.5 / §3.6"
3+
realm: realm1
4+
serializer: json
5+
6+
steps:
7+
- send: [1, "realm1", {roles: {subscriber: {}}}]
8+
- expect: [2, "{{$session_id:int}}", "_"]
9+
10+
- send: [32, 8001, {}, "spec.test.unsubscribe"]
11+
- expect: [33, 8001, "{{$sub_id:int}}"]
12+
note: "SUBSCRIBED — capture subscription id"
13+
14+
- send: [34, 8002, "{{$sub_id:int}}"]
15+
note: "UNSUBSCRIBE referencing the captured id"
16+
- expect: [35, 8002]
17+
note: "UNSUBSCRIBED for request_id=8002"
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
name: client-initiated-goodbye-router-echoes
2+
spec_section: "Basic Profile §3.4.2"
3+
realm: realm1
4+
serializer: json
5+
6+
steps:
7+
- send: [1, "realm1", {roles: {publisher: {}}}]
8+
- expect: [2, "{{$session_id:int}}", "_"]
9+
10+
- send: [6, {message: "client done"}, "wamp.close.normal"]
11+
note: "GOODBYE — message=6"
12+
- expect: [6, "_", "wamp.close.goodbye_and_out"]
13+
note: "Router echoes GOODBYE with the standard reason URI"
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: pattern-based-prefix-subscription
2+
spec_section: "Advanced §14.4.7 — Pattern-based Subscription"
3+
realm: realm1
4+
serializer: json
5+
6+
# Subscriber subscribes with `match=prefix` to "spec.test.area.";
7+
# publisher posts to a child URI; broker delivers the EVENT.
8+
peers:
9+
- name: subscriber
10+
- name: publisher
11+
12+
steps:
13+
- peer: subscriber
14+
send: [1, "realm1", {roles: {subscriber: {}}}]
15+
- peer: subscriber
16+
expect: [2, "{{$sub_session:int}}", "_"]
17+
18+
- peer: subscriber
19+
send: [32, 10001, {match: "prefix"}, "spec.test.area."]
20+
note: "SUBSCRIBE with match=prefix"
21+
- peer: subscriber
22+
expect: [33, 10001, "{{$sub_id:int}}"]
23+
24+
- peer: publisher
25+
send: [1, "realm1", {roles: {publisher: {}}}]
26+
- peer: publisher
27+
expect: [2, "{{$pub_session:int}}", "_"]
28+
29+
- peer: publisher
30+
send: [16, 10002, {acknowledge: true}, "spec.test.area.fire", ["alarm"]]
31+
- peer: publisher
32+
expect: [17, 10002, "{{$pub_id:int}}"]
33+
34+
# Pattern-matched EVENT carries the original topic in details.topic.
35+
- peer: subscriber
36+
expect: [36, "{{$sub_id:int}}", "{{$pub_id:int}}", {topic: "spec.test.area.fire"}, ["alarm"]]
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: pattern-based-wildcard-subscription
2+
spec_section: "Advanced §14.4.7 — Pattern-based Subscription"
3+
realm: realm1
4+
serializer: json
5+
6+
# Wildcard pattern: each empty URI component is a single-segment
7+
# wildcard. "spec.test..fire" matches "spec.test.<anything>.fire".
8+
peers:
9+
- name: subscriber
10+
- name: publisher
11+
12+
steps:
13+
- peer: subscriber
14+
send: [1, "realm1", {roles: {subscriber: {}}}]
15+
- peer: subscriber
16+
expect: [2, "{{$sub_session:int}}", "_"]
17+
18+
- peer: subscriber
19+
send: [32, 11001, {match: "wildcard"}, "spec.test..fire"]
20+
note: "SUBSCRIBE with match=wildcard, second segment is the wildcard"
21+
- peer: subscriber
22+
expect: [33, 11001, "{{$sub_id:int}}"]
23+
24+
- peer: publisher
25+
send: [1, "realm1", {roles: {publisher: {}}}]
26+
- peer: publisher
27+
expect: [2, "{{$pub_session:int}}", "_"]
28+
29+
- peer: publisher
30+
send: [16, 11002, {acknowledge: true}, "spec.test.alarm.fire", ["match"]]
31+
- peer: publisher
32+
expect: [17, 11002, "{{$pub_id:int}}"]
33+
34+
- peer: subscriber
35+
expect: [36, "{{$sub_id:int}}", "{{$pub_id:int}}", {topic: "spec.test.alarm.fire"}, ["match"]]
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
name: shared-registration-roundrobin-distributes-calls
2+
spec_section: "Advanced §14.3.9 — Shared Registration"
3+
realm: realm1
4+
serializer: json
5+
6+
# Two callees register the same procedure with invoke=roundrobin. Caller
7+
# issues 4 CALLs; the dealer rotates: call 1 → callee1, call 2 → callee2,
8+
# call 3 → callee1, call 4 → callee2. Confirms roundrobin distribution
9+
# in registration order (matches dealer.go's nextCallee policy).
10+
peers:
11+
- name: callee1
12+
- name: callee2
13+
- name: caller
14+
15+
steps:
16+
# Callee 1 handshake + REGISTER (first registrant — index 0).
17+
- peer: callee1
18+
send: [1, "realm1", {roles: {callee: {}}}]
19+
- peer: callee1
20+
expect: [2, "{{$c1_session:int}}", "_"]
21+
22+
- peer: callee1
23+
send: [64, 12001, {invoke: "roundrobin"}, "spec.test.shared"]
24+
- peer: callee1
25+
expect: [65, 12001, "{{$reg_id:int}}"]
26+
note: "Both callees share the same registration id"
27+
28+
# Callee 2 handshake + REGISTER (second registrant — index 1).
29+
- peer: callee2
30+
send: [1, "realm1", {roles: {callee: {}}}]
31+
- peer: callee2
32+
expect: [2, "{{$c2_session:int}}", "_"]
33+
34+
- peer: callee2
35+
send: [64, 12002, {invoke: "roundrobin"}, "spec.test.shared"]
36+
- peer: callee2
37+
expect: [65, 12002, "{{$reg_id:int}}"]
38+
39+
# Caller handshake.
40+
- peer: caller
41+
send: [1, "realm1", {roles: {caller: {}}}]
42+
- peer: caller
43+
expect: [2, "{{$caller_session:int}}", "_"]
44+
45+
# CALL #1 → callee1.
46+
- peer: caller
47+
send: [48, 12101, {}, "spec.test.shared", [1]]
48+
- peer: callee1
49+
expect: [68, "{{$inv1:int}}", "{{$reg_id:int}}", "_", [1]]
50+
- peer: callee1
51+
send: [70, "{{$inv1:int}}", {}, ["one"]]
52+
- peer: caller
53+
expect: [50, 12101, "_", ["one"]]
54+
55+
# CALL #2 → callee2.
56+
- peer: caller
57+
send: [48, 12102, {}, "spec.test.shared", [2]]
58+
- peer: callee2
59+
expect: [68, "{{$inv2:int}}", "{{$reg_id:int}}", "_", [2]]
60+
- peer: callee2
61+
send: [70, "{{$inv2:int}}", {}, ["two"]]
62+
- peer: caller
63+
expect: [50, 12102, "_", ["two"]]
64+
65+
# CALL #3 → callee1 (rotation wraps).
66+
- peer: caller
67+
send: [48, 12103, {}, "spec.test.shared", [3]]
68+
- peer: callee1
69+
expect: [68, "{{$inv3:int}}", "{{$reg_id:int}}", "_", [3]]
70+
- peer: callee1
71+
send: [70, "{{$inv3:int}}", {}, ["three"]]
72+
- peer: caller
73+
expect: [50, 12103, "_", ["three"]]
74+
75+
# CALL #4 → callee2.
76+
- peer: caller
77+
send: [48, 12104, {}, "spec.test.shared", [4]]
78+
- peer: callee2
79+
expect: [68, "{{$inv4:int}}", "{{$reg_id:int}}", "_", [4]]
80+
- peer: callee2
81+
send: [70, "{{$inv4:int}}", {}, ["four"]]
82+
- peer: caller
83+
expect: [50, 12104, "_", ["four"]]
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: progressive-call-results-stream
2+
spec_section: "Advanced §14.3.1 — Progressive Call Results"
3+
realm: realm1
4+
serializer: json
5+
6+
# Caller issues a CALL with receive_progress=true. The callee yields
7+
# two progressive YIELDs (progress=true), then a final non-progress
8+
# YIELD. The caller observes two progressive RESULTs followed by the
9+
# terminal RESULT.
10+
peers:
11+
- name: callee
12+
- name: caller
13+
14+
steps:
15+
- peer: callee
16+
send: [1, "realm1", {roles: {callee: {features: {progressive_call_results: true}}}}]
17+
note: "Per spec §14.3.1.2 the callee only needs to declare progressive_call_results"
18+
- peer: callee
19+
expect: [2, "{{$callee_session:int}}", "_"]
20+
21+
- peer: callee
22+
send: [64, 13001, {}, "spec.test.progressive"]
23+
- peer: callee
24+
expect: [65, 13001, "{{$reg_id:int}}"]
25+
26+
- peer: caller
27+
send: [1, "realm1", {roles: {caller: {}}}]
28+
- peer: caller
29+
expect: [2, "{{$caller_session:int}}", "_"]
30+
31+
- peer: caller
32+
send: [48, 13002, {receive_progress: true}, "spec.test.progressive"]
33+
note: "CALL with receive_progress=true"
34+
- peer: callee
35+
expect: [68, "{{$inv_id:int}}", "{{$reg_id:int}}", {receive_progress: true}]
36+
note: "INVOCATION carries receive_progress"
37+
38+
# Progressive YIELD #1.
39+
- peer: callee
40+
send: [70, "{{$inv_id:int}}", {progress: true}, ["chunk1"]]
41+
- peer: caller
42+
expect: [50, 13002, {progress: true}, ["chunk1"]]
43+
44+
# Progressive YIELD #2.
45+
- peer: callee
46+
send: [70, "{{$inv_id:int}}", {progress: true}, ["chunk2"]]
47+
- peer: caller
48+
expect: [50, 13002, {progress: true}, ["chunk2"]]
49+
50+
# Final non-progress YIELD terminates the stream.
51+
- peer: callee
52+
send: [70, "{{$inv_id:int}}", {}, ["final"]]
53+
- peer: caller
54+
expect: [50, 13002, "_", ["final"]]
55+
note: "Terminal RESULT — details dict need not carry progress=false explicitly"

0 commit comments

Comments
 (0)