Skip to content

release v0.8.8#1303

Merged
ding113 merged 1 commit into
mainfrom
dev
Jun 30, 2026
Merged

release v0.8.8#1303
ding113 merged 1 commit into
mainfrom
dev

Conversation

@ding113

@ding113 ding113 commented Jun 30, 2026

Copy link
Copy Markdown
Owner

Summary

Release v0.8.8 — merges the dev branch into main. This is a single-feature release containing 1 PR: the new usage-log filter for billing/actual model mismatches.

Included Changes

feat(usage-logs): filter by billing/actual model mismatch (#1302)

Adds an optional actualResponseModelMismatch boolean filter to usage-log queries that surfaces records where the effective billing/request model differs from the model the upstream provider actually returned (actualResponseModel).

  • Why: Since feat(logs): record and display upstream actual response model #1092 the hub records and displays the upstream actualResponseModel as a ↳ {model} hint, but there was no way to search for rows where the two diverge — making silent upstream model substitutions (e.g. a provider downgrading the model) hard to spot across large datasets.
  • Comparison baseline: The effective request model is computed as COALESCE(btrim(model), btrim(originalModel)) and a row is flagged only when it is non-blank and differs (<>) from the non-blank actualResponseModel. Because the baseline is COALESCE(model, originalModel), a pure model redirect (originalModel <> model) is not flagged as a mismatch on its own — only a true divergence between what was billed/requested and what the upstream actually returned. Blank/whitespace values collapse to NULL, so rows missing a model are excluded rather than flagged.
  • Wired through every layer: admin + self usage-log APIs, async exports, repository list / stats / slim cache-key paths, generated OpenAPI types, Zod schemas, dashboard URL state round-trip, active-filter chip + badge counts, a Switch toggle, and five locale strings (en, ja, ru, zh-CN, zh-TW).

Foundational PRs this builds on:

Notes for Reviewers

Testing

Automated (added/updated)

  • tests/unit/repository/usage-logs-actual-model-mismatch-filter.test.ts — SQL semantics: confirms COALESCE/<> comparison against actual_response_model, asserts original_model <> model is not the trigger condition, and that the flag absent/false adds no condition.
  • tests/api/v1/usage-logs/usage-logs.test.ts — admin list / stats / async export propagate the filter.
  • tests/api/v1/me/me.test.ts — self usage-logs list / full propagate the filter.
  • usage-logs-view-virtualized.test.tsx — URL state includes actualResponseModelMismatch=true.

Manual verification

  1. Toggle "Billing/actual model mismatch" on the usage logs page; confirm only rows where the billing model differs from the actual response model remain.
  2. Verify a known pure model-redirect row (originalModel <> model, matching actualResponseModel) is not filtered out.
  3. Confirm the filter survives a page reload / shareable-URL round-trip and applies to the stats summary.

Description enhanced by Claude AI

Add a toggle filter that surfaces usage-log records whose requested
billing model differs from the model actually returned by the provider.
The SQL condition compares COALESCE(model, original_model) against
actual_response_model after trimming whitespace, skipping rows where
either side is NULL or empty. This intentionally ignores model
redirection (original_model vs model) and focuses on provider-side
model substitution.

Wired through the full stack: API query schemas and handlers, server
actions, repository conditions for list/batch/stats/slim queries, the
dashboard filter UI with active-filter display, URL serialization, and
i18n strings for all five locales.
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 94f88ab7-b8f9-4e62-8a38-53382ecf67b2

📥 Commits

Reviewing files that changed from the base of the PR and between f96d00f and bb87cc6.

📒 Files selected for processing (24)
  • messages/en/dashboard.json
  • messages/ja/dashboard.json
  • messages/ru/dashboard.json
  • messages/zh-CN/dashboard.json
  • messages/zh-TW/dashboard.json
  • src/actions/my-usage.ts
  • src/app/[locale]/dashboard/logs/_components/filters/active-filters-display.tsx
  • src/app/[locale]/dashboard/logs/_components/filters/request-filters.tsx
  • src/app/[locale]/dashboard/logs/_components/filters/types.ts
  • src/app/[locale]/dashboard/logs/_components/usage-logs-filters.tsx
  • src/app/[locale]/dashboard/logs/_components/usage-logs-view-virtualized.test.tsx
  • src/app/[locale]/dashboard/logs/_components/usage-logs-view-virtualized.tsx
  • src/app/[locale]/dashboard/logs/_components/virtualized-logs-table.tsx
  • src/app/[locale]/dashboard/logs/_utils/logs-query.ts
  • src/app/api/v1/resources/me/handlers.ts
  • src/app/api/v1/resources/usage-logs/handlers.ts
  • src/lib/api-client/v1/openapi-types.gen.ts
  • src/lib/api/v1/schemas/me.ts
  • src/lib/api/v1/schemas/usage-logs.ts
  • src/repository/_shared/usage-log-filters.ts
  • src/repository/usage-logs.ts
  • tests/api/v1/me/me.test.ts
  • tests/api/v1/usage-logs/usage-logs.test.ts
  • tests/unit/repository/usage-logs-actual-model-mismatch-filter.test.ts

📝 Walkthrough

Walkthrough

在整个代码栈中端到端新增 actualResponseModelMismatch 布尔过滤条件:数据库层通过 btrim/COALESCE 归一化生成不等式 SQL 条件;仓库层在批量查询、slim 查询(含缓存 key)和统计聚合中接入;API schema、handler、actions 层透传该参数;前端 URL 工具解析/序列化,UI 组件新增 Switch 开关和激活标签;五种语言文案同步添加。

Changes

actualResponseModelMismatch 端到端过滤

Layer / File(s) Summary
SQL 条件构建与仓库层过滤
src/repository/_shared/usage-log-filters.ts, src/repository/usage-logs.ts
UsageLogFilterParams 新增字段,新增 buildActualResponseModelMismatchCondition 生成归一化不等式 SQL,并接入 buildUsageLogConditionsfindUsageLogsBatchfindUsageLogsForKeySlim(含缓存 key)、buildKeyLedgerConditionsfindUsageLogsStats 的 ledger 聚合分支。
API schema、handler 与 actions 层透传
src/lib/api/v1/schemas/usage-logs.ts, src/lib/api/v1/schemas/me.ts, src/app/api/v1/resources/usage-logs/handlers.ts, src/app/api/v1/resources/me/handlers.ts, src/actions/my-usage.ts, src/lib/api-client/v1/openapi-types.gen.ts
UsageLogsQuerySchemaMeUsageLogsQuerySchema 新增 BooleanQuerySchema 字段;handler 中读取并透传至 actions;MyUsageLogsFilters/MyUsageLogsBatchFilters 及三个 getMyUsageLogs* 调用均传递该字段;生成类型同步更新。
前端 URL 解析、类型与视图层接入
src/app/[locale]/dashboard/logs/_components/filters/types.ts, src/app/[locale]/dashboard/logs/_utils/logs-query.ts, src/app/[locale]/dashboard/logs/_components/virtualized-logs-table.tsx, src/app/[locale]/dashboard/logs/_components/usage-logs-view-virtualized.tsx, src/app/[locale]/dashboard/logs/_components/usage-logs-filters.tsx
前端过滤类型、URL 解析/序列化、VALID_FILTER_KEYS 白名单、requestActiveCount 计数及 activeFilterCount 均接入 actualResponseModelMismatch
过滤器 UI 组件
src/app/[locale]/dashboard/logs/_components/filters/request-filters.tsx, src/app/[locale]/dashboard/logs/_components/filters/active-filters-display.tsx
RequestFilters 新增 Switch 开关 UI,切换时将字段置为 trueundefinedActiveFiltersDisplay 追加对应激活标签项。
多语言文案
messages/*/dashboard.json
在 en、ja、ru、zh-CN、zh-TW 五个文件中分别新增 actualResponseModelMismatchenabled 文案键。
测试覆盖
tests/unit/repository/usage-logs-actual-model-mismatch-filter.test.ts, tests/api/v1/me/me.test.ts, tests/api/v1/usage-logs/usage-logs.test.ts, src/app/[locale]/dashboard/logs/_components/usage-logs-view-virtualized.test.tsx
新增仓库单元测试验证 SQL 条件;新增 API 集成测试覆盖 me 和 usage-logs 接口参数透传;更新 UI 测试的过滤对象和期望路由 URL。

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (1 warning, 2 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.79% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive 标题仅写了版本号,无法体现本次实际变更内容。 请改成概括主要改动的简短标题,例如“为 usage logs 添加实际响应模型不匹配筛选”。
Description check ❓ Inconclusive 未提供变更描述,信息不足以说明本次修改内容。 补充一段简短描述,说明本次发布包含的核心改动或范围。
✅ Passed checks (2 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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

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 added enhancement New feature or request area:UI area:i18n labels Jun 30, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new filter, actualResponseModelMismatch, allowing users to filter usage logs where the requested billing model differs from the actual response model. The changes span UI updates (including translations, a new switch component, and active filter display), API schemas, and repository query logic, along with comprehensive integration and unit tests. The reviewer feedback highlights two key improvement opportunities: removing the PostgreSQL-specific btrim function in the SQL query builder to improve database portability and index performance, and explicitly parsing the actualResponseModelMismatch URL search parameter to a boolean to prevent TypeScript type mismatches and runtime bugs.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +72 to +75
const effectiveRequestModel = fallbackModelColumn
? sql`COALESCE(NULLIF(btrim(${modelColumn}), ''), NULLIF(btrim(${fallbackModelColumn}), ''))`
: sql`NULLIF(btrim(${modelColumn}), '')`;
const actualResponseModel = sql`NULLIF(btrim(${actualResponseModelColumn}), '')`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The use of the PostgreSQL-specific btrim function on columns in the WHERE clause has two drawbacks:

  1. Database Portability: btrim is PostgreSQL-specific. If the application or its tests are run against other databases (such as SQLite for local testing), this query will fail.
  2. Performance / Index Usage: Applying functions directly to columns in a WHERE clause prevents the database from utilizing standard indexes on those columns (e.g., an index on model or actual_response_model).

Since model names are system identifiers and do not contain leading or trailing whitespace, trimming is unnecessary. We can safely use standard NULLIF without btrim:

const effectiveRequestModel = fallbackModelColumn
  ? sql`COALESCE(NULLIF(${modelColumn}, ''), NULLIF(${fallbackModelColumn}, ''))`
  : sql`NULLIF(${modelColumn}, '')`;
const actualResponseModel = sql`NULLIF(${actualResponseModelColumn}, '')`;

endTime: _params.get("endTime") ?? undefined,
statusCode: _params.get("statusCode") ?? undefined,
model: _params.get("model") ?? undefined,
actualResponseModelMismatch: _params.get("actualResponseModelMismatch") ?? undefined,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The parameter actualResponseModelMismatch is retrieved directly from URLSearchParams using _params.get("actualResponseModelMismatch") ?? undefined. This returns a string (e.g., "true" or "false") or undefined, rather than a boolean.

This causes a TypeScript type mismatch if the filter is typed as boolean | undefined. Furthermore, it can lead to subtle runtime bugs because the string "false" is truthy in JavaScript, which would cause the filter to be treated as active even when set to false.

We should explicitly parse the string value to a boolean.

Suggested change
actualResponseModelMismatch: _params.get("actualResponseModelMismatch") ?? undefined,
actualResponseModelMismatch: _params.get("actualResponseModelMismatch") === "true" ? true : undefined,

Comment on lines +39 to +40
/** 仅筛选请求模型与实际响应模型不一致的记录(不按 originalModel/模型重定向判断) */
actualResponseModelMismatch?: boolean;

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 The JSDoc comment says "不按 originalModel/模型重定向判断" (not based on originalModel / model-redirect logic), but the SQL condition produced by buildActualResponseModelMismatchCondition deliberately uses originalModel as a COALESCE fallback for the effective billing model. The comment contradicts the implementation and will mislead future readers into thinking originalModel is entirely ignored.

Suggested change
/** 仅筛选请求模型与实际响应模型不一致的记录(不按 originalModel/模型重定向判断) */
actualResponseModelMismatch?: boolean;
/** 仅筛选请求模型与实际响应模型不一致的记录(按 COALESCE(model, originalModel) 作为有效计费模型与 actualResponseModel 比较) */
actualResponseModelMismatch?: boolean;
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/repository/usage-logs.ts
Line: 39-40

Comment:
The JSDoc comment says "不按 originalModel/模型重定向判断" (not based on originalModel / model-redirect logic), but the SQL condition produced by `buildActualResponseModelMismatchCondition` deliberately uses `originalModel` as a COALESCE fallback for the effective billing model. The comment contradicts the implementation and will mislead future readers into thinking `originalModel` is entirely ignored.

```suggestion
  /** 仅筛选请求模型与实际响应模型不一致的记录(按 COALESCE(model, originalModel) 作为有效计费模型与 actualResponseModel 比较) */
  actualResponseModelMismatch?: boolean;
```

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@github-actions

Copy link
Copy Markdown
Contributor

🧪 测试结果

测试类型 状态
代码质量
单元测试
集成测试
API 测试

总体结果: ✅ 所有测试通过

@github-actions github-actions Bot added the size/L Large PR (< 1000 lines) label Jun 30, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review Summary

This release PR cleanly threads a single optional boolean filter (actualResponseModelMismatch) through the entire stack — Zod schemas, REST handlers, server actions, the repository condition builder, the slim cache key, generated OpenAPI types, dashboard URL state, the active-filter chip, and all five locales. The SQL semantics (COALESCE(NULLIF(btrim(model),''), NULLIF(btrim(original_model),'')) <> NULLIF(btrim(actual_response_model),'') with both sides IS NOT NULL) correctly implement the documented intent: it flags only a true divergence between the billed/requested model and what the upstream actually returned, deliberately excluding pure model redirects. No defects met the reporting threshold after full-context validation.

PR Size: L

  • Lines changed: 260 (+259 / -1)
  • Files changed: 24

Split note (L-sized): Despite 24 files, ~20 are minimal one-line touch-points wiring a single boolean through the stack, plus 5 mechanical i18n locale additions. The change is one tightly-coupled feature; splitting it (e.g. repo-layer vs. UI-layer) would leave the halves unshippable on their own — the API contract, repository condition, and UI toggle must land together. No practical split recommended.

Verification performed (all paths confirmed covered)

  • buildActualResponseModelMismatchCondition is applied on both the message-request and usage-ledger sides of every query: findUsageLogsBatch, findUsageLogsForKeySlim/Batch, findReadonlyUsageLogsBatchForKey, and findUsageLogsStats.
  • Slim-path total-count cache key includes the flag, preventing stale cross-filter totals.
  • BooleanQuerySchema coerces "true"/"false"/absent correctly; URL round-trip (trueactualResponseModelMismatch=truetrue) verified in logs-query.ts and the navigation test.
  • All three self-usage entry points (getMyUsageLogs, getMyUsageLogsBatch, getMyUsageLogsBatchFull) forward the filter.
  • i18n keys resolve under the dashboard.logs.filters namespace in active-filters-display.tsx and request-filters.tsx.

Issues Found

Category Critical High Medium Low
Logic/Bugs 0 0 0 0
Security 0 0 0 0
Error Handling 0 0 0 0
Types 0 0 0 0
Comments/Docs 0 0 0 0
Tests 0 0 0 0
Simplification 0 0 0 0

No issues at confidence >= 80.

Observations (below threshold, no action required)

  • The unit test in tests/unit/repository/usage-logs-actual-model-mismatch-filter.test.ts asserts on the generated SQL string rather than executing against a database. This is the standard approach for Drizzle SQL-builder unit tests here and adequately guards the COALESCE/<>/original_model-exclusion semantics; it does not exercise the ledger-side inline copies of the condition, but those call the same shared builder.
  • The generated actualResponseModelMismatch?: "true" | "false" | boolean union in openapi-types.gen.ts is intentionally permissive to mirror the Zod union that accepts both string and boolean query input.

Review Coverage

  • Logic and correctness
  • Security (OWASP Top 10)
  • Error handling
  • Type safety
  • Documentation accuracy
  • Test coverage
  • Code clarity

Automated review by Claude AI

@ding113
ding113 merged commit ba18fc1 into main Jun 30, 2026
26 of 27 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in Claude Code Hub Roadmap Jun 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:i18n area:UI enhancement New feature or request size/L Large PR (< 1000 lines)

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant