sym 0.13.12 — directed CMBs reach their agent, authors stay authors, bad frames close - #43
Merged
Merged
Conversation
- A bad length prefix stops the parser and closes the TCP connection instead of reading payload bytes as the next length. - A parse error no longer clears the 10 s inbound identification deadline; only a handshake or a close does. - Frames that are null, non-objects or lack a string type are discarded silently; invalid UTF-8 is rejected; handler exceptions are reported as handler failures, not "Invalid JSON". - A relay message null (or an envelope without a typed payload) is ignored instead of crashing the process. - send() returns false when the socket is closed, the relay is not open or the frame exceeds MAX_FRAME_SIZE. Audit findings B-T1, B-T2, B-T3, B-T10 and the transport half of B-T4. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…record
Directed delivery (MMP §9.2.2, §8.8.2):
- a directed reply citing the receiver's own CMB is no longer dropped
as an echo
- directed de-duplication uses content key + signature (interim until
assertionId), so a new send of already-seen words surfaces
- an admitted directed CMB the store already holds surfaces as
delivered-not-stored, and no longer poisons the dedup cache
- a rejected directed CMB with a mood surfaces once, not twice
Authorship (MMP §8.8.4, §15.2): a collapsed admission keeps the
author's createdBy, timestamp, signature and lineage on both SVAF paths
instead of re-stamping the receiver as author.
Send path: a directed send that collapses onto HEAD or is already
stored still delivers the stored record, and dispatched counts only
frames a transport accepted.
Interface: cmb-accepted entries carry author {name, nodeId, via} and
the inbox id; node.inboxAck(id) marks one item read out of order.
Audit findings B-D1 to B-D6, B-L1, B-T4 (send half).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…bad frames close Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Confirmed each finding with a test that fails before the fix: - F1/F13 a collapsed or already-stored directed send now sends the caller's freshly signed record (re-signed after the self-edge lineage is cleared), so the peer surfaces a repeated request instead of dropping it as a replay - F2/F6 only an authenticated mark (assertionId, else signature) widens the directed dedup key; unverified records keep the content key - F3 an admitted-but-not-stored broadcast runs the post-admit tail as before; only a directed CMB additionally surfaces - F4 a rejected directed CMB still delivers its §9.3 mood - F5/F8 collapse keeps the author's categories (signed meta included); the test signs for real and verifies the stored record - F7 relay payloads over MAX_FRAME_SIZE are dropped inbound - F9 delivery tests drive a real receiving node - F10 an acked inbox is not neverDrained; acked evictions are counted - F11/F12 the duplicate path dispatches without metadata.key and returns an entry-shaped result - F14 a pre-boundary record keeps its author name on collapse - F15 author.nodeId only when verified against the delivering peer it names; msg.source never names the author Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- e2e-admission put A and B in different rooms, which 0.13.11's room door correctly refuses; both are now in sym-bot-team - e2e-cmb-path expected a remix record with parents:[A]; under content addressing an admission that adds nothing keeps A's record as signed (the remix-rule RFC), so it now accepts either shape - both stop their nodes in finally, so a failed assertion no longer holds the run until the 30 s timeout Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…es on it) The channel keys sender authorization on author.via.name, the delivering peer. Pin it on the rejected-directed, CLI-host and admitted paths, and on the inbox item each produces. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Confirmed with tests that fail before the fix (F1, F2, F4-F8): - F1 the echo exemption needs an authenticated addressee: a verified record must be signed to this node (metadata.to); unsigned frame flags still surface a CMB but never bypass §14 echo suppression - F2 a caller-supplied opts.cmb that collapses is not sent unre-signed; delivery says undelivered with a reason - F4 neverDrained clears only when every item is acked - F5 the duplicate-send result is built from the caller's record, never a peer's stored envelope - F6 strippedOfVectors keeps everything but the vector (mood affect) - F7 a failed store write surfaces as decision 'not-stored' - F8 stop() flushes a pending inbox write - F9 a node's own createdTimestamp is strictly increasing - F3/F10/F11 e2e-cmb-path requires a real outcome and asserts the collapse; nodes stop via Promise.allSettled Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Confirmed with tests that fail before the fix: - r3 F1 a verified record overrides the frame's directed flag only when it signs an addressee field; emitters that sign none keep §9.2.2 - r3 F2 an unauthenticated directed reply citing our CMB is delivered once (decision 'echo') but never admitted, stored or remixed; the echo check now runs after de-duplication - r3 F3 a failed store write on the duplicate path is persisted:false, not duplicate:true - r3 F5 strippedOfVectors keeps only text, meta, valence, arousal - r3 F6 a caller's collapsed record is returned unmodified - r3 F8 neverDrained holds when the ring was evicted undrained - r3 F10 e2e-cmb-path requires an admission, not any outcome - r3 F11 the duplicate result carries this node's source - R2-F12 the store wrapper passes creatorRole through (anchorWeight 2.0) - R2-F7/F10 relay ws maxPayload at the frame bound; drops are logged Deferred with reasons in CHANGELOG known limits: r3 F4, F9, R2-F5, R2-F9, R2-F11. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…known limits Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t ~/code/sym It resolved lib/core/room-grant.js under $HOME/code/sym, which exists only on one machine; CI has failed on it since 0.13.10. Default to the repo the test lives in (SYM_DIR still overrides). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A cmb frame is {type, timestamp, cmb}; only a hostile peer sets source,
and every msg.source || peerName read then named whoever it chose,
including the receiver itself. Dropped (and logged) where a CMB frame
enters, so the deliverer always comes from the connection. Found by the
xmesh review of sym-mesh-channel#30 (mission-56a137ffa8e4, F2).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sym-bot
added a commit
to sym-bot/sym-mesh-channel
that referenced
this pull request
Oct 1, 2026
0.13.12 (sym-bot/sym#43, published 2026-10-01, shasum bd8115b1) is the engine the 0.10.0 channel is written against: entry.author with a connection-derived via, entry.inboxId and node.inboxAck, remember().delivery on every directed send including re-sends of a stored record, and a frame-supplied `source` ignored. With it, a held directed send flushes without the re-send suffix. 16/16 test files pass against the published 0.13.12; verify:packed passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes from an MMP 2.0 conformance audit of sym-mesh-channel and the SDK it runs. Every bug fixed here has a test that fails on 0.13.11. See
CHANGELOG.mdfor the full list.Changes
Wire (§4.1, §19.1): malformed frames no longer cancel the 10 s inbound identification deadline. A bad length prefix closes the connection instead of desynchronising the stream. A relay message
nullno longer crashes the process.send()reports whether a transport accepted the frame.Directed delivery (§9.2.2, §8.8.2): fixes four paths that dropped or doubled a CMB addressed to this node:
Authorship (§8.8.4, §15.2): when an admission collapses onto an existing record, the author's
createdBy, signature and lineage are kept. Before, the receiver re-stamped itself as author at the author's address.Send path: a directed send that collapses onto HEAD, or is already stored, now delivers the stored record instead of nothing.
delivery.dispatchedcounts only accepted frames.Interface for sym-mesh-channel:
cmb-acceptedentries carryauthor {name, nodeId, via},inboxIdandinboxSeq. Newnode.inboxAck(id).Testing
npm test: 605/605. Of those, 26 are new: 19 reproduce a specific bug and fail on 0.13.11.npm run gate:stock-nodes: passes.npm run test:integration: 6/8.e2e-admissionande2e-cmb-pathtime out at 30 s, and they fail the same way on unmodified 0.13.11, so this PR doesn't touch them.Known gaps (follow-ups)
assertionId(Core Secure emission, a separate rollout).createdByNodeId, and the legacy handshake is still used. Both are part of the Core Secure rollout plan, not this release.🤖 Generated with Claude Code