Hand-written. ../harvested/sse-streaming.md is what the documents say; this file is what the
implementation found, and it wins. Each entry names the harvested entry it answers by that entry's
stable key.
- Only the BOM-consumed flag persists across
Reader#next_eventcalls; the last event id and the current retry value do not. Supersedessse-streaming/2dba42b0("The convenience view reuses one reader instance so per-stream state (consumed BOM, current retry value, last event id) is preserved across pulls"), harvested verbatim from design §7.2's parenthesis atdocs/sdk-design-ruby/07-pagination-sse-and-serialization.md:79-84.SSE-16is a MUST — "only the 'BOM already consumed' flag persists across calls; the last-event-id is NOT carried forward" — andSSE-38is a MUST that the subsystem "MUST NOT persist a last-event-id across events"; carrying a "current retry value" across events is forbidden by the same "only".SSE-40's own canonical text says "per-stream state (e.g. BOM consumption)" and names nothing else. The view does reuse one reader instance, which isSSE-40's actual clause; what that preserves is the BOM flag. Built that way on 2026-09-20:Dexpace::SSE::Readerresets all five accumulators — id, event, data, comment and retry — at every dispatch, andgems/dexpace-core/test/dexpace/sse/reader_test.rb'sDispatchTestasserts the two prohibitions directly ("nothing but the BOM flag persists across calls -- no carried retry value"; "no last-event-id is carried forward") beside the one persistence ("the BOM flag DOES persist"). review ·docs/work/mvp/phase7/phase7b/2026-09-10-phase7b-server-sent-events-design.md· high · sha:manual-phase7b-sse16-only-bom - The SSE line machine is built over
Dexpace::IO::BufferedSource#getbyte, not over phase 3a's#read_line_utf8, becauseIO-14andSSE-2disagree about a lone CR. Correctssse-streaming/8c25db7dandsse-streaming/e98a0668insofar as either reads as "the SSE machine sits on the hand-written line primitive": the reason both give is right — the primitive was hand-written rather than delegated toIO#getsbecauseSSE-2wants LF, CR and CRLF all recognised — but what phase 3a hand-wrote followsIO-14's grammar ("a lone'\r'not followed by'\n'MUST be kept as part of the line's content";gems/dexpace-core/lib/dexpace/io/typed_reads.rb,read_line_utf8("a\rb\n")is"a\rb"on every supported Ruby), andSSE-2requires that CR to terminate a line by itself. Post-processing a#read_line_utf8result cannot rescue it either: a conforming CR-only stream contains no\n, so the method would buffer the whole stream before returning anything — the read-aheadSSE-39forbids and the unbounded allocation the line cap exists to prevent. Built asDexpace::SSE::LineReader(phase 7b, P7-20), which recognises the three terminators natively with a one-byte pushback;#read_line_utf8ends v1 with no in-repository caller, and its YARD now says so. review ·docs/work/mvp/phase7/phase7b/2026-09-10-phase7b-server-sent-events-design.md· high · sha:manual-phase7b-line-reader-not-read-line-utf8
sse-streaming/5f4803a0andsse-streaming/b94ce49eareSSE-26andSSE-40's rules, filed underPAGE-14alone. Adds to both: the@viewedlatch on the SSE view — "must not be taken twice over the same source … latching a@viewedflag on first call and raising on a second" — and the conclusion that the single-use guard is a SHOULD the port implements outright are the Ruby realisation ofSSE-26andSSE-40's second clause, and--req SSE-26/--req SSE-40return neither; a pagination author queryingPAGE-14receives two SSE rules instead. A harvest attribution artefact of a design sentence that mentions a neighbouring ID, not a defect in the rules. Built asDexpace::SSE::Stream#take_view!(gems/dexpace-core/lib/dexpace/sse/stream.rb), one flag for both consumption shapes and the typed layer's, asserted instream_test.rb's andtyped_stream_test.rb'sViewTestclasses. review ·docs/work/mvp/phase7/phase7b/2026-09-10-phase7b-server-sent-events-checklist.md· high · sha:manual-phase7b-viewed-latch-attributionsse-streaming/dff112adisSSE-11's conclusion and notSSE-19's, andsse-streaming/7adc2212isSSE-12's and notSSE-11's. Adds to both: the first files the 2^31−1 millisecond retry cap under(SSE-11, SSE-19), so--req SSE-19returns an entry entirely about theretryfield and nothing about line length — the corpus-level origin of the line-cap finding's mis-citation, which phase 7b's design (R4) corrects: the requirement obliging the line cap isSSE-19, a MAY, andSSE-11is a MUST about the retry field's value. The second files the BOM lookahead under(SSE-12, SSE-11), the same artefact in the other direction. Built as two constants and two checklist rows:Dexpace::SSE::MAX_LINE_BYTES/MAX_EVENT_BYTES(SSE-19) andDexpace::SSE::MAX_RETRY_MS(SSE-11), each YARD stating which cap it is not. review ·docs/work/mvp/phase7/phase7b/2026-09-10-phase7b-server-sent-events-checklist.md· high · sha:manual-phase7b-cap-attributionEnumerator#nexton a fiber that died by exception starts#eachover. Adds tosse-streaming/4d83311b(SSE-29) and toio-and-byte-streams'.overrule: after aDexpace::IO::BufferedSource.over(chunked)has raised a mid-stream failure out of#getbyte, the NEXT#getbytedoes not answerniland does not raise a second time — the enumerator's fiber is dead,Enumerator#nextcreates a fresh one, and the body's#eachruns again from its first chunk, so the pull re-delivers the stream's first byte. Measured on 2026-09-20 on 3.2.11, 3.3.12, 3.4.10 and 4.0.6 (gems/dexpace-core/test/dexpace/sse/matrix_facts_test.rb, "after a mid-stream failure BufferedSource.over's enumerator RESTARTS instead of ending"). The SSE facade never meets it becauseSSE-27'sclosed?check runs before every pull and the facade closed itself on the failure; a bareReaderdriven again after a raise would. Phase 3a's residue, routed to phase 10's inbound list by phase 7b's checklist. review ·docs/work/mvp/phase7/phase7b/2026-09-10-phase7b-server-sent-events-checklist.md· high · sha:manual-phase7b-enumerator-restart