You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Source: multi-agent review of PR #16, perf verifier verdicts. 2026-08-13. M-anchor: M3 runway — the SSE engine sits directly on this path (one union-typed event per message on a hot loop); redesign lands before/with M3, gated on baselines from the performance test project (see the perf-infrastructure issue).
P1 · CONFIRMED · low-to-moderate now, high-plausibility M3 hot-loop concern — all seven generated union converters do JsonDocument.ParseValue(ref reader) then JsonSerializer.Deserialize(payload, typeInfo) (SessionMessageInfoJsonConverter.cs:35,56; emitted by UnionEmitter.cs:270-280): DOM materialization + second traversal per union level; nested assistant content/tool state multiplies. Verifier correction: the JsonElement overload does not necessarily re-encode text — the cost is DOM + second traversal, not string round-trip. Fix direction: benchmark a reader-based discriminator dispatch that avoids the DOM for known tags while preserving unknown-payload capture. Do NOT assume the discriminator is the first property — a robust design needs a copied reader or controlled buffering. Keep JsonDocument/clone for unknown carriers.
P5 · PLAUSIBLE · negligible-to-low now — per-node OpenCodeJsonContext.Default.GetTypeInfo(type) (SessionMessageInfoJsonConverter.cs:53-56) resolves through a cached Options.TryGetTypeInfo, not fresh metadata. Do not optimize speculatively; after P1, benchmark direct tag→JsonTypeInfo dispatch on representative nested M3 events. Stay source-generated and AOT-safe.
P3 · CONFIRMED · low now, medium for large one-shot payloads — Pipeline unconditionally buffers via ReadAsStringAsync (Pipeline.cs:92,146); success adapters parse and discard the UTF-16 string (RawBody is error-only); ResponseHeadersRead already means status is known pre-buffer. Fix direction: adapter-boundary redesign so declared success statuses can deserialize from the content stream while error statuses stay string-buffered (ADR-0007 RawBody contract survives). Not a one-liner — adapters currently take string rawBody. The M3 SSE engine gets its own streaming path and must not reuse the one-shot buffer.
P4 rider (very low): downgrade path triple-parse (ResponseAdapter.cs:84,90,99-102) — only if profiling justifies; correctness of the compatibility path outranks it.
The second review of PR #26 confirmed a third mechanism for this issue's benchmark-gated redesign (R2-14c): cursor-list success pages are validated element-by-element by NullElementRejectingListJsonConverter, then re-copied and re-scanned by the public envelope initializer's defensive copy (ListPayloadInput.CopyRejectingNullElements) — an O(n) copy + null re-scan per success page that every future list operation inherits. Candidate shape: an internal adoption path in EnvelopeEmitter (adapter-built success instances adopt the converter-validated list without the second copy) while the public init keeps its defensive copy for consumer-constructed instances. Same benchmark gate as the rest of this issue.
The 1ee8c30 review adds correctness requirements to P3's adapter-boundary rewrite; they belong here rather than in a parallel buffering issue.
Timeout scope
Every send uses ResponseHeadersRead, so HttpClient.Timeout stops governing once headers arrive. ReadBodyAsync receives only the caller token. A probe with a 50 ms client timeout, immediate headers, a blocked body, and a 500 ms caller token ran until the caller's 500 ms deadline.
The one-shot body must remain inside one overall timeout budget from send through consumption. Caller cancellation still passes through; timeout with an untouched caller token maps to OpenCodeTransportException. Open SSE bodies remain post-header timeout-exempt.
Success media type
The adapter receives only (status, rawBody), so a 200 health body under text/plain or without Content-Type is accepted as JSON success. P3 must preserve each operation's declared success media type and apply the chosen policy. Fail-closed recommendation: missing/different media is OpenCodeTransportException, compared case-insensitively after stripping parameters.
Ownership
The current one-shot response is disposed correctly, but no test observes response/content disposal on success, API error, malformed success, or cancellation. The new handoff must pin those paths while preserving ADR-0007 error RawBody and NoThrow behavior.
UTF-8 link
Malformed one-shot UTF-8 is currently replacement-decoded before STJ and can return corrupted typed data. Fold strict success-body decoding into this rewrite; the SSE half is tracked separately.
Execution trigger: Arc 6 with P3, before closing #23.
Scope correction from ADR-0014 / Q106 (7f771eb): retire the unimplemented one-shot strict-UTF-8 rider, the single-declared-materializer response-media validation rider, and the premise that generated model defensive copies must survive. Buffered JSON continues through HttpContent charset/BOM decoding; media remains a runtime dispatch key only when several materializers exist. Keep timeout budgeting, response ownership on every exit, reader-based known-union dispatch, raw error-body retention, and measured success-path representation work. #55 owns model/copy cleanup; this issue retains the remaining Arc 6 adapter/converter performance work.
Arc 6 shipped in fa6124d and passed hosted CI run 32374393085 on Linux, Windows, and macOS. Known tagged-union arms now scan a copied reader and deserialize the original reader once; only unknown carriers retain a JsonElement DOM. Declared one-shot successes use validated UTF-8 byte adapters while charset/BOM and malformed-UTF-8 replacement behavior remain compatible; errors stay decoded strings with RawBody under throw and NoThrow. The overall HttpClient timeout now covers finite body consumption, pending reads are disposed/observed on timeout or caller cancellation, and no-content successes skip body reads while retaining response ownership. Same-environment baseline -> final: deep union 41.99 us / 13.35 KB -> 37.54 us / 12.72 KB; GetMessage 45.970 us / 21.91 KB -> 39.728 us / 19.15 KB; ListMessages 46.859 us / 22.60 KB -> 43.593 us / 19.81 KB. Health allocation moved 2.08 -> 2.05 KB; no health throughput win is claimed. PublicApi and generated-manifest membership are unchanged; 1,413 local executions and the hosted matrix are green.
Activity
docs(agents): hand off the M2 close-out — Q91 research, fix batch, me…
fix(sdk): land the small confirmed review fold-ins
Blind-Striker commentedon Aug 15, 2026
The second review of PR #26 confirmed a third mechanism for this issue's benchmark-gated redesign (R2-14c): cursor-list success pages are validated element-by-element by
NullElementRejectingListJsonConverter, then re-copied and re-scanned by the public envelope initializer's defensive copy (ListPayloadInput.CopyRejectingNullElements) — an O(n) copy + null re-scan per success page that every future list operation inherits. Candidate shape: an internal adoption path inEnvelopeEmitter(adapter-built success instances adopt the converter-validated list without the second copy) while the public init keeps its defensive copy for consumer-constructed instances. Same benchmark gate as the rest of this issue.Blind-Striker commentedon Aug 17, 2026
The
1ee8c30review adds correctness requirements to P3's adapter-boundary rewrite; they belong here rather than in a parallel buffering issue.Timeout scope
Every send uses
ResponseHeadersRead, soHttpClient.Timeoutstops governing once headers arrive.ReadBodyAsyncreceives only the caller token. A probe with a 50 ms client timeout, immediate headers, a blocked body, and a 500 ms caller token ran until the caller's 500 ms deadline.The one-shot body must remain inside one overall timeout budget from send through consumption. Caller cancellation still passes through; timeout with an untouched caller token maps to
OpenCodeTransportException. Open SSE bodies remain post-header timeout-exempt.Success media type
The adapter receives only
(status, rawBody), so a 200 health body undertext/plainor withoutContent-Typeis accepted as JSON success. P3 must preserve each operation's declared success media type and apply the chosen policy. Fail-closed recommendation: missing/different media isOpenCodeTransportException, compared case-insensitively after stripping parameters.Ownership
The current one-shot response is disposed correctly, but no test observes response/content disposal on success, API error, malformed success, or cancellation. The new handoff must pin those paths while preserving ADR-0007 error
RawBodyandNoThrowbehavior.UTF-8 link
Malformed one-shot UTF-8 is currently replacement-decoded before STJ and can return corrupted typed data. Fold strict success-body decoding into this rewrite; the SSE half is tracked separately.
Execution trigger: Arc 6 with P3, before closing
#23.Blind-Striker commentedon Aug 17, 2026
Scope correction from ADR-0014 / Q106 (7f771eb): retire the unimplemented one-shot strict-UTF-8 rider, the single-declared-materializer response-media validation rider, and the premise that generated model defensive copies must survive. Buffered JSON continues through HttpContent charset/BOM decoding; media remains a runtime dispatch key only when several materializers exist. Keep timeout budgeting, response ownership on every exit, reader-based known-union dispatch, raw error-body retention, and measured success-path representation work. #55 owns model/copy cleanup; this issue retains the remaining Arc 6 adapter/converter performance work.
Blind-Striker commentedon Aug 20, 2026
Arc 6 shipped in fa6124d and passed hosted CI run 32374393085 on Linux, Windows, and macOS. Known tagged-union arms now scan a copied reader and deserialize the original reader once; only unknown carriers retain a JsonElement DOM. Declared one-shot successes use validated UTF-8 byte adapters while charset/BOM and malformed-UTF-8 replacement behavior remain compatible; errors stay decoded strings with RawBody under throw and NoThrow. The overall HttpClient timeout now covers finite body consumption, pending reads are disposed/observed on timeout or caller cancellation, and no-content successes skip body reads while retaining response ownership. Same-environment baseline -> final: deep union 41.99 us / 13.35 KB -> 37.54 us / 12.72 KB; GetMessage 45.970 us / 21.91 KB -> 39.728 us / 19.15 KB; ListMessages 46.859 us / 22.60 KB -> 43.593 us / 19.81 KB. Health allocation moved 2.08 -> 2.05 KB; no health throughput win is claimed. PublicApi and generated-manifest membership are unchanged; 1,413 local executions and the hosted matrix are green.