Repository navigation
sym 0.13.14 — a peer's admission verdict is observable as it lands - #46
Merged
Merged
Conversation
…lands A receiver gossips a signed Admission Attestation for every CMB it gates, but the author, or a mesh visualiser, could only see it by polling attestationsFor(). The node now emits 'attestation-received' on first sight of a verified, recorded attestation: of, by/byName, verdict, per-field categories, method, role, seq/prev, sig, verified, keySource (anchor, grant or handshake; handshake is trust on first use), from/fromPeerId and relayed. Duplicates, rate-limited copies, roster mismatches, unknown attesters and bad signatures emit nothing. Listeners get a copy, so they cannot alter the stored record, and a throwing listener does not undo the ingest. Asked for by dev-team-2 for the XMesh World hotel-bots view, which shows real SVAF signals instead of hardcoded passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014y3qC1m9acDVaerca56dvV
…listener Fixes from review mission-2b03e90f1876 (SHIP-WITH-FIXES, F1-F14): - method is outside the signed bytes, so it is now methodUnsigned (F1). - role is the attester's claim; roleResolved/roleMatches give what this node's grant chain resolves (F2). - categories are projected onto the seven CAT7 fields as the strings the signature covers: no nested value aliases the stored record, and no unsigned key a relay added reaches a listener (F3, F4). - The event is built from a clone and frozen. Each listener is called on its own: a throw (of any value) or an async rejection is logged with the attestation it was handling and cannot starve later listeners, undo the ingest, or become an unhandled rejection. once() still works (F5, F6, F10). - sigAlg is carried, so verifyAttestation(event, key) re-checks it (F7). - relayed is null when the deliverer is unknown (F12). - Tests: byName vs from with different names, unknown deliverer, claimed vs resolved role, relay-added fields, the rate-limited path, listener order, throw null, async rejection, once (F8, F9). Each protection was removed in turn and fails at least one test. - CHANGELOG separates signed fields from what this node adds, documents receivedAt, and says this node's own verdict is not on the event (F11, F13, F14). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014y3qC1m9acDVaerca56dvV
…ops reported Fixes from confirmation review mission-adf61be25234 (F1-F14 all FIXED; SHIP-WITH-FIXES on six low findings): - N1: return early when nothing listens, and pick the signed fields instead of deep-cloning the whole record (an unsigned blob is no longer cloned per ingest). - N2: every field is a primitive; an object-valued signed field is given as the string the canonicalizer signs, so one listener cannot change what the next sees, and the event still re-verifies. - N3: roleClaimed carries the claim roleMatches was computed against. - N4: an event that cannot be built is reported on metric as attestation-event-dropped; the attestation is still recorded. - N5: the log calls inside the failure handlers are guarded. - N6: tests for prependListener order and for listeners removed or added during dispatch. The async-rejection test now waits 20 ms, and removing the rejection handler fails it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014y3qC1m9acDVaerca56dvV
… too Fixes from round-3 review mission-cddbd2cddca0 (N1-N6: 4 fixed, 2 partly; SHIP-WITH-FIXES on five findings): - F1: roleClaimed and roleResolved go through the same coercion as the signed fields, and roleMatches compares those forms, so an array-valued role neither aliases the stored record nor fails to match a claim that signs identically. - F5: the attestation-event-dropped report reaches every metric listener through the same isolated dispatch (_emitIsolated) the event uses. - F2: a test that the no-listener path does no work. - F3: the log-sink test exercises the async rejection handler on its own, then the sync catch. - F4: the order test observes prependListener order. Each protection was removed in turn and fails a test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014y3qC1m9acDVaerca56dvV
…ng role compare Fixes from release-gate review mission-9b6156331681 (round-3 F1-F5 all FIXED; code gate SHIP; five low findings): - F1: the CHANGELOG named the seven CAT7 fields with the verdict vocabulary; it now lists focus ... mood, each carrying admit ... silent. - F2: the attestation-event-dropped payload is a plain object like the other 22 metric emits, so a listener that stamps it still records the drop; the notes say it is dispatched in isolation, not through emit(). - F3: roleClaimed/roleResolved are compared as strings, so a numeric role that signs as '2' matches a resolved '2'. - F4: the zero-listener test asserts the grant chain is never walked. - F5: the notes and JSDoc say listeners run synchronously on the frame-ingest path, after gossip, so heavy work belongs in a queue. Unit suite 642/644 (0 failed, 2 skipped), integration gossip e2e green; each new protection was removed in turn and fails a test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014y3qC1m9acDVaerca56dvV
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.
Adds the
attestation-receivedevent. A node emits it the first time it verifies and records a peer's Admission Attestation, so an author or a mesh view sees each verdict as it lands instead of pollingattestationsFor(). Asked for by dev-team-2 for the XMesh World hotel-bots view, which shows real SVAF signals.What the event carries
of,by,at,roster,seq,prev,verdict, the seven CAT7categories(as the strings the signature covers), the claimedrole, plussig/sigAlg.verifyAttestation(event, key)re-checks the event.verified,keySource(anchor/grant/handshake; handshake is trust on first use);roleClaimed,roleResolved,roleMatches;methodUnsigned;byName(a label, not an identity);from,fromPeerId,relayed(true / false / null);receivedAt.Guarantees
throw nullor an async rejection is logged and cannot starve later listeners, undo the ingest or become an unhandled rejection.once()andprependListenerbehave as withemit.metricasattestation-event-dropped.Review
Four xmesh review rounds: mission-2b03e90f1876, mission-adf61be25234, mission-cddbd2cddca0 and mission-9b6156331681. That's 14 + 6 + 5 + 5 findings, all fixed. The final round gated the code SHIP. Each protection was removed in turn and fails at least one test.
Tests
🤖 Generated with Claude Code
https://claude.ai/code/session_014y3qC1m9acDVaerca56dvV