Skip to content

feat(logs): surface and filter the routed account label per request - #4134

Merged
lidge-jun merged 2 commits into
devfrom
codex/log-account-identity-4057
Sep 9, 2026
Merged

feat(logs): surface and filter the routed account label per request#4134
lidge-jun merged 2 commits into
devfrom
codex/log-account-identity-4057

Conversation

@lidge-jun

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

Copy link
Copy Markdown
Owner

Summary

Every request row and every attempt in this proxy already carries a stable, non-PII account label — main and p<hex6> for Codex pool accounts, o<hex6> for other OAuth providers — written by sealRequestAttemptIdentity. Nothing could read it back. An operator running several accounts behind one provider had to grep usage.jsonl by hand to answer "which account served this request", which is the first diagnostic question for a quota anomaly or a cache miss.

  • GET /api/logs accepts ?account=<label>. Like the existing ?provider and ?model clauses, it matches failover attempts, so a request is findable by the account that finally served it as well as by the account that first refused it (src/server/request-log.ts).
  • ocx logs --account <label> passes the filter through, and human output now prints acct=<label> next to conv=<id> for the same reason conv= exists: without it, an empty result and a wrong-label result look identical (src/cli/observe.ts).
  • The ocx skill pages document the flag, the accountLogLabel JSONL field, and a per-request recipe next to the existing per-account spend recipe.

No new field is persisted, no new identifier is derived, and no raw key, email, or upstream account id is written anywhere. requestLogDto needed no change: it spreads the entry (src/server/management/shared.ts:155-177) and the label is already set on the in-memory row (src/server/request-log.ts:1048) and preserved through hydration (:292, :324). Because that only holds by way of a spread — while the sibling projection requestLogEntryFromPersistedUsage rebuilds field by field and warns in its own comment that a field missing there never reaches usage.jsonl — the served contract is now pinned by a test rather than left implicit.

Deliberately not in this PR

The dashboard Logs column. The issue also asks for an Account column in the GUI Logs table. Any changed path under gui/ arms missing_ui_screenshot (.github/scripts/pr-quality.cjs:526-532), which enforce-target turns into a failed check and an auto-draft (.github/workflows/enforce-pr-target.yml:1251). This change was produced under an instruction not to run any local build, so no honest screenshot of the rendered change could be attached. The GUI half is a separate change: it needs an 11th column in a table-layout: fixed table, both colSpan={10} spacers bumped, and logs.col.account added to en.ts plus all eight other locale catalogs.

Key-pool k<hex6> labels. A stable non-secret id for a pool key already exists (_apiKeyAttempt.entryId, src/providers/api-key-selection-capture.ts:4-9), but stamping it is not a small addition: ACCOUNT_LOG_LABEL_RE (src/codex/account-label.ts:24) and the persistence predicates in src/usage/log.ts would have to accept a fourth label family, and the stamp would need six new sites in src/server/responses/core.ts — the initial seal at 4354-4385 plus four key-rotation arms (6254, 7230, 7299, 7711) that do not restamp identity today — and two in chat-native.ts. It also widens what is derived from a secret: entryId hashes the configured key string itself, unlike oauthAccountLogLabel, which hashes a provider account id. That deserves its own review rather than a tail hunk on this one.

Closes #4057

Verification

Local checks were NOT RUN, per maintainer instruction for this change: no local test suite, typecheck, build, lint, or bun install was executed. The exact-head remote CI on this PR is the gate.

Regression coverage added with the change:

  • tests/usage/request-log.test.tsfilterRequestLogs by account: exact row match, match through a failover attempt, a non-matching label returning [] (the assertion an unfiltered implementation cannot pass), an unlabelled row never swept in, and the filter combined with provider.

  • tests/server/management-api-logs-metrics.test.ts — through the real /api/logs handler: the DTO serves accountLogLabel on the row and on each attempt, and ?account= selects the same rows end to end.

  • tests/cli/cli-observe-logs.test.ts (new) — --account reaches the query string alongside the other filters, is omitted entirely when not requested, and human output prints acct=<label> for a labelled row and nothing for an unlabelled one.

  • src/cli/capabilities.ts declares the flag and skills/ocx/references/01_management_surface.md is its rendered output; tests/ci-workflows/skill-ocx.test.ts:62 byte-compares the two. The first push edited the rendered page alone and that check failed, which is exactly what it exists to catch; the flag is now declared at its source.

The new test file is registered in both scripts/test-layout/layout.json and tests/fixtures/test-layout-expected.json, as tests/test-layout-tooling.test.ts requires.

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.

The filter reads back a label the proxy already persists; it derives nothing new and logs no account identifier. --account takes a label, never a key, and the CLI prints only the same digest already present in usage.jsonl.

Summary by CodeRabbit

  • New Features

    • Added an --account <label> filter to ocx logs for viewing logs associated with a specific account.
    • Account labels appear as acct=<label> in human-readable output and as accountLogLabel in JSONL results.
    • Account filtering also matches failover attempts.
  • Documentation

    • Added guidance on account labels, filtering, and viewing per-request spending.
  • Tests

    • Added coverage for account filtering, output formatting, and account labels in log responses.

The proxy has stamped a stable non-PII account label on every request row and
every attempt for a long time (main, p<hex6> for Codex pool accounts, o<hex6>
for other OAuth providers), but nothing could read it back. An operator running
several accounts behind one provider had to grep usage.jsonl to answer "which
account served this request", which is the first diagnostic question for a quota
or cache anomaly.

/api/logs now accepts ?account=<label>, matching failover attempts the same way
?provider and ?model already do, so a request is findable by the account that
finally served it as well as the one that first refused it. ocx logs gains the
matching --account flag and prints acct=<label> in human output, so a filtered
result can be told apart from an empty one.

No new field is persisted and no new identifier is derived: this reads back the
label already written by sealRequestAttemptIdentity.

Closes #4057
@lidge-jun
lidge-jun requested a review from Ingwannu as a code owner September 9, 2026 15:01
@coderabbitai

coderabbitai Bot commented Sep 9, 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: 286e4703-4980-48bf-b23d-1584689d33df

📥 Commits

Reviewing files that changed from the base of the PR and between da9aef5 and d693361.

📒 Files selected for processing (2)
  • skills/ocx/references/01_management_surface.md
  • src/cli/capabilities.ts

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


📝 Walkthrough

Walkthrough

The change adds account-aware request-log filtering. The CLI accepts --account, sends the filter to /api/logs, and prints acct=<label> for labeled rows. Server filtering checks parent rows and failover attempts. Tests and references cover the contract.

Changes

Account-aware request logs

Layer / File(s) Summary
Server account filtering
src/server/request-log.ts, tests/server/management-api-logs-metrics.test.ts, tests/usage/request-log.test.ts
filterRequestLogs matches accountLogLabel on the main row or any attempt. Tests cover labeled rows, unlabeled rows, failover attempts, and combined provider filtering.
CLI account filtering and output
src/cli/observe.ts, tests/cli/cli-observe-logs.test.ts, scripts/test-layout/layout.json, tests/fixtures/test-layout-expected.json
ocx logs accepts --account, sends the account query parameter, and prints acct=<label> when available. CLI tests cover present, absent, and displayed account values.
Account capability and documentation
src/cli/capabilities.ts, skills/ocx/references/01_management_surface.md, skills/ocx/references/02_json_shapes.md, skills/ocx/references/03_recipes.md
Capability metadata and references document the account filter, accountLogLabel, label formats, failover matching, and human-readable output.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to d6933

Request logs can now be filtered by account label across failover attempts, and labeled rows display the selected account identity in CLI output. The API, CLI, and documented behavior are aligned with focused coverage, with no current merge-blocking risk identified.

Sequence Diagram(s)

sequenceDiagram
  participant Operator
  participant ObserveLogs
  participant LogsAPI
  participant filterRequestLogs
  Operator->>ObserveLogs: run ocx logs --account label
  ObserveLogs->>LogsAPI: request /api/logs?account=label
  LogsAPI->>filterRequestLogs: apply account filter
  filterRequestLogs-->>LogsAPI: return matching rows and attempts
  LogsAPI-->>ObserveLogs: return log rows
  ObserveLogs-->>Operator: print acct=label for labeled rows
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The changes satisfy the CLI and existing-label API portions of issue [#4057]. They add the /api/logs account filter, ocx logs --account, human-readable acct= output, documentation, and regressio… Either implement the remaining [#4057] requirements by adding the dashboard Logs account column and populating usage.jsonl account labels for multi-account providers, including non-Codex providers, or split this work into a separately tra…
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 4 functions across 6 files. (1 skipped: 1 … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed All changes are related to the account-label logging scope: API filtering in src/server/request-log.ts, CLI filtering and output in src/cli/observe.ts, capability metadata in `src/cli/capabilities…
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: exposing and filtering the routed account label in request logs. It is specific, concise, and consistent with the CLI, API, documentation, and test change…
Full details: Linked Issues check

Explanation

The changes satisfy the CLI and existing-label API portions of issue [#4057]. They add the /api/logs account filter, ocx logs --account, human-readable acct= output, documentation, and regression tests in src/server/request-log.ts, src/cli/observe.ts, and the related test files. However, issue [#4057] also requires account visibility in the dashboard Logs panel and populated accountLogLabel values for multi-account non-Codex providers in usage.jsonl. The provided changes do not implement those requirements.

Resolution

Either implement the remaining [#4057] requirements by adding the dashboard Logs account column and populating usage.jsonl account labels for multi-account providers, including non-Codex providers, or split this work into a separately tracked issue and update the linked issue scope to document that this PR covers only existing-label API and CLI visibility and filtering.

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 4 functions across 6 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/log-account-identity-4057

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 9, 2026

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the enhancement New feature or request label Sep 9, 2026
…he rendered page

`skills/ocx/references/01_management_surface.md` is generated from `CAPABILITIES`
in `src/cli/capabilities.ts`, and `tests/ci-workflows/skill-ocx.test.ts` compares
the committed file against a fresh render byte for byte. The previous commit
edited the rendered page by hand, so the two disagreed.

Declare the flag at its source instead: the logs capability now carries
`--account` between `--conversation` and `--status`, its summary names the new
filter, and a detail line documents the `acct=<label>` column next to the
existing `conv=<id>` one. The rendered page is unchanged from the previous
commit apart from that detail line, which is what the registry now emits.
@lidge-jun

Copy link
Copy Markdown
Owner Author

리뷰 · 우선순위 58 / 80

이 PR은 이슈 #4057의 “요청 로그에서 어느 계정이 응답했는지”를 읽기 쉽게 만드는 작업이다. 현재 dev HEAD 3b4d8c439(패키지 2.50.0)를 보면, sealRequestAttemptIdentity가 이미 각 요청·시도에 main / p<hex6> / o<hex6> 같은 비식별 계정 라벨을 찍어 두고 있다. 그런데 src/server/request-log.tsfilterRequestLogs는 지금 provider·model·conversation·status·페이지네이션만 보고, account 절은 없다. 운영자가 할당량 이상이나 캐시 미스를 볼 때 가장 먼저 묻는 “이 요청은 어느 계정?”을 usage.jsonl을 직접 열어봐야만 답할 수 있는 상태다.

이 변경은 그 구멍을 메운다. GET /api/logs?account=<label>이 기존 ?provider / ?model과 똑같이 페일오버 attempt까지 매칭하고, ocx logs --account가 같은 쿼리를 넘긴다. 사람용 출력에는 acct=<label>conv= 옆에 찍어서, 필터 결과가 비었는지·라벨이 틀린 건지 구분할 수 있게 했다. 새 필드를 저장하거나 키·이메일을 로그에 넣는 일은 없다. requestLogDto가 엔트리를 spread 해서 라벨이 이미 내려가던 계약을 테스트로 고정한 점도 좋다. GUI Logs 테이블 Account 열과 k<hex6> 키풀 라벨은 PR 본문대로 의도적으로 빼 두었고, gui/를 건드리면 missing_ui_screenshot에 막히는 현재 게이트와도 맞다.

현재 로그 필터 엔진(#2704 model 절, 이후 #3508/#3712 계열 개선이 이미 HEAD에 있음) 위에 같은 패턴으로 한 절만 더하는 형태라 충돌·회귀 위험이 낮다. 테스트도 filterRequestLogs 단위, /api/logs 핸들러, CLI 쿼리 문자열·acct= 출력까지 세 겹으로 잡혀 있다. 다만 CI에서 test 4/4 실패가 보였고, 로컬 스위트는 유지자 지시로 돌리지 않았다고 본문에 적혀 있으니 원격 CI 그린이 머지 게이트다. GUI 절반은 #4057을 완전히 닫지 못하므로 이슈를 부분 클로즈하거나 follow-up 이슈를 남기는 편이 낫다.

라인 - src/server/request-log.ts filterRequestLogs — HEAD에는 account 절이 없고, PR이 provider/model과 동일하게 attempt 매칭을 추가한다. 비매칭 라벨이 []를 돌려야 한다는 테스트가 핵심이다.

경로/심볼 - src/cli/observe.ts logs() — HEAD는 query({ provider, model, status, conversationId, limit })만 보낸다. --account가 빠지면 서버 필터를 우회하는 클라이언트 필터가 되어 오래된 매칭이 잘릴 수 있는데, PR은 서버 쿼리로 보내는 쪽이 맞다.

경로/심볼 - GUI Account 열 / k<hex6> — 이번 PR 범위 밖. #4057을 닫을 때 “로그 API·CLI만 닫힘, GUI·키풀은 남음”을 이슈에 명시할 필요가 있다.

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

  • #4057을 이 PR만으로 닫을지, GUI 절반을 별도 이슈로 남길지
  • test 4/4 실패가 이 변경 때문인지 일시적인 샤드 노이즈인지 CI 로그 확인 후 머지할지
  • k<hex6> 키풀 라벨을 다음 스프린트에 넣을지(ACCOUNT_LOG_LABEL_RE·persistence·core.ts restamp 사이트 확장)

너의 추천
CI가 그린이면 dev에 머지한다. #4057은 GUI Account 열 follow-up을 남기거나 부분 완료로 정리하고, 키풀 라벨은 별 PR로 분리한다. 지금 당장 막을 설계 충돌은 없다.

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

@lidge-jun
lidge-jun merged commit 7dd50ea into dev Sep 9, 2026
31 of 35 checks passed
@lidge-jun
lidge-jun deleted the codex/log-account-identity-4057 branch September 9, 2026 15:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant