Skip to content

docs(devlog): assess what the dev tip closes of the pooled-routing cost incident (#4546) - #4969

Merged
lidge-jun merged 1 commit into
devfrom
codex/4546-dev-tip-closure-assessment
Sep 17, 2026
Merged

lidge-jun merged 1 commit into
devfrom
codex/4546-dev-tip-closure-assessment

Conversation

@lidge-jun

Copy link
Copy Markdown
Owner

Summary

#4546 has been reopened once already for being closed against partial work, and the record
of what it still covers is now spread across five issue comments and two devlog docs written
before cohort keying landed. This adds the closure assessment against the current dev tip so
the next person to look at the issue does not have to re-derive it.

The finding, in short: the cache-destruction half of #4546 is closed, and the token-burn half
is not — but not for the reason the issue says. Routing can no longer move a live conversation
for a quota preference (mayRebindAffinityForQuota defaults to a genuine-exhaustion bar), the
re-score interval is no longer short-circuited in the 80-99% band, preview agrees with resolve,
and cohort keying puts a whole conversation tree on one account. What remains is the reporter's
Phase 1: a fan-out of one-off requests whose prefixes are cold because each is a distinct
prompt, which no account-affinity rule can warm.

The doc names the remaining mechanism precisely. DEFAULT_SPEND_RESERVATION_POLICY leaves every
token ceiling undefined by design, and sharedSpendLedger() constructs the process-wide ledger
with no policy argument at all. There is no configureSharedSpendLedger and no spend key in
src/types/config.ts, so a SpendReservationPolicy carrying a real maxTokens is built in
exactly two places in the tree, both tests. Token enforcement cannot be switched on by any
configuration an operator can write, so the ledger measures the volume and never refuses it.
What is enforced is counts, and the doc checks those against the reporter's own figures: at
roughly 61 sends and 61 distinct children per ten-minute window, the measured incident passes
the 256-send and 64-child caps and is bounded by nothing on tokens.

It also records three things that are true and easy to mistake for defects: cohort keying now
deliberately concentrates a fan-out onto the interactive account (correct for cache locality,
and interactiveReserve reserves a concurrency slot rather than quota), the wpc domain
classifier in src/routing/identity-domains.ts is landed with config validation as its only
production consumer, and the synthetic cached_tokens: 0 on the bridged wire is a required
compatibility behaviour rather than dishonest accounting.

Docs only. No source, test, or configuration file changes.

Verification

Local verification was not run — no suite, focused test, typecheck, build, install, or ocx
invocation — because this lane forbids it. Hosted CI at the exact head of this branch is the
executable verification.

Every claim in the doc is a static source citation at dev@61ee64747b, and each one names the
file and line it rests on so a reviewer can check it by reading rather than by running anything.
The two load-bearing negative claims were established by exhaustive search rather than by
inspection of a single site: that no production caller passes a policy to
createSpendReservationLedger, and that the only production importer of
src/routing/identity-domains.ts is src/config/schema/leaf-validators.ts.

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.

@lidge-jun
lidge-jun requested a review from Ingwannu as a code owner September 17, 2026 22:57
@coderabbitai

coderabbitai Bot commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

Next included review available in 29 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 557103b3-a17a-4aea-bb6e-787550fa0d8b

📥 Commits

Reviewing files that changed from the base of the PR and between 61ee647 and 629a9ee.

📒 Files selected for processing (1)
  • devlog/_plan/260914_cost_guard_stabilization/100_dev_tip_closure_assessment.md

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 17, 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-17T23:00:51.635475Z 629a9ee 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.

@lidge-jun

Copy link
Copy Markdown
Owner Author

리뷰 · 우선순위 76 / 80

이 PR은 코드나 설정을 바꾸지 않습니다. 다시 열린 이슈 #4546이 지금 dev 끝(61ee647, #4948 cold status setup 측정, 패키지 2.59.0)에서 어디까지 닫혔는지 한 장으로 정리한 문서만 추가합니다. 파일은 devlog/_plan/260914_cost_guard_stabilization/100_dev_tip_closure_assessment.md 하나입니다.

지금 dev를 직접 읽어 보면, 문서의 한 줄 결론은 맞습니다. 캐시가 깨지는 쪽은 이미 닫혀 있습니다. mayRebindAffinityForQuota는 기본이 진짜 고갈(usage >= 100)이고, retainsBoundAccountForQuota → isCacheAffinityEnabled(pool.cacheAffinity !== false)라서 80–99% 구간에서는 산 대화를 옮기지 않습니다. pickCacheSafeQuotaReplacement는 더 시원한 계정만 고르고, CODEX_UNKNOWN_USAGE_SCORE(101) 때문에 측정 안 된 계정은 이기지 못합니다. reevaluateAffinityQuota는 재평가 간격과 재바인드 막대를 같은 조건에 묶어 두었고, previewReusableAffinityAccount도 같은 규칙을 탑니다. 코호트 키(#4935)는 한 대화 나무를 한 계정에 묶습니다.

토큰을 태우는 쪽은 아직 안 닫혔고, 이유는 라우팅이 아닙니다. DEFAULT_SPEND_RESERVATION_POLICY는 모든 토큰 한도를 비워 두고, sharedSpendLedger()는 policy 없이 장부를 만듭니다. configureSharedSpendLedger는 없고, src/types/config.ts에도 spend 키가 없습니다. 운영자가 쓸 수 있는 설정으로 토큰 거절을 켤 수 없습니다. 살아 있는 한도는 10분 창의 전송 256·자식 64·동시 자식 8뿐인데, 리포터 Phase 1 규모(~61 sends / ~61 children / 10분)는 그 한도 아래를 지나갑니다. interactiveReserve: 1은 동시성 자리만 남겨 두고 쿼터는 남기지 않습니다.

문서가 결함이 아니라고 적은 세 가지도 현재 트리와 맞습니다. 코호트가 팬아웃을 인터랙티브 계정에 모으는 것, identity-domains.ts가 사실상 leaf-validators 설정 검증에만 쓰이는 것, 브리지 와이어의 합성 cached_tokens: 0이 호환 강제라는 것입니다. 그래서 #4546은 처음 신고한 라우팅 결함 때문이 아니라, 차가운 입력 속도를 막을 설정 면이 없어서 열어 두자는 판단이 됩니다. 다음 일은 라우팅이 아니라 SpendReservationPolicy 설정 면과 워커 레인 계정 지정입니다.

라인 27–36 근처 - mayRebindAffinityForQuota / cache-affinity.ts:57 인용은 맞고, 본문 스니펫도 HEAD와 같습니다.
라인 48–51 근처 - pickCacheSafeQuotaReplacement(routing.ts:649)·CODEX_UNKNOWN_USAGE_SCORE(101, quota.ts:77) 설명은 맞습니다. 상수 정의 파일은 routing이 아니라 quota인데, 문서가 쓰는 맥락(교체 선택)은 틀리지 않습니다.
라인 57–62 근처 - reevaluateAffinityQuota를 :680에 걸었지만, 인용한 mayRebind 짧은 회로 코드는 함수 시작이 아니라 그 안의 ~707 근처입니다. 내용은 맞습니다.
라인 71 근처 - previewReusableAffinityAccount는 :536 onward가 아니라 함수 시작이 :534입니다. 두 줄 차이입니다.
라인 115–118 근처 - 프로덕션에 실 maxTokens policy가 없다는 주장은 맞습니다. 다만 테스트 쪽은 헬퍼 두 곳(spend-reservation-ledger.test.ts:26, workflow-budget.test.ts:37) 말고 ledger 테스트 :346 인라인도 있습니다. “정확히 두 곳”은 조금 세게 말한 셈이고, “운영 경로 0”이 핵심입니다.
경로/심볼 - 본문은 코호트를 #4935로 적었고 그게 맞습니다(머지된 cohort affinity PR). 인트리 주석(lineage.ts / routing.ts)은 아직 #4780을 가리킵니다. 문서 잘못이라기보다 주석이 낡은 번호일 수 있습니다.
라인 163–165 근처 - 레인 결정을 server/index.ts:505로 적었지만, 505는 parent-thread-id 읽기이고 lane 삼항은 507–511입니다. admitWorkflowTurn 호출 :512·early return workflow-budget.ts:425는 정확합니다.

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

  • #4546을 이 문서 결론대로 “라우팅 결함은 닫힘 / 토큰 한도 설정 면 없음으로 이유 재서술 후 열린 채 유지”할지, 아니면 캐시 절반만 부분 클로즈 코멘트로 남길지
  • 다음 구현 단위를 root-scope SpendReservationPolicy 설정(기본 unset)으로 잡을지, 워커 레인 계정 지정을 먼저 할지, 둘을 한 스택으로 묶을지
  • 코호트 때문에 팬아웃이 인터랙티브 계정에 몰리는 현상을 문서의 “의도된 대가”로 수용할지, remediation 2(워커 계정 지정)를 [Bug]: Account pool routing destroys prompt cache and triggers 10x-50x token burn death-spiral above 80% usage threshold #4546 잔여 범위에 명시할지

너의 추천
문서 PR은 머지하세요. 인용은 HEAD에서 대부분 맞았고, 남은 것은 줄 번호·“정확히 두 곳” 같은 작은 과장뿐입니다. #4546은 닫지 말고, 이 평가를 이슈에 붙여 이유를 “캐시 파괴 → 차갑고 한도 없는 입력 속도 + 켤 수 없는 spend policy”로 고친 뒤 열어 두세요. 다음 PR은 SpendReservationPolicy를 설정으로 켜는 면(기본 unset)과, 가능하면 워커 레인 계정 지정입니다. 라우팅 추가 패치는 이 이슈의 다음 단위가 아닙니다.

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

@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: 629a9ee47d

ℹ️ 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 +160 to +164
`x-codex-parent-thread-id` has no root, and `admitWorkflowTurn` returns early on
`if (!rootId) return undefined` (`src/lib/workflow-budget.ts:425`), so unparented
one-off traffic sits outside every ceiling. And the lane is decided purely by header shape
at `src/server/index.ts:505`, so a client that omits `thread-id` on its children has
them admitted as interactive.

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 Move the live budget-bypass analysis to scratch

When this assessment is published, these lines provide concrete bypasses for still-unfixed cost protections: omitting the parent header skips every workflow ceiling, while omitting thread-id gives child traffic interactive treatment. This exposes operator quota/cost and is precisely unfixed bypass reasoning, so keep it in .tmp/ until the fixes ship rather than committing it to the public devlog/.

AGENTS.md reference: AGENTS.md:L124-L131

Useful? React with 👍 / 👎.

Comment on lines +134 to +137
| `maxPhysicalSends` | 256 / 10 min | ~61 / 10 min | no |
| `maxDistinctChildren` | 64 / 10 min | ~61 / 10 min | no, by three |
| `maxConcurrentChildren` | 8 (7 for workers) | throttles shape, not volume | n/a |
| token ceiling | unset and unsettable | ~8.7M uncached input / 10 min | **cannot** |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use windowed data before declaring the count caps inactive

Dividing 732 calls across the full two-hour interval yields only an average; it cannot establish that no ten-minute window exceeded either cap. At the assessed SHA, src/lib/workflow-budget.ts:65-75 explicitly describes this incident as a 700-send one-minute burst and says the ten-minute limits were chosen to refuse it, in which case the 64-child and 256-send caps would fire. Use timestamped per-root window data or qualify the conclusion that the measured incident passes every live ceiling.

Useful? React with 👍 / 👎.

@github-actions

Copy link
Copy Markdown
Contributor

✅ Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Sep 17, 2026
@lidge-jun
lidge-jun merged commit 96b0536 into dev Sep 17, 2026
20 checks passed
@lidge-jun
lidge-jun deleted the codex/4546-dev-tip-closure-assessment branch September 17, 2026 23:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant