Skip to content

fix(codex): retain overlapping multiline TOML terminators - #4039

Closed
luvs01 wants to merge 1 commit into
lidge-jun:devfrom
luvs01:agent/toml-overlapping-terminator-20260908
Closed

fix(codex): retain overlapping multiline TOML terminators#4039
luvs01 wants to merge 1 commit into
lidge-jun:devfrom
luvs01:agent/toml-overlapping-terminator-20260908

Conversation

@luvs01

@luvs01 luvs01 commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Summary

A valid TOML multiline basic string ending with an escaped quote immediately followed by its closing delimiter can hide the real provider/profile settings on subsequent lines from project-config diagnostics. For example, a backslash followed by four quotes represents one escaped quote and the three-quote terminator. The scanner rejects the first overlapping candidate but skips all three characters, missing the actual terminator one character later. Subsequent configuration is then incorrectly treated as string content.

Search the next candidate one character later after rejecting an escaped delimiter. Keep provider examples inside an unfinished string ignored, while restoring the existing warnings and effective-provider resolution for real settings after the string. The focused regressions cover root overrides, a same-line multiline string, a selected profile, and a selected provider table; a negative control keeps fake routing inside an escaped three-quote string body. English/Korean lifecycle documentation describes this diagnostic behavior. The change adds no settings or new warning types.

Verification

  • Head 7ce4dac80b5cc81e9f1eb1a9dbb4751f8dbe544c, based on dev 7dc7dc99e65268bc8764e19840952256b030bce9; Bun 1.4.0 on Windows.
  • Before the runtime fix, all four positive regressions failed to recover the expected provider, while the negative control passed. Each fixture is independently parsed by Bun.TOML.parse, including the actual escaped-quote string value. This follows the TOML 1.0 multiline basic-string syntax.
  • bun run test -- --timeout 60000 --parallel=1 tests/codex-integration/project-config-warnings.test.ts: 26 tests / 59 assertions passed. Assertions cover effective provider, warning code/detail/profile, and provider-table contents, rather than only the internal string boundary.
  • Existing tests/codex-integration/codex-legacy-config-keys.test.ts, another direct parser consumer: 12 tests / 43 assertions passed.
  • bun run typecheck, bun run privacy:scan, and git diff --check passed. An independent read-only review found no required corrections.
  • docs-site build passed: 425 pages, 21.38 seconds. Both new paragraphs were verified in generated HTML without opening a preview. Existing dependency assets were reused only after matching their lockfile hash and declared dependencies.
  • CodeRabbit reviewed current head 7ce4dac80 and found no blocking findings after checking the parser state, diagnostic consumers, and positive/negative regressions. No inline findings are outstanding at this update. Full contributor CI completed successfully: 26/26 jobs, including all six Windows shards and the macOS control, on this exact head. Current dev remains 7dc7dc99e.

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.

Review readiness checklist

  • All CI tests are green on my local testing.
  • I pushed my PR to the latest dev commit.
  • I resolved all correct Codex and CodeRabbit findings.
  • My PR is ready for review.

@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: d870fe26-8864-48db-b31d-6dcb1fedb4c8

📥 Commits

Reviewing files that changed from the base of the PR and between 7dc7dc9 and 7ce4dac.

📒 Files selected for processing (4)
  • docs-site/src/content/docs/ko/reference/cli/lifecycle.md
  • docs-site/src/content/docs/reference/cli/lifecycle.md
  • src/codex/project-config-warnings.ts
  • tests/codex-integration/project-config-warnings.test.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 8 remain after this review.


📝 Walkthrough

Walkthrough

The parser now handles overlapping escaped quotes and multiline TOML terminators correctly. Integration tests cover routing diagnostics and escaped content. English and Korean CLI documentation describe the parsing behavior.

Changes

Multiline TOML diagnostics

Layer / File(s) Summary
Overlapping delimiter parsing and validation
src/codex/project-config-warnings.ts, tests/codex-integration/project-config-warnings.test.ts
multilineCloseIndex checks overlapping delimiter candidates after rejecting escaped quotes. Tests cover root, profile, provider, and multiline-content cases.
CLI diagnostic documentation
docs-site/src/content/docs/reference/cli/lifecycle.md, docs-site/src/content/docs/ko/reference/cli/lifecycle.md
The lifecycle references document how project-config diagnostics handle provider examples inside TOML multiline strings and settings after the closing delimiter.

Priority: ⬇️ Low — Defer this TOML scanner fix because it narrowly restores project-config diagnostics for overlapping multiline delimiters, with documentation and regression-test updates.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 7ce4d

This fixes project configuration diagnostics after multiline TOML strings containing an escaped quote before the closing delimiter, while preserving examples inside strings as ignored content. The covered parsing and diagnostic behavior is ready to merge.

Suggested reviewers: lidge-j

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 2 files. (2 skipped: 2 … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main fix: preserving overlapping multiline TOML terminators in the Codex configuration scanner.
Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 2 files. (2 skipped: 2 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

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

luvs01 commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please review head 7ce4dac80b5cc81e9f1eb1a9dbb4751f8dbe544c against 7dc7dc99e65268bc8764e19840952256b030bce9, focusing on escaped multiline basic-string delimiters and downstream project-config diagnostics.

The runtime change advances only one character after an escaped delimiter candidate, preserving an overlapping real terminator. Four regressions failed before the fix and now pass; Bun's TOML parser independently validates the fixtures. The negative control ensures escaped three quotes do not expose fake routing in the string body. Existing diagnostics and legacy-key parser consumers pass 38 tests / 102 assertions in total. Typecheck, privacy scan, diff check, independent read-only review, and the documentation build passed. Full cross-platform CI remains separate and pending.

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

✅ READY

  • all PR quality gates passed; the review readiness checklist is complete.

Review readiness checklist

  • ✅ All CI tests are green on my local testing.
  • ✅ I pushed my PR to the latest dev commit.
  • ✅ I resolved all correct Codex and CodeRabbit findings.
  • ✅ My PR is ready for review.

4/4 boxes ticked.

This pull request has been marked Ready for Review.
The review-ready label marks this PR as ready; review automation runs independently.
Maintainers notified: @lidge-jun @Ingwannu

Hygiene

Deterministic PR hygiene checks passed.

@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base="7dc7dc99e65268bc8764e19840952256b030bce9"
head="7ce4dac80b5cc81e9f1eb1a9dbb4751f8dbe544c"

printf '%s\n' '=== Changed files ==='
git diff --name-status "$base" "$head"

printf '%s\n' '=== Diff (with function context) ==='
git diff --find-renames --find-copies --unified=80 "$base" "$head"

printf '%s\n' '=== Outlines of changed code files ==='
git diff --name-only "$base" "$head" \
  | grep -E '\.(ts|tsx|js|jsx|mjs|cjs)$' \
  | while IFS= read -r file; do
      echo "--- $file"
      ast-grep outline "$file" --items all || true
    done

Length of output: 35338


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '=== Project-config parser and diagnostic flow ==='
nl -ba src/codex/project-config-warnings.ts | sed -n '45,325p'

printf '%s\n' '=== Full affected test section ==='
nl -ba tests/codex-integration/project-config-warnings.test.ts | sed -n '1,285p'

printf '%s\n' '=== Direct parser and scanner references ==='
rg -n -C 3 --glob '*.ts' \
  '\b(parseTomlDocument|resolveEffectiveProjectModelProvider|analyzeProjectCodexConfig|multilineCloseIndex|multilineStateAfterLine)\s*\(' \
  src tests

printf '%s\n' '=== Static delimiter-candidate model ==='
python3 - <<'PY'
def close_index(line, start=0):
    delimiter = '"""'
    index = line.find(delimiter, start)
    while index >= 0:
        backslashes = 0
        cursor = index - 1
        while cursor >= 0 and line[cursor] == '\\':
            backslashes += 1
            cursor -= 1
        if backslashes % 2 == 0:
            return index
        index = line.find(delimiter, index + 1)
    return -1

for slash_count in range(0, 5):
    for quote_count in range(3, 8):
        line = '\\' * slash_count + '"' * quote_count
        print(f"slashes={slash_count}; quotes={quote_count}; close={close_index(line)}; repr={line!r}")
PY

Length of output: 1626


🏁 Script executed:

#!/bin/bash
set -euo pipefail

numbered_range() {
  local file="$1"
  local start="$2"
  local end="$3"
  awk -v start="$start" -v end="$end" 'NR >= start && NR <= end { printf "%6d\t%s\n", NR, $0 }' "$file"
}

printf '%s\n' '=== Project-config parser and diagnostic flow ==='
numbered_range src/codex/project-config-warnings.ts 45 325

printf '%s\n' '=== Full affected test section ==='
numbered_range tests/codex-integration/project-config-warnings.test.ts 1 285

printf '%s\n' '=== Direct parser and scanner references ==='
rg -n -C 3 --glob '*.ts' \
  '\b(parseTomlDocument|resolveEffectiveProjectModelProvider|analyzeProjectCodexConfig|multilineCloseIndex|multilineStateAfterLine)\s*\(' \
  src tests || true

printf '%s\n' '=== Static delimiter-candidate model ==='
python3 - <<'PY'
def close_index(line, start=0):
    delimiter = '"""'
    index = line.find(delimiter, start)
    while index >= 0:
        backslashes = 0
        cursor = index - 1
        while cursor >= 0 and line[cursor] == '\\':
            backslashes += 1
            cursor -= 1
        if backslashes % 2 == 0:
            return index
        index = line.find(delimiter, index + 1)
    return -1

for slash_count in range(0, 5):
    for quote_count in range(3, 8):
        line = '\\' * slash_count + '"' * quote_count
        print(f"slashes={slash_count}; quotes={quote_count}; close={close_index(line)}; repr={line!r}")
PY

Length of output: 42201


@luvs01 Reviewed head 7ce4dac80b5cc81e9f1eb1a9dbb4751f8dbe544c against 7dc7dc99e65268bc8764e19840952256b030bce9.

I found no blocking findings.

src/codex/project-config-warnings.ts Line 74 now advances by one character after an escaped """ candidate. For \"""", this rejects the candidate that starts at the escaped quote and then detects the real overlapping terminator at the next quote. The change is limited to multiline basic strings. Multiline literal strings remain unchanged.

The scanner state flows correctly into parseTomlDocument() at Lines 142-167. Later root keys and tables become visible after the valid terminator. resolveEffectiveProjectModelProvider() at Lines 204-225 and analyzeProjectCodexConfig() at Lines 262-303 then preserve the expected provider resolution and warning selection.

The added tests in tests/codex-integration/project-config-warnings.test.ts cover root overrides, a same-line terminator, selected profiles, and selected provider tables at Lines 133-160. The negative control at Lines 163-174 confirms that an escaped three-quote sequence keeps provider-like content inside the multiline string.

I also checked direct parser consumers in src/codex/legacy-config-keys.ts and src/codex/inject.ts. The parser contract remains compatible with those call paths.

I could not execute repository tests in this sandbox. This review is based on static inspection and the verification results in the PR description.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@lidge-jun

Copy link
Copy Markdown
Owner

리뷰 · 우선순위 70 / 80

이 PR은 Codex 프로젝트 설정 진단용 간이 TOML 스캐너(src/codex/project-config-warnings.tsmultilineCloseIndex)가 멀티라인 basic string 끝에서 이스케이프된 따옴표와 종료 구분자 """가 겹칠 때 진짜 종료 위치를 놓치는 버그를 고칩니다. 지금 dev HEAD 7dc7dc99e에서는 거절된 후보를 index + delimiter.length(즉 +3)로 건너뛰기 때문에, 본문이 백슬래시 다음에 따옴표 네 개(이스케이프된 따옴표 + 실제 종료 """)인 줄에서 종료를 못 찾고, 그 뒤의 model_provider / [profiles.*] / [model_providers.*]를 문자열 본문으로 삼켜 버립니다. 그러면 analyzeProjectCodexConfig / resolveEffectiveProjectModelProvider가 실제 라우팅을 못 보고, 있어야 할 model_provider_root·profile_selector·model_providers_table 경고도 안 나옵니다.

왜 지금 dev에서 가치가 있을까요. tip은 #4037 provider-runtime 스택 기록이고, 코드 tip은 #4031 쪽입니다. 그와 별개로 HEAD에는 이미 #3553 legacy config diagnostics 강화가 들어와 있고, doctor/lifecycle 문서가 프로젝트 설정 진단을 사용자에게 설명합니다. 이 구멍은 “문자열 안의 예시 provider는 무시한다”는 의도(올바른 쪽)와 “문자열이 끝난 뒤의 실제 설정은 검사한다”는 계약을 동시에 깨뜨립니다. 고치는 코드는 한 줄에 가깝습니다. index + delimiter.lengthindex + 1로 overlapping 후보를 다시 보게 합니다. ''' literal은 이스케이프가 없어서 기존 delimiter === '"""' 가드 안에만 루프가 도는 구조와 잘 맞습니다.

테스트는 tests/codex-integration/project-config-warnings.test.ts에 root / same-line / selected profile / selected provider table 네 긍정 회귀와, 본문 안에 이스케이프된 따옴표 세 개만 있고 진짜 종료는 다음 줄인 부정 통제를 넣었습니다. 각 fixture를 Bun.TOML.parse로 독립 검증한 점도 좋습니다. 영·한 docs-site/.../reference/cli/lifecycle.md에 진단 동작을 한 단락씩 보강했습니다. types.ts/config.ts 대분할과 무관해서 close-don't-rebase 대상이 아닙니다. draft이고 작성자 보고 테스트는 통과, enforce-target/hygiene도 현재 그린입니다.

라인 72 - HEAD의 index + delimiter.length가 overlapping 백슬래시+따옴표4개에서 진짜 종료를 건너뛴다. index + 1이 TOML 1.0 멀티라인 basic string과 맞다
경로/심볼 multilineCloseIndex - """만 escape 검사를 도는 기존 가드는 유지하는 편이 맞고, literal '''까지 넓힐 필요는 없다
경로/심볼 tests/codex-integration/project-config-warnings.test.ts - Bun.TOML.parse 교차검증 + 긍정 4 / 부정 1이 계약(본문 무시 vs 종료 후 진단)을 직접 고정한다
경로/심볼 lifecycle.md(영·한) - doctor가 “문자열 안 예시는 무시, 종료 뒤 설정은 검사”를 말하게 맞춘 문서 추가는 좋다
경로/심볼 draft - ready·전체 contributor CI 채우기 전에는 landing 트레인에 넣지 말 것

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

  • 이 진단 스캐너를 계속 유지할지, 장기적으로는 공용 TOML 파서에 더 기대고 간이 lexer를 줄일지
  • draft를 ready로 올리기 전에 Cross-platform / 전체 CI를 필수로 둘지
  • same-line developer_instructions처럼 실제 사용자 config에서 이 패턴이 체감 회귀인지(테스트는 커버함)

너의 추천
내용상 머지 가치가 높다. 작성자가 draft를 풀고 contributor CI가 그린이면 dev에 단독 버그픽스로 받아도 됩니다. 닫을 중복 원본 PR은 없고, types/config 분할과도 무관합니다.

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

@github-actions
github-actions Bot marked this pull request as ready for review September 8, 2026 15:12
lidge-jun added a commit that referenced this pull request Sep 8, 2026
* test(lib): make idle deadline reset timing deterministic

Carried from #4041 (author luvs01) for maintainer-side CI and sequential integration.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* test: stabilize Windows fixture waits and case cleanup

Carried from #4015 (author luvs01) for maintainer-side CI and sequential integration.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* test(codex): verify timeout termination without racing child timers

Carried from #4012 (author luvs01) for maintainer-side CI and sequential integration.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* test(codex): hold prompt-probe admission through document edits

Carried from #4014 (author luvs01) for maintainer-side CI and sequential integration.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* test(clients): bound transaction fixture child completion

Carried from #4004 (author luvs01) for maintainer-side CI and sequential integration.
Closes #4003

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(codex): retain overlapping multiline TOML terminators

Carried from #4039 (author luvs01) for maintainer-side CI and sequential integration.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(cli): reject unsupported caps and report ignored legacy values

Carried from #4043 (author luvs01) for maintainer-side CI and sequential integration.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(codex): share trigger-only delegation guidance with v1

Carried from #4034 (author luvs01) for maintainer-side CI and sequential integration.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(codex): preserve settings when journal injection hashes are missing

Carried from #4006 (author luvs01) for maintainer-side CI and sequential integration.
Closes #4005

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* docs(cli): note that --injection still accepts none and minimal

CodeRabbit review on #4049: the effort reference documents caps only, so the
new rejection of none/minimal reads as a global removal. --injection keeps
both values because it sets the injection effort rather than a cap.

---------

Co-authored-by: t <a@b.com>
Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
@lidge-jun

Copy link
Copy Markdown
Owner

Landed on dev in cfff026 via #4049, which carried all nine PRs of this train as one sequentially reviewed integration branch. Your commit is preserved in the squash body with a Co-authored-by trailer, so the contribution stays attributed to you.

Verification at the exact merged head 8c58bac0863f1f2ca2b430e1177a0e417b474c85: Cross-platform CI run 34256853348 finished with 19 jobs successful and 0 failures, bun x tsc --noEmit exit 0, and 312 focused tests passing across the ten affected files. An independent review confirmed the stacked tree is byte-identical to the union of the nine PR diffs.

Closing this PR because the change is already on dev. Thank you.

@lidge-jun lidge-jun closed this Sep 8, 2026
@lidge-jun

Copy link
Copy Markdown
Owner

Landed via #4049 at cfff026

@lidge-jun lidge-jun added the landed-via-maintainer Original PR closed after landing via a maintainer merge train label Sep 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working landed-via-maintainer Original PR closed after landing via a maintainer merge train review-ready

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants