Skip to content

fix(responses): bound the streaming citation marker span (carry #3843) - #3868

Merged
lidge-jun merged 4 commits into
devfrom
codex/rt-m4-3843
Sep 7, 2026
Merged

fix(responses): bound the streaming citation marker span (carry #3843)#3868
lidge-jun merged 4 commits into
devfrom
codex/rt-m4-3843

Conversation

@lidge-jun

@lidge-jun lidge-jun commented Sep 7, 2026

Copy link
Copy Markdown
Owner

Summary

Carries #3843 by @luvs01: the streaming citation-marker filter retains at most 4096 characters for an unterminated START. Adds the fix for the unresolved major finding (discussion_r3946034145): START-delimited segments are now walked independently, so an oversized malformed span followed by a valid marker in the same delta is emitted verbatim instead of being paired with the later END and dropped.

(carried/reimplemented from #3843; Co-authored-by trailer in the commit)

Verification

  • Regression: tests/responses/citation-markers.test.ts (existing bound/recovery tests plus the new same-delta case) runs in the chain-top CI.
  • Local checks NOT RUN by maintainer instruction.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

Manual review chain (integrate bottom-up; stack: null, no native stack)

Layer Branch Base Source
1 codex/rt-m1-3532 dev #3532 (Ingwannu)
2 codex/rt-m2-3840 layer 1 #3840 (chilung-cgu)
3 codex/rt-m3-3837 layer 2 #3837 (luvs01) + test isolation fix
4 codex/rt-m4-3843 layer 3 #3843 (luvs01) + same-delta fix
5 codex/rt-m5-3845 layer 4 #3845 (luvs01)
6 codex/rt-m6-2033 layer 5 #2033 (louis-tepe) reimplemented — chain top

Verification policy (maintainer instruction, this train): local test suite / typecheck / build were NOT RUN; branches pushed with --no-verify. Lower layers carry [skip ci]; the full Cross-platform CI (lane=all, Windows shards included) runs once at the chain top head and is the exact-head evidence for the cumulative tree.

Layer 4 of 6. Review this PR's diff only.


Maintainer integration decision (MAINTAINERS.md, dev-only admin integration): @lidge-jun integrates this manual chain into dev bottom-up. Exact chain-top evidence: Cross-platform CI run 34106345180 at head 6eadb1658 (lane=all: Linux 4/4, macOS 2/2 + control, Windows 6/6, gates, storage policy, api usage, keyring ×3, npm-global ×3, docker smoke, aggregate ci = success). Tested tree 7621cac89 equals the prospective merge tree of origin/dev@ece556a6e + chain top. Independent chain review PASS; #3845 security review PASS (see #3869). Local suites NOT RUN by maintainer instruction. This is maintainer integration, not self-approval. Lower-layer PR runs are skipped/cancelled by design ([skip ci]); they are not passing evidence on their own.

luvs01 and others added 4 commits September 7, 2026 18:17
`debugProviderDiagnostic` already returns early when provider debug is off,
but its argument object is built by the caller first. The Kiro request path
therefore ran `new TextEncoder().encode(body).length` over the entire
serialized request body on every request, including when diagnostics were
disabled, and then discarded the result inside the callee.

Wrap the diagnostic call in `isDebugEnabled()` so the details are only
constructed when they can actually be emitted. `src/adapters/openai-chat.ts`
already guards its diagnostics the same way.

The regression asserts that building a request performs no `TextEncoder`
encode over the serialized payload while diagnostics are off; it fails
without the guard and passes with it.

(cherry picked from commit d5d711a)

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
…ate reads [skip ci]

Resolves the maintainer objection on #3837 (discussion_r3945935220): the
shared setup cleared only OCX_DEBUG_FRAMES, so an inherited OCX_DEBUG=1 or a
runtime debug override made the encoder-spy test fail legitimately. Snapshot
OCX_DEBUG, OCX_DEBUG_FRAMES and the runtime override in beforeEach, clear
them, and restore the exact previous values in afterEach.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
(cherry picked from commit 8ef77f7)

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
…er marker in the same delta [skip ci]

Resolves the unresolved major finding on #3843 (discussion_r3946034145):
lastIndexOf selected the later START, its END made the whole-string strip
pair the first START with that END, and the malformed text vanished. Walk
START-delimited segments independently so a superseded or over-bound span is
emitted verbatim and only a bounded trailing span is held for the next delta.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
@lidge-jun
lidge-jun requested a review from Ingwannu as a code owner September 7, 2026 09:24
@coderabbitai

coderabbitai Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (2)
  • ^dev$
  • ^preview$

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Team

Run ID: b10bc1fa-478f-484b-a22d-9f4b4613b05b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 7, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-07T09:30:15.634771Z 00b74c7 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions github-actions Bot added the bug Something isn't working label Sep 7, 2026
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 00b74c7200

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +114 to +116
// Superseded by a later START, or over the bound: ordinary text, emitted verbatim
// so neither the retained text nor the per-delta rescan grows without limit.
out += segment;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep terminal text consistent with streamed deltas

When an over-limit unterminated START is followed by a valid marker, this branch emits the malformed segment verbatim, but src/bridge.ts:615 still constructs every terminal event by running the raw accumulated text through stripCitationMarkers(). That whole-string parser pairs the malformed START with the later marker's END, so the deltas contain the retained text while response.output_text.done, content_part.done, and output_item.done omit it; clients can therefore replace visible output or save a truncated transcript. Build the terminal text from the same segmented filtering result (or give the whole-string stripper identical semantics) and cover this case through bridgeToResponsesSSE, not only the standalone filter.

AGENTS.md reference: AGENTS.md:L367-L370

Useful? React with 👍 / 👎.

@lidge-jun

Copy link
Copy Markdown
Owner Author

리뷰 · 우선순위 61 / 80

이 PR은 기여자 #3843(luvs01)을 릴리스 트레인 레이어 4(codex/rt-m4-3843, base codex/rt-m3-3837)로 옮긴 캐리입니다. 지금 dev HEAD ece556a6ecreateCitationMarkerFilter는 아직 lastIndexOf(START)로 마지막 열린 구간만 보고, 길이 상한도 없습니다. 백엔드가 START만 보내고 END를 안 주면 held가 응답 끝까지 커지고, 이후 델타마다 그 접두사를 다시 스캔합니다. 더 위험한 경우는 같은 델타 안에 과대 malformed START 뒤에 정상 마커가 올 때입니다. 예전 로직은 앞쪽 START와 뒤쪽 END를 한 쌍으로 묶어 stripCitationMarkers로 통째로 지워 버릴 수 있었습니다. 리뷰에서 지적된 major(discussion_r3946034145)가 바로 그 지점이고, 이 캐리는 그 수정도 포함합니다.

새 구현은 MAX_STREAMING_MARKER_SPAN_LENGTH = 4096을 두고 START 구간을 앞에서부터 하나씩 걷습니다. 구간 안에 END가 있으면 그 마커만 버리고 뒤를 이어 붙입니다. END가 없고 다음 START도 없으며 길이가 상한 이하면 held에 남겨 다음 델타를 기다립니다. 다음 START에 밀렸거나 상한을 넘으면 malformed 일반 텍스트로 보고 그대로 방출합니다. 그래서 과대 스팬이 메모리를 잡아먹지 않고, 뒤에 오는 정상 인용 마커는 독립적으로 제거됩니다. 실제 인용 스팬은 cite와 turn id 몇 개라 4096이면 넉넉하고, 상한은 DoS/재스캔 방어용입니다.

테스트 세 개가 계약을 잠급니다. (1) 미종료 스팬에 x를 5000자 붙이면 전부 방출되고 flush()는 빈 문자열. (2) 과대 malformed 뒤에 새 START+정상 END가 오면 malformed는 남고 정상 마커만 제거. (3) 같은 델타 안에 span(이미 파일 상단 상수) + 과대 malformed + 정상 마커가 섞여도 malformed는 살아남고 정상만 빠집니다. span 심볼은 테스트 파일에 이미 정의되어 있어 깨지지 않습니다. 체인 top CI가 누적 증거이고 로컬은 미실행인 정책은 PR에 명시되어 있습니다. types/config 분할과 무관합니다.

동작 미묘한 점 하나: START가 전혀 없을 때 예전 코드는 stripCitationMarkers(combined)를 호출했고, 지금은 combined를 그대로 반환합니다. 실제 인용 문법은 START로 열리므로 실질 차이는 거의 없고, 세그먼트 walk가 완전한 스팬을 직접 제거하므로 경로가 단순해졌습니다. 다만 END만 단독으로 오는 기형 입력까지 예전 strip에 의존하던 가정이 있었다면 그 경로만 달라집니다. 현실 트래픽에서는 문제 될 가능성은 낮습니다.

src/responses/citation-markers.ts MAX_STREAMING_MARKER_SPAN_LENGTH - 미종료 START 보류 상한 4096. 넘어가면 방출.

src/responses/citation-markers.ts push START 세그먼트 walk - 과대/앞선 malformed가 뒤 END와 짝지어져 통째로 지워지던 major를 제거.

tests/responses/citation-markers.test.ts 상한 방출 / 이후 정상 스팬 / same-delta 생존 - 회귀 세 축을 직접 잠금.

메인테이너의 판단이 필요한 지점

  • 4096이 프로덕션에 충분한지, 더 작게(예: 512) 줄일지
  • START 없는 경로에서 stripCitationMarkers 제거를 그대로 둘지, 방어적으로 한 줄 남길지
  • 랜딩 후 원본 #3843을 바로 landed-via-maintainer로 닫을지, 트레인 전체 후 일괄 닫을지

너의 추천
레이어 4로 머지하세요. 상한과 same-delta 수정이 핵심이고 테스트가 그 major를 직접 잠급니다. 머지 후 원본 #3843에 Landed via #3868 at <commit> + landed-via-maintainer로 닫으세요.

이 댓글은 grok-bot이 작성했습니다

@lidge-jun
lidge-jun changed the base branch from codex/rt-m3-3837 to dev September 7, 2026 10:10
@lidge-jun
lidge-jun merged commit 99451df into dev Sep 7, 2026
8 of 9 checks passed
@lidge-jun
lidge-jun deleted the codex/rt-m4-3843 branch September 7, 2026 10:10
lidge-jun pushed a commit that referenced this pull request Sep 7, 2026
…treaming filter

After #3868 the streaming filter keeps a malformed START verbatim when a
later START opens a real span, but stripCitationMarkers still paired the
first START with that later span's END and deleted everything between.
bridge.ts re-strips the accumulated text for output_text.done and
output_item.done, so the terminal text disagreed with the concatenated
deltas. Walk START-delimited segments in the whole-string path too, and
share the 4096 span bound with the whole-string path (an over-bound span that is terminated late is malformed text in both), and assert delta-vs-whole equality across several chunkings.

Found by the lane A fresh-base composition audit on dev d00615d.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
lidge-jun pushed a commit that referenced this pull request Sep 7, 2026
…treaming filter

After #3868 the streaming filter keeps a malformed START verbatim when a
later START opens a real span, but stripCitationMarkers still paired the
first START with that later span's END and deleted everything between.
bridge.ts re-strips the accumulated text for output_text.done and
output_item.done, so the terminal text disagreed with the concatenated
deltas. Walk START-delimited segments in the whole-string path too, and
share the 4096 span bound with the whole-string path (an over-bound span that is terminated late is malformed text in both), and assert delta-vs-whole equality across several chunkings.

Found by the lane A fresh-base composition audit on dev d00615d.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
lidge-jun pushed a commit that referenced this pull request Sep 7, 2026
…treaming filter

After #3868 the streaming filter keeps a malformed START verbatim when a
later START opens a real span, but stripCitationMarkers still paired the
first START with that later span's END and deleted everything between.
bridge.ts re-strips the accumulated text for output_text.done and
output_item.done, so the terminal text disagreed with the concatenated
deltas. Walk START-delimited segments in the whole-string path too, and
share the 4096 span bound with the whole-string path (an over-bound span that is terminated late is malformed text in both), and assert delta-vs-whole equality across several chunkings.

Found by the lane A fresh-base composition audit on dev d00615d.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
lidge-jun pushed a commit that referenced this pull request Sep 7, 2026
…treaming filter

After #3868 the streaming filter keeps a malformed START verbatim when a
later START opens a real span, but stripCitationMarkers still paired the
first START with that later span's END and deleted everything between.
bridge.ts re-strips the accumulated text for output_text.done and
output_item.done, so the terminal text disagreed with the concatenated
deltas. Walk START-delimited segments in the whole-string path too, and
share the 4096 span bound with the whole-string path (an over-bound span that is terminated late is malformed text in both), and assert delta-vs-whole equality across several chunkings.

Found by the lane A fresh-base composition audit on dev d00615d.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants