fix: 修复 Code Review 发现的 4 个 High + 1 个 Medium 问题

High-1/2: baseline mode 违反 DB CHECK 约束
- ck_mode_enum 扩展为 ('single','multi','baseline')
- baseline 的 run_type 从 'baseline' 改为 'live'(符合现有约束)
- 新增迁移 0017_mode_baseline

High-3: 限流日志 NameError: ip 未定义
- deps.py:190 的 logger.warning 中 ip → client_ip

High-4: 生产 Cookie 缺少 Secure 标志
- auth.py 登录时根据 APP_ENV 设置 secure=True(生产)

Medium-5: 降级日志参数类型错误
- orchestrator.py:266 ok_reports(list) → len(ok_reports)(int)

附加: PredictRequest mode 字段加 pattern 校验,与 DB 约束同源

Co-Authored-By: new-provider/LongCat-2.0 <<EMAIL>>
This commit is contained in:
shangfangjian
2026-09-21 02:44:32 +08:00
co-authored by new-provider/LongCat-2.0 <
parent 0a6af0657a
commit 675e176603
7 changed files with 47 additions and 4 deletions
+39
View File
@@ -0,0 +1,39 @@
"""扩展 ck_mode_enum 约束支持 baseline 模式
Revision ID: 0017_mode_baseline
Revises: 0016_schedules
Create Date: 2026-09-21
Code Review High-1/2 修复:
业务支持 mode='baseline'(非 LLM 统计基线),但 DB CHECK 约束只允许
('single', 'multi'),导致 baseline 预测写入时 CheckViolation。
run_type='baseline' 改为 'live'(代码侧),约束无需扩展。
"""
from typing import Sequence, Union
from alembic import op
# revision identifiers, used by Alembic.
revision: str = '0017_mode_baseline'
down_revision: Union[str, None] = '0016_schedules'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
op.drop_constraint('ck_mode_enum', 'predictions', type_='check')
op.create_check_constraint(
'ck_mode_enum', 'predictions',
"mode IN ('single', 'multi', 'baseline')",
)
def downgrade() -> None:
# 先清理 baseline 数据再恢复旧约束
op.execute("DELETE FROM predictions WHERE mode = 'baseline'")
op.drop_constraint('ck_mode_enum', 'predictions', type_='check')
op.create_check_constraint(
'ck_mode_enum', 'predictions',
"mode IN ('single', 'multi')",
)
+1 -1
View File
@@ -187,7 +187,7 @@ async def rate_limit_predict(request: Request) -> None:
client_ip = get_client_ip(request)
if not _predict_limiter.is_allowed(client_ip):
logger.warning("rate limit exceeded for %s", ip)
logger.warning("rate limit exceeded for %s", client_ip)
raise HTTPException(
status_code=429,
detail="请求过于频繁,请稍后再试(每分钟最多 10 次)",
+3
View File
@@ -83,6 +83,8 @@ async def login(body: LoginIn, request: Request, response: Response):
raise HTTPException(status_code=401, detail="密码错误")
_fail_times.pop(ip, None)
# Code Review High-4: 生产环境(HHTTPS)下 Cookie 必须带 Secure,防中间人窃取
secure = settings.APP_ENV == "production"
response.set_cookie(
key=SESSION_COOKIE,
value=create_session_token(await get_session_secret()),
@@ -90,6 +92,7 @@ async def login(body: LoginIn, request: Request, response: Response):
httponly=True,
samesite="lax",
path="/",
secure=secure,
)
logger.info("管理员登录成功 (ip=%s)", ip)
return {"ok": True, "expires_in_hours": settings.ADMIN_SESSION_TTL_HOURS}
+1 -1
View File
@@ -116,7 +116,7 @@ async def _persist_baseline(match_id: int, baseline: dict) -> int:
provider_name="baseline",
model="baseline",
mode="baseline",
run_type="baseline",
run_type="live", # baseline 是 live 预测的变体,符合 ck_run_type_enum
values={
"prompt_version": "baseline_v1",
"prompt_tokens": 0,
+1
View File
@@ -48,6 +48,7 @@ class PredictRequest(BaseModel):
prompt_version: str | None = None
mode: str = Field(
"multi",
pattern="^(multi|single|baseline)$",
description="multi(默认,5专家+终裁) | single(单次) | baseline(极简统计基线,不调用 LLM)",
)
use_cache: bool = True
+1 -1
View File
@@ -249,7 +249,7 @@ class Prediction(Base):
CheckConstraint("pred_away_goals >= 0", name="ck_pred_away_goals_nonneg"),
CheckConstraint("subjective_confidence >= 0 AND subjective_confidence <= 1", name="ck_confidence_range"),
CheckConstraint("pred_1x2 IN ('1', 'X', '2')", name="ck_pred_1x2_enum"),
CheckConstraint("mode IN ('single', 'multi')", name="ck_mode_enum"),
CheckConstraint("mode IN ('single', 'multi', 'baseline')", name="ck_mode_enum"),
CheckConstraint("status IN ('success', 'failed', 'degraded')", name="ck_status_enum"),
CheckConstraint("run_type IN ('live', 'backtest')", name="ck_run_type_enum"),
)
+1 -1
View File
@@ -263,7 +263,7 @@ async def predict_match_multi(
# 所有专家无数据/均失败:跳过终裁,标记 degraded
logger.warning(
"预测降级 match=%s mode=%s status=degraded experts=%d/%d 均无有效数据",
match_id, "multi", ok_reports, len(reports),
match_id, "multi", len(ok_reports), len(reports),
)
# 无有效专家时不调用 aggregator provider,避免多余开销
# model 使用 settings 默认值占位(无实际 LLM 调用)