Skip to content

feat: 统一请求特殊设置命中的展示方式#574

Merged
ding113 merged 3 commits intodevfrom
feat/unify-special-settings-display
Jan 9, 2026
Merged

feat: 统一请求特殊设置命中的展示方式#574
ding113 merged 3 commits intodevfrom
feat/unify-special-settings-display

Conversation

@ding113
Copy link
Owner

@ding113 ding113 commented Jan 9, 2026

Summary

Unifies the display of request special settings by merging scattered audit fields (blockedBy/blockedReason, cacheTtlApplied, context1mApplied) with existing specialSettings into a single, consistent presentation across logs list, log details dialog, and session details page.

Problem

Previously, special request information was fragmented:

  • Provider parameter overrides and response fixer results were stored in special_settings
  • Guard intercepts (warmup, sensitive word blocking) were stored separately in blockedBy/blockedReason fields
  • Anthropic cache TTL and 1M context header overrides were stored in dedicated columns

This fragmentation made it difficult to see all special conditions affecting a request in one place.

Related PRs:

Solution

  1. New utility function buildUnifiedSpecialSettings() that:

    • Merges existing specialSettings from Redis/DB
    • Derives guard_intercept settings from blockedBy/blockedReason
    • Derives anthropic_cache_ttl_header_override from cacheTtlApplied
    • Derives anthropic_context_1m_header_override from context1mApplied
    • Deduplicates entries using a composite key
  2. Extended type system with three new SpecialSetting variants:

    • GuardInterceptSpecialSetting - for warmup/sensitive word blocks
    • AnthropicCacheTtlHeaderOverrideSpecialSetting - for cache TTL overrides
    • AnthropicContext1mHeaderOverrideSpecialSetting - for 1M context overrides
  3. Integrated display in:

    • Usage logs list (new "Special" badge in VirtualizedLogsTable)
    • Error details dialog (passes specialSettings prop)
    • Session details page (merges Redis + DB audit fields)

Changes

Core Changes

File Description
src/lib/utils/special-settings.ts New utility for building unified special settings with deduplication
src/types/special-settings.ts Extended SpecialSetting union type with 3 new variants
src/repository/message.ts New query findMessageRequestAuditBySessionIdAndSequence()
src/repository/usage-logs.ts Apply unified special settings in both batch and detailed log queries
src/actions/active-sessions.ts Merge Redis + DB special settings for session details

UI Changes

File Description
src/app/[locale]/dashboard/logs/_components/virtualized-logs-table.tsx Add "Special" badge and pass specialSettings to ErrorDetailsDialog

Tests

File Description
tests/unit/lib/utils/special-settings.test.ts Unit tests for buildUnifiedSpecialSettings function
tests/unit/actions/active-sessions-special-settings.test.ts Integration tests for session details unification
tests/unit/dashboard-logs-virtualized-special-settings-ui.test.tsx UI tests for Special badge display

Testing

Automated Tests

  • Unit tests added for buildUnifiedSpecialSettings() function
  • Integration tests for session details special settings merging
  • UI tests for VirtualizedLogsTable Special badge

Verification Commands

bun run build
bun run lint && bun run lint:fix
bun run typecheck
bun run test
bun run test:integration
bun run test:e2e
bun run test:coverage

Checklist


Description enhanced by Claude AI

@coderabbitai
Copy link

coderabbitai bot commented Jan 9, 2026

📝 Walkthrough

Walkthrough

新增 specialSettings 类型与构建工具,扩展消息审计查询并在会话与使用日志路径合并 Redis/审计字段生成统一 specialSettings;前端将该数据传递给错误详情对话框,日志表中部分行内的 specialSettings 徽章被移除;补充相关单元测试覆盖(合并、去重、渲染)。

Changes

Cohort / File(s) 变更摘要
类型与工具
src/types/special-settings.ts, src/lib/utils/special-settings.ts
扩展 SpecialSetting 联合类型(新增 GuardIntercept、AnthropicCacheTtlHeaderOverride、AnthropicContext1mHeaderOverride);新增 buildUnifiedSpecialSettings(params),用于派生、合并并去重来自现有设置与审计字段的 specialSettings(返回 `SpecialSetting[]
存储/仓库层
src/repository/message.ts
新增并导出 findMessageRequestAuditBySessionIdAndSequence(sessionId, requestSequence),读取 message_request 审计列(statusCode、blockedBy、blockedReason、cacheTtlApplied、context1mApplied、specialSettings)并返回结构化结果(或 null)。
使用日志查询
src/repository/usage-logs.ts
在批量与详情查询路径中引入 buildUnifiedSpecialSettings,用审计字段与现有 row.specialSettings 构建统一的 specialSettings 并将其包含在返回行中。
业务逻辑(会话动作)
src/actions/active-sessions.ts
getSessionDetails 中动态导入审计查询以获取 requestAudit(若存在),将 Redis 缓存值与 requestAudit 字段合并并通过 buildUnifiedSpecialSettings 生成最终返回的 specialSettings
前端 UI / 组件
src/app/[locale]/dashboard/logs/_components/virtualized-logs-table.tsx, src/app/[locale]/dashboard/logs/_components/error-details-dialog.test.tsx, src/app/[locale]/dashboard/logs/_components/usage-logs-table.tsx
log.specialSettings 传入 ErrorDetailsDialog(其 props 新增可选 specialSettings?);同时移除了日志表行内原有的 specialSettings 徽章渲染(usage-logs-table.tsx)。相关测试新增/更新以验证渲染行为。
测试
tests/unit/lib/utils/special-settings.test.ts, tests/unit/actions/active-sessions-special-settings.test.ts, tests/unit/dashboard-logs-virtualized-special-settings-ui.test.tsx
新增单元测试:验证 buildUnifiedSpecialSettings 的派生规则、合并与去重逻辑;验证会话详情合并来源(Redis + 审计);验证日志列表/错误详情中 specialSettings 的传递与渲染。

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed 标题中文表述清晰明确,反映了此PR的主要目标——统一请求特殊设置命中的展示方式,与changeset中所有核心变更(合并audit字段、创建统一工具函数、扩展类型系统、更新UI展示)完全相关。
Description check ✅ Passed 描述详尽完整,清晰说明了问题(特殊设置信息分散)、解决方案(统一工具函数和展示)以及所有核心文件变更,与changeset完全相关且信息充分。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/unify-special-settings-display

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to Reviews > Disable Cache setting

📥 Commits

Reviewing files that changed from the base of the PR and between d0df372 and 4fae3da.

📒 Files selected for processing (4)
  • src/app/[locale]/dashboard/logs/_components/error-details-dialog.test.tsx
  • src/app/[locale]/dashboard/logs/_components/usage-logs-table.tsx
  • src/app/[locale]/dashboard/logs/_components/virtualized-logs-table.tsx
  • tests/unit/dashboard-logs-virtualized-special-settings-ui.test.tsx
💤 Files with no reviewable changes (1)
  • src/app/[locale]/dashboard/logs/_components/usage-logs-table.tsx
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

No emoji characters in any code, comments, or string literals

Files:

  • src/app/[locale]/dashboard/logs/_components/error-details-dialog.test.tsx
  • src/app/[locale]/dashboard/logs/_components/virtualized-logs-table.tsx
  • tests/unit/dashboard-logs-virtualized-special-settings-ui.test.tsx
**/*.{ts,tsx,jsx,js}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,jsx,js}: All user-facing strings must use i18n (5 languages supported: zh-CN, en, ja, ko, de). Never hardcode display text
Use path alias @/ to map to ./src/
Use Biome for code formatting with configuration: double quotes, trailing commas, 2-space indent, 100 character line width
Prefer named exports over default exports
Use next-intl for internationalization
Use Next.js 16 App Router with Hono for API routes

Files:

  • src/app/[locale]/dashboard/logs/_components/error-details-dialog.test.tsx
  • src/app/[locale]/dashboard/logs/_components/virtualized-logs-table.tsx
  • tests/unit/dashboard-logs-virtualized-special-settings-ui.test.tsx
**/*.test.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Place unit tests in tests/unit/, integration tests in tests/integration/, and source-adjacent tests in src/**/*.test.ts

Files:

  • src/app/[locale]/dashboard/logs/_components/error-details-dialog.test.tsx
  • tests/unit/dashboard-logs-virtualized-special-settings-ui.test.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use React 19, shadcn/ui, Tailwind CSS, and Recharts for the UI layer

Files:

  • src/app/[locale]/dashboard/logs/_components/error-details-dialog.test.tsx
  • src/app/[locale]/dashboard/logs/_components/virtualized-logs-table.tsx
  • tests/unit/dashboard-logs-virtualized-special-settings-ui.test.tsx
🧠 Learnings (3)
📚 Learning: 2026-01-05T03:02:06.594Z
Learnt from: NieiR
Repo: ding113/claude-code-hub PR: 539
File: src/app/[locale]/dashboard/_components/user/user-key-table-row.tsx:66-66
Timestamp: 2026-01-05T03:02:06.594Z
Learning: In the claude-code-hub project, the translations.actions.addKey field in UserKeyTableRowProps is defined as optional for backward compatibility, but all actual callers in the codebase provide the complete translations object. The field has been added to all 5 locale files (messages/{locale}/dashboard.json).

Applied to files:

  • src/app/[locale]/dashboard/logs/_components/error-details-dialog.test.tsx
📚 Learning: 2026-01-07T17:05:36.362Z
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-07T17:05:36.362Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Place unit tests in tests/unit/, integration tests in tests/integration/, and source-adjacent tests in src/**/*.test.ts

Applied to files:

  • tests/unit/dashboard-logs-virtualized-special-settings-ui.test.tsx
📚 Learning: 2026-01-07T17:05:36.362Z
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-07T17:05:36.362Z
Learning: Applies to **/*.{ts,tsx,jsx,js} : All user-facing strings must use i18n (5 languages supported: zh-CN, en, ja, ko, de). Never hardcode display text

Applied to files:

  • tests/unit/dashboard-logs-virtualized-special-settings-ui.test.tsx
🧬 Code graph analysis (1)
tests/unit/dashboard-logs-virtualized-special-settings-ui.test.tsx (2)
src/repository/usage-logs.ts (1)
  • UsageLogRow (30-62)
src/app/[locale]/dashboard/logs/_components/virtualized-logs-table.tsx (1)
  • VirtualizedLogsTable (51-624)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 🌐 API Tests
  • GitHub Check: Docker Build Test
  • GitHub Check: dev-build-deploy
🔇 Additional comments (4)
src/app/[locale]/dashboard/logs/_components/error-details-dialog.test.tsx (1)

73-75: 测试覆盖完整,实现正确。

新增的 specialSettings 测试用例正确验证了以下内容:

  • specialSettings 存在时,渲染"Special settings"标题
  • 渲染特定设置项(provider_parameter_override

测试数据结构与 SpecialSetting 类型匹配,断言逻辑清晰。

Also applies to: 127-152

src/app/[locale]/dashboard/logs/_components/virtualized-logs-table.tsx (1)

581-581: 正确传递 specialSettings 数据。

该行将日志的 specialSettings 字段传递给 ErrorDetailsDialog,与其他字段的传递方式一致,实现正确。

tests/unit/dashboard-logs-virtualized-special-settings-ui.test.tsx (2)

1-157: 测试结构和设置合理。

测试文件的整体结构良好:

  • Virtualizer mock 适配了 happy-dom 环境的限制
  • getUsageLogsBatch mock 提供了包含 specialSettings 的完整日志数据
  • renderWithIntl helper 正确配置了 QueryClient 和 NextIntlClientProvider
  • 异步辅助函数(flushMicrotaskswaitForText)确保数据加载后再进行断言

测试意图清晰:验证 specialSettings 不应在日志列表行中显示(仅在详情对话框中显示),这与 PR 目标一致。

Also applies to: 159-162


158-158: 没有问题。dashboardMessages.logs.table.specialSettings 在消息文件中确实存在,其值为 "Special",该断言有效。

Likely an incorrect or invalid review comment.


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

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @ding113, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

此拉取请求旨在标准化应用程序中请求相关“特殊设置”的展示方式。通过整合来自不同数据源(如 Redis 和数据库)的各种审计字段,将其统一为一致的 specialSettings 结构,并确保这些统一后的数据能在日志表格和会话详情中清晰地呈现,从而提升用户对请求处理细节的可见性和可追溯性。

Highlights

  • 统一特殊设置展示: 将 blockedBy/blockedReasoncacheTtlAppliedcontext1mApplied 等请求审计字段与既有的 special_settings 合并,形成统一的 specialSettings 数据结构,以便在日志列表、日志详情弹窗和 Session 详情页中一致展示。
  • 前端 UI 更新: 在 VirtualizedLogsTable 中增加了“Special”标记,当请求存在特殊设置时会显示此标记,并确保特殊设置的详细信息能正确透传到 ErrorDetailsDialog 中。
  • 后端数据处理: 引入了新的工具函数 buildUnifiedSpecialSettings,用于合并来自 Redis 缓存和数据库审计字段的特殊设置,并进行去重处理。同时,新增了 findMessageRequestAuditBySessionIdAndSequence 方法,用于从数据库获取请求的审计字段。
  • 类型定义扩展: 扩展了 SpecialSetting 类型,新增了 GuardInterceptSpecialSettingAnthropicCacheTtlHeaderOverrideSpecialSettingAnthropicContext1mHeaderOverrideSpecialSetting,以支持更丰富的特殊设置类型。
  • 新增单元测试和 UI 测试: 为 active-sessions 动作、special-settings 工具函数以及 VirtualizedLogsTable 组件添加了新的单元测试和 UI 测试,确保特殊设置的合并逻辑和前端展示的正确性。
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 9, 2026

🧪 测试结果

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

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

Copy link
Contributor

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

Choose a reason for hiding this comment

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

Code Review

本次变更通过引入 buildUnifiedSpecialSettings 工具函数,统一了来自数据库和 Redis 的 specialSettings 数据源,逻辑清晰,结构良好。新的 specialSettings 类型定义和相应的后端数据获取逻辑修改都很到位。前端在日志表格中增加了 Special 标记,并透传了数据,实现了端到端的展示。此外,为新功能增加了全面的单元测试和 UI 测试,保证了代码质量。

我发现了一些可以改进的地方,主要涉及去重逻辑中的一个潜在 bug 和一些代码可读性优化,具体请看我的评论。

Comment on lines 31 to 68
function buildSettingKey(setting: SpecialSetting): string {
switch (setting.type) {
case "provider_parameter_override":
return [
setting.type,
setting.providerId ?? "null",
setting.providerType ?? "null",
setting.hit ? "1" : "0",
setting.changed ? "1" : "0",
].join(":");
case "response_fixer":
return [
setting.type,
setting.hit ? "1" : "0",
setting.fixersApplied
.map((f) => `${f.fixer}=${f.applied ? "1" : "0"}`)
.sort()
.join(","),
].join(":");
case "guard_intercept":
return [
setting.type,
setting.guard,
setting.action,
setting.statusCode ?? "null",
setting.reason ?? "null",
].join(":");
case "anthropic_cache_ttl_header_override":
return [setting.type, setting.ttl].join(":");
case "anthropic_context_1m_header_override":
return [setting.type, setting.flag].join(":");
default: {
// 兜底:保证即使未来扩展类型也不会导致运行时崩溃
const _exhaustive: never = setting;
return JSON.stringify(_exhaustive);
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

high

当前的 buildSettingKey 实现中,使用 ?? "null" 来处理 null 值,当属性的字符串值恰好是 "null" 时,会产生哈希碰撞,导致去重逻辑错误。例如,reason: nullreason: 'null' 会生成相同的 key。建议直接使用 Array.prototype.join 的默认行为,它会将 nullundefined 转换为空字符串,从而避免此问题。

function buildSettingKey(setting: SpecialSetting): string {
  switch (setting.type) {
    case "provider_parameter_override":
      return [
        setting.type,
        setting.providerId,
        setting.providerType,
        setting.hit ? "1" : "0",
        setting.changed ? "1" : "0",
      ].join(":");
    case "response_fixer":
      return [
        setting.type,
        setting.hit ? "1" : "0",
        setting.fixersApplied
          .map((f) => `${f.fixer}=${f.applied ? "1" : "0"}`)
          .sort()
          .join(","),
      ].join(":");
    case "guard_intercept":
      return [
        setting.type,
        setting.guard,
        setting.action,
        setting.statusCode,
        setting.reason,
      ].join(":");
    case "anthropic_cache_ttl_header_override":
      return [setting.type, setting.ttl].join(":");
    case "anthropic_context_1m_header_override":
      return [setting.type, setting.flag].join(":");
    default: {
      // 兜底:保证即使未来扩展类型也不会导致运行时崩溃
      const _exhaustive: never = setting;
      return JSON.stringify(_exhaustive);
    }
  }
}

Comment on lines 592 to 594
const { findMessageRequestAuditBySessionIdAndSequence } = await import("@/repository/message");

const { findAdjacentRequestSequences } = await import("@/repository/message");
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

为了代码简洁和避免重复导入,可以将来自同一模块的动态导入合并为一条语句。

Suggested change
const { findMessageRequestAuditBySessionIdAndSequence } = await import("@/repository/message");
const { findAdjacentRequestSequences } = await import("@/repository/message");
const { findMessageRequestAuditBySessionIdAndSequence, findAdjacentRequestSequences } =
await import("@/repository/message");

Comment on lines 656 to 662
const existingSpecialSettings: SpecialSetting[] | null = (() => {
const merged = [
...(Array.isArray(redisSpecialSettings) ? redisSpecialSettings : []),
...(Array.isArray(requestAudit?.specialSettings) ? requestAudit.specialSettings : []),
];
return merged.length > 0 ? merged : null;
})();
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

这个立即执行函数表达式(IIFE)使代码稍微有些复杂。可以将其重构为几个简单的常量声明,以提高可读性。

    const mergedSpecialSettings = [
      ...(Array.isArray(redisSpecialSettings) ? redisSpecialSettings : []),
      ...(Array.isArray(requestAudit?.specialSettings) ? requestAudit.specialSettings : []),
    ];
    const existingSpecialSettings = mergedSpecialSettings.length > 0 ? mergedSpecialSettings : null;

@github-actions github-actions bot added the size/L Large PR (< 1000 lines) label Jan 9, 2026
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

4 files reviewed, 4 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 106 to 114
if (params.context1mApplied) {
derived.push({
type: "anthropic_context_1m_header_override",
scope: "request_header",
hit: true,
header: "anthropic-beta",
flag: CONTEXT_1M_BETA_HEADER,
});
}
Copy link

Choose a reason for hiding this comment

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

The condition if (params.context1mApplied) only adds the setting when context1mApplied is true. However, based on the type signature on line 28 (context1mApplied?: boolean | null), this means:

  • When context1mApplied is false, no setting is added (expected behavior)
  • When context1mApplied is null, no setting is added (expected behavior)
  • When context1mApplied is true, the setting IS added (expected behavior)

This is actually correct as is. The issue is that unlike the other two conditions (if (params.blockedBy) and if (params.cacheTtlApplied) which check truthiness), the context1m condition explicitly checks for boolean true - which is the correct behavior since we need to distinguish between "not applied" (false) and "no data" (null). However, for consistency with the other two conditions that derive settings, this should use explicit null checking instead of relying on truthiness:

Suggested change
if (params.context1mApplied) {
derived.push({
type: "anthropic_context_1m_header_override",
scope: "request_header",
hit: true,
header: "anthropic-beta",
flag: CONTEXT_1M_BETA_HEADER,
});
}
if (params.context1mApplied === true) {
derived.push({
type: "anthropic_context_1m_header_override",
scope: "request_header",
hit: true,
header: "anthropic-beta",
flag: CONTEXT_1M_BETA_HEADER,
});
}

This makes the intention clearer - we only want to add this setting when the flag is explicitly set to true, not just truthy.

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!

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/lib/utils/special-settings.ts
Line: 106:114

Comment:
The condition `if (params.context1mApplied)` only adds the setting when `context1mApplied` is `true`. However, based on the type signature on line 28 (`context1mApplied?: boolean | null`), this means:
- When `context1mApplied` is `false`, no setting is added (expected behavior)
- When `context1mApplied` is `null`, no setting is added (expected behavior)  
- When `context1mApplied` is `true`, the setting IS added (expected behavior)

This is actually correct as is. The issue is that unlike the other two conditions (`if (params.blockedBy)` and `if (params.cacheTtlApplied)` which check truthiness), the context1m condition explicitly checks for boolean `true` - which is the correct behavior since we need to distinguish between "not applied" (`false`) and "no data" (`null`). However, for consistency with the other two conditions that derive settings, this should use explicit null checking instead of relying on truthiness:

```suggestion
  if (params.context1mApplied === true) {
    derived.push({
      type: "anthropic_context_1m_header_override",
      scope: "request_header",
      hit: true,
      header: "anthropic-beta",
      flag: CONTEXT_1M_BETA_HEADER,
    });
  }
```

This makes the intention clearer - we only want to add this setting when the flag is explicitly set to `true`, not just truthy.

<sub>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!</sub>

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

Comment on lines +120 to +127
const seen = new Set<string>();
const result: SpecialSetting[] = [];
for (const item of [...base, ...derived]) {
const key = buildSettingKey(item);
if (seen.has(key)) continue;
seen.add(key);
result.push(item);
}
Copy link

Choose a reason for hiding this comment

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

The deduplication logic assumes that if two settings have the same buildSettingKey() result, they are duplicates and should be deduplicated. However, there's a subtle issue with the guard_intercept type deduplication.

Consider this scenario:

  1. existing contains: { type: "guard_intercept", guard: "warmup", action: "intercept_response", statusCode: 200, reason: "original_reason" }
  2. params.blockedBy: "warmup", params.blockedReason: "different_reason", params.statusCode: 200

The buildSettingKey for guard_intercept (line 51-57) uses the reason field in the key, so:

  • existing key: "guard_intercept:warmup:intercept_response:200:original_reason"
  • derived key: "guard_intercept:warmup:intercept_response:200:different_reason"

These have different keys, so both would be included! This violates the intention to deduplicate.

The issue is that the reason field (which contains JSON string like {"reason": "..."}) is being used in the deduplication key. If the same guard intercepts a request multiple times with different reasons, they would all be kept rather than deduplicated.

A better approach would be to not include the reason in the deduplication key, or to normalize the reason data before comparison:

Suggested change
const seen = new Set<string>();
const result: SpecialSetting[] = [];
for (const item of [...base, ...derived]) {
const key = buildSettingKey(item);
if (seen.has(key)) continue;
seen.add(key);
result.push(item);
}
case "guard_intercept":
return [
setting.type,
setting.guard,
setting.action,
setting.statusCode ?? "null",
// Excluded: reason
].join(":");

Or if you want to keep the reason, at least normalize it by parsing the JSON first to make the comparison more robust.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/lib/utils/special-settings.ts
Line: 120:127

Comment:
The deduplication logic assumes that if two settings have the same `buildSettingKey()` result, they are duplicates and should be deduplicated. However, there's a subtle issue with the guard_intercept type deduplication.

Consider this scenario:
1. `existing` contains: `{ type: "guard_intercept", guard: "warmup", action: "intercept_response", statusCode: 200, reason: "original_reason" }`
2. `params.blockedBy: "warmup"`, `params.blockedReason: "different_reason"`, `params.statusCode: 200`

The buildSettingKey for guard_intercept (line 51-57) uses the `reason` field in the key, so:
- existing key: `"guard_intercept:warmup:intercept_response:200:original_reason"`
- derived key: `"guard_intercept:warmup:intercept_response:200:different_reason"`

These have different keys, so both would be included! This violates the intention to deduplicate.

The issue is that the `reason` field (which contains JSON string like `{"reason": "..."}`) is being used in the deduplication key. If the same guard intercepts a request multiple times with different reasons, they would all be kept rather than deduplicated.

A better approach would be to not include the reason in the deduplication key, or to normalize the reason data before comparison:

```suggestion
    case "guard_intercept":
      return [
        setting.type,
        setting.guard,
        setting.action,
        setting.statusCode ?? "null",
        // Excluded: reason
      ].join(":");
```

Or if you want to keep the reason, at least normalize it by parsing the JSON first to make the comparison more robust.

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

Comment on lines 656 to 671
const existingSpecialSettings: SpecialSetting[] | null = (() => {
const merged = [
...(Array.isArray(redisSpecialSettings) ? redisSpecialSettings : []),
...(Array.isArray(requestAudit?.specialSettings) ? requestAudit.specialSettings : []),
];
return merged.length > 0 ? merged : null;
})();

const unifiedSpecialSettings = buildUnifiedSpecialSettings({
existing: existingSpecialSettings,
blockedBy: requestAudit?.blockedBy ?? null,
blockedReason: requestAudit?.blockedReason ?? null,
statusCode: requestAudit?.statusCode ?? null,
cacheTtlApplied: requestAudit?.cacheTtlApplied ?? null,
context1mApplied: requestAudit?.context1mApplied ?? null,
});
Copy link

Choose a reason for hiding this comment

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

The code merges redisSpecialSettings and requestAudit?.specialSettings into existingSpecialSettings, then passes this to buildUnifiedSpecialSettings. However, there's a potential issue with the merge strategy.

Looking at lines 656-662:

const existingSpecialSettings: SpecialSetting[] | null = (() => {
  const merged = [
    ...(Array.isArray(redisSpecialSettings) ? redisSpecialSettings : []),
    ...(Array.isArray(requestAudit?.specialSettings) ? requestAudit.specialSettings : []),
  ];
  return merged.length > 0 ? merged : null;
})();

This concatenates Redis settings and DB settings without deduplication. Then buildUnifiedSpecialSettings is called with this merged array as the existing parameter (line 665).

The issue is that if the same special setting exists in both Redis and DB (which can happen if data is cached in both places), buildUnifiedSpecialSettings will see duplicates in the existing array. The buildSettingKey and deduplication logic (lines 120-127) should handle this, but it's redundant to have the same data in both places.

More critically, if you look at the deduplication in buildUnifiedSpecialSettings (line 124), it uses a Set with buildSettingKey(). This means:

  • If Redis and DB have the same setting, they will be deduplicated ✓
  • BUT if they have slightly different data (e.g., different reason field in guard_intercept), they might both appear ✗

This isn't necessarily a bug, but it's a subtle edge case. Consider adding a comment explaining this expected behavior, or consider normalizing the data before merging.

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!

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/actions/active-sessions.ts
Line: 656:671

Comment:
The code merges `redisSpecialSettings` and `requestAudit?.specialSettings` into `existingSpecialSettings`, then passes this to `buildUnifiedSpecialSettings`. However, there's a potential issue with the merge strategy.

Looking at lines 656-662:
```typescript
const existingSpecialSettings: SpecialSetting[] | null = (() => {
  const merged = [
    ...(Array.isArray(redisSpecialSettings) ? redisSpecialSettings : []),
    ...(Array.isArray(requestAudit?.specialSettings) ? requestAudit.specialSettings : []),
  ];
  return merged.length > 0 ? merged : null;
})();
```

This concatenates Redis settings and DB settings without deduplication. Then `buildUnifiedSpecialSettings` is called with this merged array as the `existing` parameter (line 665).

The issue is that if the same special setting exists in both Redis and DB (which can happen if data is cached in both places), `buildUnifiedSpecialSettings` will see duplicates in the `existing` array. The `buildSettingKey` and deduplication logic (lines 120-127) should handle this, but it's redundant to have the same data in both places.

More critically, if you look at the deduplication in `buildUnifiedSpecialSettings` (line 124), it uses a Set with `buildSettingKey()`. This means:
- If Redis and DB have the same setting, they will be deduplicated ✓
- BUT if they have slightly different data (e.g., different `reason` field in guard_intercept), they might both appear ✗

This isn't necessarily a bug, but it's a subtle edge case. Consider adding a comment explaining this expected behavior, or consider normalizing the data before merging.

<sub>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!</sub>

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

Comment on lines 245 to 252
const unifiedSpecialSettings = buildUnifiedSpecialSettings({
existing: row.specialSettings as SpecialSetting[] | null,
blockedBy: row.blockedBy,
blockedReason: row.blockedReason,
statusCode: row.statusCode,
cacheTtlApplied: row.cacheTtlApplied,
context1mApplied: row.context1mApplied,
});
Copy link

Choose a reason for hiding this comment

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

In the findUsageLogsBatch function, buildUnifiedSpecialSettings is called with parameters derived from a database row. However, the issue is that row.specialSettings is cast to SpecialSetting[] | null without validation:

const unifiedSpecialSettings = buildUnifiedSpecialSettings({
  existing: row.specialSettings as SpecialSetting[] | null,
  blockedBy: row.blockedBy,
  blockedReason: row.blockedReason,
  statusCode: row.statusCode,
  cacheTtlApplied: row.cacheTtlApplied,
  context1mApplied: row.context1mApplied,
});

If row.specialSettings is malformed JSON data from the database (e.g., invalid structure), the cast will silently allow invalid data to pass through. This could cause issues downstream when the UI tries to render the specialSettings.

The same issue exists in findUsageLogsWithDetails (line 461-468) and in virtualized-logs-table.tsx where the data is used.

While this is primarily a data integrity issue (bad data in the DB), it's worth considering adding runtime validation:

Suggested change
const unifiedSpecialSettings = buildUnifiedSpecialSettings({
existing: row.specialSettings as SpecialSetting[] | null,
blockedBy: row.blockedBy,
blockedReason: row.blockedReason,
statusCode: row.statusCode,
cacheTtlApplied: row.cacheTtlApplied,
context1mApplied: row.context1mApplied,
});
const existingSettings = Array.isArray(row.specialSettings)
? (row.specialSettings as SpecialSetting[])
: null;
const unifiedSpecialSettings = buildUnifiedSpecialSettings({
existing: existingSettings,
blockedBy: row.blockedBy,
blockedReason: row.blockedReason,
statusCode: row.statusCode,
cacheTtlApplied: row.cacheTtlApplied,
context1mApplied: row.context1mApplied,
});

This adds a simple runtime check that specialSettings is actually an array before treating it as such.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/repository/usage-logs.ts
Line: 245:252

Comment:
In the `findUsageLogsBatch` function, `buildUnifiedSpecialSettings` is called with parameters derived from a database row. However, the issue is that `row.specialSettings` is cast to `SpecialSetting[] | null` without validation:

```typescript
const unifiedSpecialSettings = buildUnifiedSpecialSettings({
  existing: row.specialSettings as SpecialSetting[] | null,
  blockedBy: row.blockedBy,
  blockedReason: row.blockedReason,
  statusCode: row.statusCode,
  cacheTtlApplied: row.cacheTtlApplied,
  context1mApplied: row.context1mApplied,
});
```

If `row.specialSettings` is malformed JSON data from the database (e.g., invalid structure), the cast will silently allow invalid data to pass through. This could cause issues downstream when the UI tries to render the specialSettings.

The same issue exists in `findUsageLogsWithDetails` (line 461-468) and in `virtualized-logs-table.tsx` where the data is used.

While this is primarily a data integrity issue (bad data in the DB), it's worth considering adding runtime validation:

```suggestion
const existingSettings = Array.isArray(row.specialSettings)
  ? (row.specialSettings as SpecialSetting[])
  : null;
const unifiedSpecialSettings = buildUnifiedSpecialSettings({
  existing: existingSettings,
  blockedBy: row.blockedBy,
  blockedReason: row.blockedReason,
  statusCode: row.statusCode,
  cacheTtlApplied: row.cacheTtlApplied,
  context1mApplied: row.context1mApplied,
});
```

This adds a simple runtime check that `specialSettings` is actually an array before treating it as such.

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @tests/unit/dashboard-logs-virtualized-special-settings-ui.test.tsx:
- Around line 136-162: Replace all Chinese characters in the test file: change
the test suite and test case names in describe("VirtualizedLogsTable -
specialSettings 展示") and test("当 log.specialSettings 存在时应显示 Special 标记") to
English, update the waitForText error message throw new Error(`等待文本超时: ${text}`)
to an English message, and convert any Chinese inline comments (e.g., the
comment before waitForText and the comment about waiting for first-screen data)
into English; ensure any user-visible asserted strings remain appropriate (use
i18n where required) and keep function names like waitForText, renderWithIntl,
flushMicrotasks, and VirtualizedLogsTable unchanged.
🧹 Nitpick comments (2)
src/lib/utils/special-settings.ts (1)

31-68: exhaustive switch 模式与去重键设计

使用 never 类型进行穷举检查是良好实践。但 provider_parameter_override 的去重键未包含 changes 数组,若同一 provider 的不同 changes 需区分,可能被误判为重复。

当前场景下(同请求内同 provider 的覆写通常唯一)应无问题,但建议在注释中说明该约束。

src/repository/message.ts (1)

274-316: 函数实现正确,考虑添加运行时验证。

函数逻辑清晰,查询条件正确使用了复合索引(idx_message_request_session_seq)。Line 314 的类型断言依赖数据库数据完整性,如果 DB 中的 specialSettings JSON 结构不符合 SpecialSetting[] 类型定义,可能导致运行时类型错误。

💡 可选:添加运行时验证以提高类型安全
  if (!row) return null;
  return {
    statusCode: row.statusCode,
    blockedBy: row.blockedBy,
    blockedReason: row.blockedReason,
    cacheTtlApplied: row.cacheTtlApplied,
    context1mApplied: row.context1mApplied,
-   specialSettings: row.specialSettings as SpecialSetting[] | null,
+   specialSettings: Array.isArray(row.specialSettings) ? row.specialSettings as SpecialSetting[] : null,
  };

这样可以在类型断言前添加基础的数组类型检查,提高代码健壮性。

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to Reviews > Disable Cache setting

📥 Commits

Reviewing files that changed from the base of the PR and between 33c5247 and 5581efc.

📒 Files selected for processing (9)
  • src/actions/active-sessions.ts
  • src/app/[locale]/dashboard/logs/_components/virtualized-logs-table.tsx
  • src/lib/utils/special-settings.ts
  • src/repository/message.ts
  • src/repository/usage-logs.ts
  • src/types/special-settings.ts
  • tests/unit/actions/active-sessions-special-settings.test.ts
  • tests/unit/dashboard-logs-virtualized-special-settings-ui.test.tsx
  • tests/unit/lib/utils/special-settings.test.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

No emoji characters in any code, comments, or string literals

Files:

  • src/types/special-settings.ts
  • tests/unit/lib/utils/special-settings.test.ts
  • src/lib/utils/special-settings.ts
  • src/actions/active-sessions.ts
  • tests/unit/actions/active-sessions-special-settings.test.ts
  • src/repository/usage-logs.ts
  • src/app/[locale]/dashboard/logs/_components/virtualized-logs-table.tsx
  • src/repository/message.ts
  • tests/unit/dashboard-logs-virtualized-special-settings-ui.test.tsx
**/*.{ts,tsx,jsx,js}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,jsx,js}: All user-facing strings must use i18n (5 languages supported: zh-CN, en, ja, ko, de). Never hardcode display text
Use path alias @/ to map to ./src/
Use Biome for code formatting with configuration: double quotes, trailing commas, 2-space indent, 100 character line width
Prefer named exports over default exports
Use next-intl for internationalization
Use Next.js 16 App Router with Hono for API routes

Files:

  • src/types/special-settings.ts
  • tests/unit/lib/utils/special-settings.test.ts
  • src/lib/utils/special-settings.ts
  • src/actions/active-sessions.ts
  • tests/unit/actions/active-sessions-special-settings.test.ts
  • src/repository/usage-logs.ts
  • src/app/[locale]/dashboard/logs/_components/virtualized-logs-table.tsx
  • src/repository/message.ts
  • tests/unit/dashboard-logs-virtualized-special-settings-ui.test.tsx
**/*.test.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Place unit tests in tests/unit/, integration tests in tests/integration/, and source-adjacent tests in src/**/*.test.ts

Files:

  • tests/unit/lib/utils/special-settings.test.ts
  • tests/unit/actions/active-sessions-special-settings.test.ts
  • tests/unit/dashboard-logs-virtualized-special-settings-ui.test.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use React 19, shadcn/ui, Tailwind CSS, and Recharts for the UI layer

Files:

  • src/app/[locale]/dashboard/logs/_components/virtualized-logs-table.tsx
  • tests/unit/dashboard-logs-virtualized-special-settings-ui.test.tsx
🧠 Learnings (2)
📚 Learning: 2026-01-05T03:01:39.354Z
Learnt from: NieiR
Repo: ding113/claude-code-hub PR: 539
File: src/types/user.ts:158-170
Timestamp: 2026-01-05T03:01:39.354Z
Learning: In TypeScript interfaces, explicitly document and enforce distinct meanings for null and undefined. Example: for numeric limits like limitTotalUsd, use 'number | null | undefined' when null signifies explicitly unlimited (e.g., matches DB schema or special UI logic) and undefined signifies 'inherit default'. This pattern should be consistently reflected in type definitions across related fields to preserve semantic clarity between database constraints and UI behavior.

Applied to files:

  • src/types/special-settings.ts
  • src/lib/utils/special-settings.ts
  • src/actions/active-sessions.ts
  • src/repository/usage-logs.ts
  • src/repository/message.ts
📚 Learning: 2026-01-07T17:05:36.362Z
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-07T17:05:36.362Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Place unit tests in tests/unit/, integration tests in tests/integration/, and source-adjacent tests in src/**/*.test.ts

Applied to files:

  • tests/unit/lib/utils/special-settings.test.ts
  • tests/unit/dashboard-logs-virtualized-special-settings-ui.test.tsx
🧬 Code graph analysis (7)
tests/unit/lib/utils/special-settings.test.ts (2)
src/lib/utils/special-settings.ts (1)
  • buildUnifiedSpecialSettings (76-130)
src/types/special-settings.ts (1)
  • SpecialSetting (8-13)
src/lib/utils/special-settings.ts (2)
src/types/special-settings.ts (1)
  • SpecialSetting (8-13)
src/lib/special-attributes/index.ts (1)
  • CONTEXT_1M_BETA_HEADER (25-25)
tests/unit/actions/active-sessions-special-settings.test.ts (1)
src/actions/active-sessions.ts (1)
  • getSessionDetails (511-697)
src/repository/usage-logs.ts (2)
src/lib/utils/special-settings.ts (1)
  • buildUnifiedSpecialSettings (76-130)
src/types/special-settings.ts (1)
  • SpecialSetting (8-13)
src/app/[locale]/dashboard/logs/_components/virtualized-logs-table.tsx (2)
src/components/ui/badge.tsx (1)
  • Badge (39-39)
scripts/sync-settings-keys.js (1)
  • t (72-72)
src/repository/message.ts (3)
src/types/special-settings.ts (1)
  • SpecialSetting (8-13)
src/drizzle/db.ts (1)
  • db (37-44)
src/drizzle/schema.ts (1)
  • messageRequest (276-362)
tests/unit/dashboard-logs-virtualized-special-settings-ui.test.tsx (2)
src/repository/usage-logs.ts (1)
  • UsageLogRow (30-62)
src/app/[locale]/dashboard/logs/_components/virtualized-logs-table.tsx (1)
  • VirtualizedLogsTable (51-632)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: pr-description
  • GitHub Check: pr-review
  • GitHub Check: 🌐 API Tests
  • GitHub Check: check-codex-status
  • GitHub Check: Docker Build Test
  • GitHub Check: dev-build-deploy
🔇 Additional comments (23)
src/lib/utils/special-settings.ts (2)

1-29: 类型定义与导入结构清晰

参数类型 BuildUnifiedSpecialSettingsParams 设计合理,使用 | null 明确表达"显式为空"与 undefined(省略/继承)的语义差异,符合项目中对 nullundefined 的区分约定。


76-129: 统一构建逻辑正确

函数逻辑清晰:

  1. 优先保留 existing 中的设置(先入 Set)
  2. 从审计字段派生 guard_interceptcache_ttlcontext_1m 设置
  3. 空结果返回 null 而非空数组,与类型签名一致

实现符合预期,去重逻辑正确。

src/app/[locale]/dashboard/logs/_components/virtualized-logs-table.tsx (2)

387-394: Special 标记渲染实现正确

条件渲染逻辑 log.specialSettings && log.specialSettings.length > 0 安全处理了 null/undefined 和空数组场景。使用 i18n key logs.table.specialSettings 符合国际化规范。


589-589: 透传 specialSettings 至详情弹窗

正确将 log.specialSettings 传递给 ErrorDetailsDialog,与 PR 目标一致。

src/repository/usage-logs.ts (2)

245-264: 批量查询中统一 specialSettings 构建

findUsageLogsBatch 中正确应用 buildUnifiedSpecialSettings,将 DB 审计字段与既有 specialSettings 合并。类型断言 as SpecialSetting[] | null 对 jsonb 列是必要的。


461-480: 分页查询中保持一致的 specialSettings 处理

findUsageLogsWithDetails 使用相同的 buildUnifiedSpecialSettings 调用模式,确保批量与分页查询返回一致的 specialSettings 结构。

两处代码几乎相同,若未来需维护可考虑提取为私有辅助函数,但当前规模下保持内联也可接受。

src/actions/active-sessions.ts (3)

592-593: 动态导入 findMessageRequestAuditBySessionIdAndSequence

遵循文件中既有的动态导入模式,有助于代码分割。


636-639: 条件查询 requestAudit

仅在 effectiveSequence 存在时查询 DB 审计数据,避免无效查询。使用 Promise.resolve(null) 保持 Promise.all 类型一致性。


656-671: 合并 Redis 与 DB specialSettings 后统一构建

合并逻辑正确处理了 null/非数组场景。Redis 数据优先(先入数组),在后续去重时保留优先级。

buildUnifiedSpecialSettings 调用包含所有必要的审计字段,确保派生设置与既有设置正确合并。

tests/unit/actions/active-sessions-special-settings.test.ts (2)

1-67: Mock 设置完整

正确模拟了所有依赖项:认证、缓存、日志、Session 管理器、消息仓库。使用 vi.fn() 而非具体实现,便于测试控制。


110-181: 测试用例覆盖核心场景

  1. Redis 为空时从 DB 审计字段派生设置
  2. Redis 与 DB 同时存在时合并去重

验证逻辑使用 .sort() 进行顺序无关比较,断言去重后 provider_parameter_override 仅保留一条。

可考虑补充边缘场景(如两者均为空、仅 Redis 有数据),但当前覆盖已满足主要需求。

tests/unit/lib/utils/special-settings.test.ts (4)

1-8: 基础测试用例:空输入返回 null

验证 existing: null 且无派生字段时返回 null,符合函数契约。


10-54: guard_intercept 派生测试

覆盖 warmup(action: intercept_response)和 sensitive_word(action: block_request)两种场景,验证 guard、scope、action、statusCode 等字段正确派生。


56-92: Header 覆写派生测试

分别测试 cacheTtlAppliedcontext1mApplied 的派生逻辑,验证类型、scope、ttl/header 字段。


94-146: 合并与去重测试

  • 合并测试:验证 existing 中的 provider_parameter_override 与派生的 guard_intercept 共存
  • 去重测试:验证 existing 已包含相同 guard_intercept 时不重复添加

测试覆盖全面,符合 PR 目标。

src/types/special-settings.ts (3)

8-13: SpecialSetting 联合类型扩展

正确添加三个新变体到联合类型。使用 type 字段作为判别器,支持 TypeScript 类型收窄。


46-63: GuardInterceptSpecialSetting 类型定义

结构设计合理:

  • action 使用字面量联合 "intercept_response" | "block_request" 而非 string
  • statusCodereason 允许 null,与 DB 字段可空性一致
  • 文档注释说明了用途和场景

65-87: Anthropic Header 覆写类型定义

两个类型结构清晰:

  • AnthropicCacheTtlHeaderOverrideSpecialSetting: ttlstring(如 "1h")
  • AnthropicContext1mHeaderOverrideSpecialSetting: header 使用字面量 "anthropic-beta" 确保类型安全
src/repository/message.ts (1)

9-9: 导入语句正确。

正确引入了 SpecialSetting 类型,用于新函数的返回类型定义。

tests/unit/dashboard-logs-virtualized-special-settings-ui.test.tsx (4)

93-128: 测试辅助函数实现良好。

renderWithIntl 函数正确配置了 React Query 和 Next Intl 的测试环境,使用了适当的 provider 嵌套和清理逻辑。


25-79: Mock 数据结构正确且类型安全。

getUsageLogsBatch 的 mock 实现正确模拟了真实数据结构,Line 73 使用 satisfies UsageLogRow 确保了类型安全,specialSettings 数据符合 SpecialSetting 联合类型的结构。


16-17: 移除代码注释中的中文字符。

根据编码规范,**/*.{js,ts,tsx,jsx} 文件中的代码、注释和字符串字面量不得包含非英文字符。

🌐 建议的修复
-// 说明:虚拟列表依赖元素测量与 ResizeObserver;在 happy-dom 下行可能不渲染。
-// 这里把 useVirtualizer 固定为"只渲染首行",确保 UI 断言稳定。
+// Note: Virtual lists depend on element measurement and ResizeObserver, which may not render properly in happy-dom.
+// Here we fix useVirtualizer to "render only the first row" to ensure stable UI assertions.

基于编码规范,所有代码注释应使用英文。

⛔ Skipped due to learnings
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-07T17:05:36.362Z
Learning: Applies to **/*.{ts,tsx,jsx,js} : All user-facing strings must use i18n (5 languages supported: zh-CN, en, ja, ko, de). Never hardcode display text
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-07T17:05:36.362Z
Learning: Applies to **/*.{js,ts,tsx,jsx} : No emoji characters in any code, comments, or string literals

81-81: 移除代码注释中的中文字符。

注释应使用英文以符合编码规范。

🌐 建议的修复
-// 测试环境不加载 next-intl/navigation -> next/navigation 的真实实现(避免 Next.js 运行时依赖)
+// In test environment, avoid loading the real next-intl/navigation -> next/navigation implementation (to avoid Next.js runtime dependencies)

基于编码规范,所有代码注释应使用英文。

⛔ Skipped due to learnings
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-07T17:05:36.362Z
Learning: Applies to **/*.{ts,tsx,jsx,js} : All user-facing strings must use i18n (5 languages supported: zh-CN, en, ja, ko, de). Never hardcode display text
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-07T17:05:36.362Z
Learning: Applies to **/*.{ts,tsx,jsx,js} : Use next-intl for internationalization

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Code Review Summary

This PR successfully unifies the display of request special settings by merging scattered audit fields (blockedBy/blockedReason, cacheTtlApplied, context1mApplied) with existing specialSettings into a single consistent presentation. The implementation is clean and well-tested.

PR Size: L

  • Lines changed: 774 (771 additions + 3 deletions)
  • Files changed: 9

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

Review Coverage

  • Logic and correctness - Clean
  • Security (OWASP Top 10) - Clean
  • Error handling - Clean
  • Type safety - Clean
  • Documentation accuracy - Clean
  • Test coverage - Adequate (unit tests for utility function, integration tests for session details, UI tests for badge display)
  • Code clarity - Good

Analysis Notes

Perspective 1 - Comment Analyzer: All comments accurately describe the code behavior. The Chinese comments provide clear explanations of the purpose of each parameter and function.

Perspective 2 - Test Analyzer: Tests cover the key scenarios:

  • buildUnifiedSpecialSettings utility has comprehensive unit tests covering null inputs, each derived setting type, merging, and deduplication
  • Session details integration test verifies Redis + DB merging
  • UI test verifies the Special badge rendering

Perspective 3 - Silent Failure Hunter: No silent failures detected. The utility function handles null/undefined inputs gracefully by returning null when no settings exist. Error handling in the calling code (getSessionDetails) has proper logging via logger.error.

Perspective 4 - Type Design Auditor:

  • The new SpecialSetting union type is well-designed with proper discriminated unions via the type field
  • The exhaustive switch in buildSettingKey() with the never check ensures type safety for future extensions
  • No use of any type

Perspective 5 - General Code Reviewer:

  • The deduplication logic using buildSettingKey() is sound and creates unique keys for each setting type
  • The guard === "warmup" ? "intercept_response" : "block_request" logic correctly maps guard types to actions
  • No SQL injection or security concerns in the new repository query

Perspective 6 - Code Simplifier: The code is already well-structured. The utility function has a clear single responsibility and the deduplication algorithm is straightforward.


Automated review by Claude AI

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Code Review Summary

No significant issues identified in this PR.

PR Size: L

  • Lines changed: 774
  • Files changed: 9
  • Split suggestions: If you want smaller PRs, consider separating (1) src/types/special-settings.ts + src/lib/utils/special-settings.ts, (2) backend plumbing src/repository/* + src/actions/active-sessions.ts, (3) UI updates + tests.

Review Coverage

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

Automated review by Codex AI

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

  • Reviewed PR #574 (feat/unify-special-settings-display) at head 5581efc71d098a38a85f79a91107a7c67e4a740b.
  • Applied the PR size label size/L.
  • Submitted the required review summary via gh pr review; no diff-line issues met the >=80 confidence threshold, so no inline comments were posted.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 9, 2026

🧪 测试结果

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

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
tests/unit/lib/utils/special-settings.test.ts (1)

5-8: 可选:补充空数组边界测试用例。

当前测试覆盖了 existing: null 的情况。可考虑补充 existing: [](空数组)且无派生设置时的边界用例,验证返回 null

test("existing 为空数组且无派生时应返回 null", () => {
  expect(buildUnifiedSpecialSettings({ existing: [] })).toBe(null);
});
src/repository/usage-logs.ts (1)

465-488: 可选:提取统一设置构建逻辑为公共辅助函数。

findUsageLogsBatchfindUsageLogsWithDetails 中的统一设置构建逻辑完全相同。如果后续有更多类似场景,可考虑提取为私有辅助函数以减少重复:

♻️ 可选重构示例
function buildUnifiedSettingsFromRow(row: {
  specialSettings: unknown;
  blockedBy: string | null;
  blockedReason: string | null;
  statusCode: number | null;
  cacheTtlApplied: string | null;
  context1mApplied: boolean | null;
}): SpecialSetting[] | null {
  const existing = Array.isArray(row.specialSettings)
    ? (row.specialSettings as SpecialSetting[])
    : null;
  return buildUnifiedSpecialSettings({
    existing,
    blockedBy: row.blockedBy,
    blockedReason: row.blockedReason,
    statusCode: row.statusCode,
    cacheTtlApplied: row.cacheTtlApplied,
    context1mApplied: row.context1mApplied,
  });
}

当前实现清晰可读,此重构为可选优化。

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to Reviews > Disable Cache setting

📥 Commits

Reviewing files that changed from the base of the PR and between 5581efc and d0df372.

📒 Files selected for processing (6)
  • src/actions/active-sessions.ts
  • src/lib/utils/special-settings.ts
  • src/repository/message.ts
  • src/repository/usage-logs.ts
  • tests/unit/dashboard-logs-virtualized-special-settings-ui.test.tsx
  • tests/unit/lib/utils/special-settings.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/actions/active-sessions.ts
  • tests/unit/dashboard-logs-virtualized-special-settings-ui.test.tsx
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

No emoji characters in any code, comments, or string literals

Files:

  • tests/unit/lib/utils/special-settings.test.ts
  • src/lib/utils/special-settings.ts
  • src/repository/usage-logs.ts
  • src/repository/message.ts
**/*.{ts,tsx,jsx,js}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,jsx,js}: All user-facing strings must use i18n (5 languages supported: zh-CN, en, ja, ko, de). Never hardcode display text
Use path alias @/ to map to ./src/
Use Biome for code formatting with configuration: double quotes, trailing commas, 2-space indent, 100 character line width
Prefer named exports over default exports
Use next-intl for internationalization
Use Next.js 16 App Router with Hono for API routes

Files:

  • tests/unit/lib/utils/special-settings.test.ts
  • src/lib/utils/special-settings.ts
  • src/repository/usage-logs.ts
  • src/repository/message.ts
**/*.test.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Place unit tests in tests/unit/, integration tests in tests/integration/, and source-adjacent tests in src/**/*.test.ts

Files:

  • tests/unit/lib/utils/special-settings.test.ts
🧠 Learnings (2)
📚 Learning: 2026-01-07T17:05:36.362Z
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-07T17:05:36.362Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Place unit tests in tests/unit/, integration tests in tests/integration/, and source-adjacent tests in src/**/*.test.ts

Applied to files:

  • tests/unit/lib/utils/special-settings.test.ts
📚 Learning: 2026-01-05T03:01:39.354Z
Learnt from: NieiR
Repo: ding113/claude-code-hub PR: 539
File: src/types/user.ts:158-170
Timestamp: 2026-01-05T03:01:39.354Z
Learning: In TypeScript interfaces, explicitly document and enforce distinct meanings for null and undefined. Example: for numeric limits like limitTotalUsd, use 'number | null | undefined' when null signifies explicitly unlimited (e.g., matches DB schema or special UI logic) and undefined signifies 'inherit default'. This pattern should be consistently reflected in type definitions across related fields to preserve semantic clarity between database constraints and UI behavior.

Applied to files:

  • src/lib/utils/special-settings.ts
  • src/repository/usage-logs.ts
  • src/repository/message.ts
🧬 Code graph analysis (4)
tests/unit/lib/utils/special-settings.test.ts (2)
src/lib/utils/special-settings.ts (1)
  • buildUnifiedSpecialSettings (72-126)
src/types/special-settings.ts (1)
  • SpecialSetting (8-13)
src/lib/utils/special-settings.ts (2)
src/types/special-settings.ts (1)
  • SpecialSetting (8-13)
src/lib/special-attributes/index.ts (1)
  • CONTEXT_1M_BETA_HEADER (25-25)
src/repository/usage-logs.ts (2)
src/types/special-settings.ts (1)
  • SpecialSetting (8-13)
src/lib/utils/special-settings.ts (1)
  • buildUnifiedSpecialSettings (72-126)
src/repository/message.ts (2)
src/types/special-settings.ts (1)
  • SpecialSetting (8-13)
src/drizzle/schema.ts (1)
  • messageRequest (276-362)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 🌐 API Tests
  • GitHub Check: Docker Build Test
  • GitHub Check: dev-build-deploy
🔇 Additional comments (6)
src/repository/message.ts (1)

274-318: LGTM!新增审计字段查询函数实现正确。

函数设计清晰:

  • 查询条件正确使用了 sessionId + requestSequence 复合条件,可利用 idx_message_request_session_seq 索引
  • Array.isArray 检查防御性地处理了 specialSettings 的类型转换
  • 返回类型明确区分了 null(无记录)与结构化对象
tests/unit/lib/utils/special-settings.test.ts (1)

1-8: LGTM!测试覆盖全面,结构清晰。

测试文件正确放置于 tests/unit/ 目录,覆盖了 buildUnifiedSpecialSettings 的主要场景:空输入、各类派生设置、合并与去重逻辑。

src/repository/usage-logs.ts (1)

245-268: LGTM!正确集成统一特殊设置构建逻辑。

findUsageLogsBatch 中正确提取现有设置并调用 buildUnifiedSpecialSettings 合并派生字段,确保返回的 specialSettings 是统一视图。

src/lib/utils/special-settings.ts (3)

4-29: LGTM!类型定义清晰,文档注释完善。

BuildUnifiedSpecialSettingsParams 类型定义遵循了项目中 nullundefined 的语义区分(基于已有 learnings),每个字段都有中文 JSDoc 说明其用途。


31-64: LGTM!去重键生成逻辑健壮。

  • changesfixersApplied 数组排序确保键的确定性
  • guard_intercept 的键正确排除了 reason 字段,符合"去重不受 reason 差异影响"的设计意图
  • default 分支的 never 类型穷尽检查可在新增类型时提供编译期保护

72-126: LGTM!统一设置构建函数实现正确。

  • 派生逻辑清晰:warmupintercept_response,其他守卫类型 → block_request
  • context1mApplied === true 严格比较正确处理了 boolean | null | undefined 类型
  • 去重时 base 设置优先于 derived,确保已有设置不被覆盖

@github-actions
Copy link
Contributor

github-actions bot commented Jan 9, 2026

🧪 测试结果

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

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

@ding113 ding113 merged commit 05b4302 into dev Jan 9, 2026
9 checks passed
@github-project-automation github-project-automation bot moved this from Backlog to Done in Claude Code Hub Roadmap Jan 9, 2026
@github-actions github-actions bot mentioned this pull request Jan 10, 2026
5 tasks
@ding113 ding113 deleted the feat/unify-special-settings-display branch January 27, 2026 09:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:session 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