Skip to content

fix(transport): mirror request wrap kind in routeTargeted responses - #79

Merged
ContextVM-org merged 4 commits into
masterfrom
fix/route-targeted-mirror-wrap-kind
Aug 19, 2026
Merged

fix(transport): mirror request wrap kind in routeTargeted responses#79
ContextVM-org merged 4 commits into
masterfrom
fix/route-targeted-mirror-wrap-kind

Conversation

@ContextVM-org

Copy link
Copy Markdown
Contributor

routeTargeted() chose the gift-wrap kind without consulting the wrap kind recorded for the client's request event, while route() mirrors it on both send paths. A targeted response (e.g. explicit-gating -32042/-32043 errors) could therefore answer an ephemeral-wrapped request (kind 21059) with a relay-stored gift wrap (kind 1059) in GiftWrapMode.OPTIONAL when the session lacks the ephemeral capability tag.

Look up the recorded wrap kind via a non-destructive getEventRoute() and pass it as fallbackWrapKind, matching route()'s policy. Callers passing an unknown event ID degrade to the previous default.

routeTargeted() chose the gift-wrap kind without consulting the wrap kind
recorded for the client's request event, while route() mirrors it on both
send paths. A targeted response (e.g. explicit-gating -32042/-32043
errors) could therefore answer an ephemeral-wrapped request (kind 21059)
with a relay-stored gift wrap (kind 1059) in GiftWrapMode.OPTIONAL when
the session lacks the ephemeral capability tag.

Look up the recorded wrap kind via a non-destructive getEventRoute() and
pass it as fallbackWrapKind, matching route()'s policy. Callers passing
an unknown event ID degrade to the previous default.
sendNotification() and the CEP-22 accept frame chose the gift-wrap kind
without the request's wrap kind, so progress notifications and oversized
accept frames answered an ephemeral-wrapped request (kind 21059) with a
relay-stored gift wrap (kind 1059) in GiftWrapMode.OPTIONAL when the
session lacks the ephemeral capability tag — the same divergence fixed
for routeTargeted().

- sendNotification() mirrors via the correlated request's route and
  accepts an explicit wrapKindHint for callers without a route yet
- the oversized accept frame threads the inbound request's wrap kind
  through that hint (no route exists at start-frame time)
- route()'s send-failure re-register restores the full route, including
  the signed request event exposed via getNostrRequestEvent()

Adds a path-agnostic invariant e2e: a raw ephemeral-wrapped client with
no capability tags never receives a persistent (1059) wrap in OPTIONAL
mode, across response, notification, and targeted forms.
- extract mirrorRequestWrapKind() into capability-negotiator and replace
  the two hand-rolled ternaries in the inbound coordinator (identical
  semantics: policy pins win, otherwise mirror the request's kind)
- add a debug tripwire in sendMcpMessage when an OPTIONAL-mode encrypted
  send carries no wrap-kind hint, so future unmirrored send paths are
  grep-visible in debug logs
- LruCache: evict correctly when the eldest key is falsy ('')
- delete unused isHex64()
@ContextVM-org
ContextVM-org merged commit cd6c66c into master Aug 19, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant