Files
Jyotisha/docs/tasks/PROGRESS-content-moderation-20260930.md
T

41 lines
4.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PROGRESS · 敏感内容审核 · 2026-09-30
> 合规轮四项之一(产品 2026-09-30「合规与法律的前四个你可以帮我做吗」)。执行:Claude fork D,直接执行。分支 `codex/content-moderation-20260930`,基于 `codex/compliance-base-20260930`(= origin/staging `5208f19b` + `lib/legal-entity.ts`)。
> 产品决定:输入命中 → 不发模型、不扣点、固定一句;输出命中 → 整段替换并退点;命中留脱敏日志。
## 做了什么
| 部分 | 位置 | 说明 |
|---|---|---|
| 审核接口 | `src/lib/moderation/index.ts` | `moderate(text, side, context)` → `{verdict, categories, ruleIds, providerId}`;本地词表先跑,命中即终判;配置了阿里云再跑远端(≤1.5 s);远端失败/超时 → 沿用本地判定(输入:本地兜底不放空;输出:不因服务不可用而扣下回答) |
| 本地词表 | `src/lib/moderation/lexicon.ts` | 12 条规则、5 类(政治 3 / 暴恐 3 / 涉未成年色情 1 / 自伤 2 / 违法交易 3),均为多字短语;归一化去空格标点零宽、全角转半角 |
| 阿里云适配 | `src/lib/moderation/aliyun-provider.ts` | TextModerationPlus(llm_query_moderation / llm_response_moderation),RPC 签名 v1;high → 拦,medium → 待复核(放行并记录);endpoint 限定 `*.aliyuncs.com`;超 2000 字分段,最多 4 段 |
| 日志 | `src/lib/moderation/log.ts` + 迁移 `20260930040000_moderation_events.sql` | 只记类别、规则编号/服务标签、方向、入口、模型、request、user_id;不存原文;仅 service_role |
| 普通咨询 | `app/api/consult/route.ts` | 输入:在 prompt-extraction 守卫之后、预留点数之前;输出:三条 agentic 流 `moderateOutput` + `completeResponse` 兜底(覆盖旧 text/plain 运行时);命中走新函数 `complete_consultation_moderated`(复制自免费结算,释放预留) |
| 流式替换 | `lib/stream-agent-response.ts`、`lib/consultation-agent-events.ts`、`lib/consultation-run-timeline.ts`、`hooks/use-consultation-run.ts` | `answer.delta` 增加可选 `replace: true`;客户端时间线与发送钩子遇到即整段替换 |
| 生时校正 | `v9/agent-route-request.ts`(输入)、`v9/agent-run-finish.ts`(输出) | 输出命中:`skipBilling` → `billing.release()`,spoken 换成撤下提示,走既有 replace |
| 出生时间引导 | `app/api/birth-time-guide/route.ts` | `draft_evidence.message` / `reframe_unmatched.note` 输入审核 |
| 后台 | `app/api/admin/moderation-events`、`components/admin/moderation-events-resource.tsx`、菜单「内容审核」 | 只读、`audit.read`、14 天分类计数 |
未接入(无用户自由文本进模型):报告生成、今日星语、合盘、星盘 / 星历。Python API 未发现把用户自由文本送进模型的端点(模型调用都在 Next.js 侧)。
## 既有断言改动(原值 / 新值 / 原因)
| 文件 | 原值 | 新值 | 原因 |
|---|---|---|---|
| `tests/test_api_server_security.py` app_routes 列表 | admin/models 后直接 admin/orders | 中间加 admin/moderation-events | 新增只读后台页 |
| `frontend/tests/admin-contracts.test.ts` 只读资源 | 四个 | 加 moderation-events | 同一只读约束覆盖新页 |
## 验证(Claude fork 实跑,Linux,Node 22.14)
| 项 | 结果 |
|---|---|
| `tsc --noEmit` | 0 错 |
| `npm run lint` | 0 error,126 warning(同基线) |
| 新增 `content-moderation.test.ts` | 10/10:占星用语 8 句全部放行;五类各自拦截含空格/全角/零宽规避;自伤给求助句;阿里云 high→拦、medium→待复核、none→放行,签名与表单校验;本地拦截不调远端;远端超时(50 ms)/500 → 沿用本地;无钥匙/非 aliyuncs.com 只用本地且只警告一次;日志不含原文、写失败不抛;流式回答被整段替换且 onComplete 收到提示句、时间线最终文本为提示句;路由里输入审核在预留点数之前、校正输出审核在结算之前 |
| `npm test` 全量 | 4,428 / fail 26。与基线(24 条环境失败)相比多 2 条:`a lookup does not reset the answer clock…` 与 `a refresh inside a rectification conversation stays in it…`,均为并发负载下超时(后者等待 16.8 s 超时),单独各跑两次全部通过,且不涉及本次改动文件。新增 10 条,消失 0 条 |
| `next build` | `/` 仍 `○ Static`;首屏 gzip-9 646,505 B(基线 646,480 B,+25 B) |
| Python | `tests/test_api_server_security.py::test_capability_audit_scans_registry_and_local_sources` 通过;快速门 Python 步 1000 passed / 2 skipped(门内 `npm test` 步走系统 Node 20,属已知环境失败) |
未验证:阿里云真实调用;迁移在真实 PostgreSQL 上执行(无 Docker);浏览器中被拦与被替换的表现;遗留 text/plain 运行时(无法就地替换,只保证存档与结算为提示句)。