Skip to content

Releases: macula-io/macula

v3.13.0

28 Apr 19:37

Choose a tag to compare

feat(advertise): V2 ADVERTISE/UNADVERTISE wire frames + station_link …

v3.12.1

28 Apr 17:29

Choose a tag to compare

fix(station_link): gate {call, ...} on peer_node_id (matches publish)

Release 3.12.1.

The {call, ...} gen_server clause was gated on peer_pid, set the moment
macula_peering:connect/1 returns — before the peering worker has finished
the CONNECT/HELLO handshake. publish/4 was correctly gated on peer_node_id
(set by the {macula_peering, connected, ...} notification after HELLO).

Race: a caller (e.g. a freshly-spawned daemon stub) issues put_record/3
immediately after start_link/1. The link forwards the call frame via
gen_statem:cast(PeerPid, {send_frame, Frame}) while the peering worker
is still in handshaking. handshaking has no clause for cast({send_frame, _}),
so the cast falls into drop_unexpected and the frame is silently dropped.
The caller's deadline timer fires and surfaces {error, timeout}, even
though the underlying QUIC connection is healthy and any subsequent call
(after the timer's wake-up) would have succeeded.

Fix: gate {call, ...} on peer_node_id to match {publish, ...}. Callers
issuing a request before the handshake completes now get
{error, not_connected} immediately, matching the SDK's documented
contract for the disconnected case. Existing call sites already handle
{error, not_connected} with a short backoff, so no consumer change is
required.

Direct evidence: handshaking peering_conn workers on production relay
boxes carried buffers stuck on V1-protocol bytes from beam-daemon
realm-join (separate problem, fixed in hecate-daemon), but V2-protocol
stub workers also exhibited timeout-then-recycle cycles on every
put_record because of this race.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

v3.11.1

27 Apr 16:47

Choose a tag to compare

fix(record_cbor): accept atoms in encode/1 to round-trip wire-decoded…

v3.11.0

27 Apr 15:48

Choose a tag to compare

chore: Release v3.11.0 — Phase 1 V2 PARITY (pool + pubsub + docs)

v3.10.3

27 Apr 12:36

Choose a tag to compare

chore: Release v3.10.3

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

v3.9.0

26 Apr 12:29

Choose a tag to compare

feat(client)!: put_record + find_record on station-client — v3.9.0

Round out macula_station_client so it owns every DHT operation a
node needs against a V2 station, not just reads:

  - put_record/2,3   wraps _dht.put_record. ok / {error,_} taxonomy.
  - find_record/2,3  wraps _dht.find_record. {ok,Record} or
                     {error, not_found}.

Closes the wire-incompat gap that left node daemons unable to
publish node_record / domain-fact records into V2-only stations:
macula_mesh_client (V1) is rejected by hecate-station's V2 peering
listener, so before this release writes silently dropped. Consumers
(hecate-daemon, future SDK clients) now have a single read+write
path through macula_station_client.

Tests: 4 new EUnit cases. macula_station_client_tests count: 10.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

v3.8.0

26 Apr 07:05

Choose a tag to compare

feat(client)!: V2 station-client for outbound RPC over peering — v3.8.0

Adds macula_station_client, a high-level gen_server wrapping macula_peering
+ macula_frame to issue CALL frames against V2 stations and match
RESULT/ERROR replies via the 16-byte call_id.

Closes a real protocol gap: V1 macula_mesh_client cannot drive a V2
station because the station dispatches the QUIC connection straight
into macula_peering:accept/2 — V1 CONNECT frames never reach the V2
handler registry. Consumers like macula-realm's topology subscriber
were silently timing out on every find_records_by_type call.

API:
  - macula_station_client:start_link/1   #{seed, identity, realm, ...}
  - macula_station_client:call/4         (Pid, Procedure, Payload, Timeout)
  - macula_station_client:find_records_by_type/2,3
  - is_connected/1, peer_node_id/1, stop/1

Tests:
  - 6 new EUnit cases for seed parsing, RESULT/ERROR matching, deadline,
    disconnect drain. Live QUIC handshake covered in hecate-station CT
    suites which already exercise the peering layer end-to-end.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

v3.7.0

26 Apr 02:17

Choose a tag to compare

feat(peering+diagnostics): vendor macula_peering + macula_diagnostics…

v3.6.0

26 Apr 00:48

Choose a tag to compare

feat(frame): vendor macula_frame + macula_bolt4 + macula_source_route…

v3.5.0

25 Apr 17:52

Choose a tag to compare

feat(record): expose envelope/4 + subject_id for domain-defined types…