Skip to content

rewrite: record the CLOSE-aborts-read decision the port already makes #957

Closed

Description

@chappie-daemon

The port aborts an in-flight stored read when a CLOSE arrives (crates/nostream-relay/src/handlers/unsubscribe.rs:11-14). The TypeScript capture does not: UnsubscribeMessageHandler only emits Unsubscribe, which reaches onUnsubscribed → subscriptions.delete(id) (src/handlers/unsubscribe-message-handler.ts:9-10, src/web-socket-adapter.ts:107-110), and its read keeps running.

No decision record covers this. docs/rewrite/decisions/0001–0004 mention CLOSE only in the transport frame list (0004-wire-transport.md:105) and id-ordering (:238). The repo rule is that the TypeScript file wins when the two disagree unless a decision record says otherwise, so the port currently holds an unrecorded deviation.

Why it surfaced. Job 010's recon found that #951's defect — a CLOSE during the invite mint losing the abort for the whole stored read and its EOSE — is worse in Rust precisely because Rust aborts on CLOSE. Fixing that defect restores the port's own rule and needs no decision. But the rule itself is a deviation, and a defect job is not the place to legitimise it.

The wire oracle cannot decide it

Of the 16 recorded sessions in crates/nostream-relay/tests/fixtures/wire-sessions.json, three contain CLOSE (sessions 1, 2, 6 — e.g. req-close-abort: ["REQ","c1",{…}] → EOSE, then ["CLOSE","c1"] → no frame), and none closes while a read is still streaming. Replaying them cannot tell "aborted" from "already finished".

What this needs

  1. A decision record stating whether CLOSE aborts an in-flight read. This is a maintainer decision; the port and the NIP-01 reading both favour aborting, which is an argument for recording the deviation rather than removing it.
  2. If the port keeps aborting: a captured or synthetic fixture that closes mid-stream, so the oracle can decide it — until then the behaviour is asserted only by unit tests.

Related

  • The capture's invite emit is likewise unguarded (src/handlers/subscribe-message-handler.ts:111), and the port matches it deliberately. Guarding it would be a second unrecorded deviation; the same record should say so, or the two should be decided together.
  • relay: CLOSE during an invite mint is lost, and frames follow the close #951 fixes the lost abort without touching this question.

Activity

  1. added
    documentationImprovements or additions to documentation
    rewritenostream 4.0 Rust/LMDB rewrite
    rustRust implementation work
    on Oct 24, 2026
  2. chappie-daemon commented on Nov 1, 2026

    @chappie-daemon
    CollaboratorAuthor

    Closed by bf1d51ed (PR #988), verified in the tree: git merge-base --is-ancestor bf1d51ed rewrite/main returns 0.

    Closed by hand rather than by the PR's Closes keyword: GitHub only auto-closes on merge when the pull request targets the repository's default branch, and cameri/nostream's default is main while this PR targeted rewrite/main. The keyword was decoration and the issue stayed open after the merge.

    Every factory job landing on the rewrite now closes its own issue with gh issue close <n> --reason completed and reads the state back as CLOSED, never trusting the PR body.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationrewritenostream 4.0 Rust/LMDB rewriterustRust implementation work

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions