From b77a22af6fce8a32ced9027c5bea231e245aa4c0 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 15 Jul 2026 16:11:41 +0200 Subject: [PATCH] =?UTF-8?q?docs(sub2api):=20=E6=98=8E=E7=A1=AE=E8=A1=A5?= =?UTF-8?q?=E5=81=BF=E5=85=AC=E5=91=8A=E9=80=82=E7=94=A8=E8=8C=83=E5=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../unidesk-sub2api/references/codex-pool.md | 6 +++ .../R3.7_Task_Report.md | 37 +++++++++++++++++++ docs/MDTODO/sub2api-upstream-reliability.md | 4 ++ .../announcements.ts | 6 ++- 4 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 docs/MDTODO/details/sub2api-upstream-reliability/R3.7_Task_Report.md diff --git a/.agents/skills/unidesk-sub2api/references/codex-pool.md b/.agents/skills/unidesk-sub2api/references/codex-pool.md index 36d9256b..b678ae99 100644 --- a/.agents/skills/unidesk-sub2api/references/codex-pool.md +++ b/.agents/skills/unidesk-sub2api/references/codex-pool.md @@ -164,6 +164,12 @@ bun scripts/cli.ts platform-infra sub2api codex-pool cleanup-probes --target D60 - `announcements list|get|create` 管理 Sub2API 原生公告: - `list` 和 `get` 只读调用原生 `/api/v1/admin/announcements`,支持分页、状态、搜索、排序和按 ID 下钻; - `create` 支持标题、Markdown 内容、`draft|active|archived`、`silent|popup`、原生 `any_of/all_of` targeting 以及可选 Unix 秒或 RFC3339 开始/结束时间;targeting 必须通过 `--targeting-json` 的 JSON 解析器输入,不拼接临时结构; + - 每次 create 的用户可见正文都必须明确业务时间范围和接收范围;`targeting` 只控制投递对象,不能替代公告正文中的业务适用范围; + - 补偿公告必须在正文逐项列出: + - 故障影响时间窗或补偿资格统计时间窗; + - 全部实际接收用户的稳定用户 ID 和邮箱;邮箱可以脱敏,但禁止只写“符合条件的用户”或其他无法对账的泛化描述; + - 每名用户的补偿金额和本批总额;候选名单与实际发放名单不一致时,两者及排除原因都要明确; + - create dry-run 和 confirm 输出都显示人工范围检查;CLI 不根据标题关键词猜测公告类型,也不把内容出现某些词误判为范围已经完整,操作者必须在 confirm 前核对正文; - `create` 默认只输出完整预览,固定 `mutation=false`、`writeAttempted=0`,不登录运行面也不调用创建 API; - 只有显式 `--confirm` 才调用原生创建 API,并按返回的正整数 ID 回读;对账必须逐字段核对 `title`、`content`、`status`、`notify_mode`、`targeting`、`starts_at`、`ends_at`,输出 `mismatchedFields`,任一字段不一致都不得报告成功;发布公告属于面向客户的外部影响操作,必须取得用户对本次具体标题、内容、状态、通知方式、targeting 和时间窗的明确授权; - 默认输出 Kubernetes 风格紧凑文本,显式 `--json` 输出同一份机器结构;命令不打印管理凭据或 Secret。 diff --git a/docs/MDTODO/details/sub2api-upstream-reliability/R3.7_Task_Report.md b/docs/MDTODO/details/sub2api-upstream-reliability/R3.7_Task_Report.md new file mode 100644 index 00000000..a21db99d --- /dev/null +++ b/docs/MDTODO/details/sub2api-upstream-reliability/R3.7_Task_Report.md @@ -0,0 +1,37 @@ +# R3.7 公告范围规则固化报告 + +## 目标 + +补偿公告不能只写“符合条件的用户”。公告必须让操作者和接收方明确知道补偿对应哪个时间段、哪些用户以及多少金额;本次只固化规则,不重新发布或修改既有公告。 + +## Skill 规则 + +Sub2API `codex-pool.md` 已明确: + +- 每次 create 的用户可见正文必须写明业务时间范围和接收范围。 +- `targeting` 只控制公告投递,不能替代补偿资格或实际发放范围。 +- 补偿公告必须列出故障影响时间窗或补偿资格统计时间窗。 +- 必须列出全部实际接收用户的稳定用户 ID 和邮箱;邮箱可以脱敏,但禁止只写泛化描述。 +- 必须列出每人金额和本批总额。 +- 候选名单与实际发放名单不一致时,必须同时写明两者和排除原因。 + +## CLI 可见性 + +公告 create 的 dry-run 和 confirm 输出新增两条固定人工检查: + +- `SCOPE-CHECK`:正文必须明确时间范围和接收范围,targeting 不能替代业务范围。 +- `COMPENSATION-CHECK`:列出全部接收用户 ID、可脱敏邮箱、每人金额和总额。 + +CLI 不通过标题关键词猜测公告类型,也不做容易误判的内容关键词自动通过;最终 confirm 前由操作者核对完整正文。 + +## 验证 + +- 使用包含参数化时间窗、用户 ID、脱敏邮箱、每人金额和总额的公告执行 dry-run。 +- 输出 `mutation=false`、`writeAttempted=0`,两条范围检查和完整正文均可见。 +- 未登录运行面,未调用公告创建 API,未修改或重新发布公告 ID 1。 +- Sub2API skill `quick_validate` 通过。 +- `git diff --check` 通过。 + +## 结论 + +后续补偿公告在发布前会同时经过 skill 规则和 CLI create 预览提醒,范围必须可由时间窗和用户 ID 对账;上次公告仅保留历史事实,不做重发。 diff --git a/docs/MDTODO/sub2api-upstream-reliability.md b/docs/MDTODO/sub2api-upstream-reliability.md index 8119a47e..5c551b0e 100644 --- a/docs/MDTODO/sub2api-upstream-reliability.md +++ b/docs/MDTODO/sub2api-upstream-reliability.md @@ -243,3 +243,7 @@ ### R3.6 [completed] 按用户明确授权,对固定补偿候选用户 ID 11、10、7、22、19 每人增加 30 USD,总额 150 USD,并并发发布服务稳定性补偿公告;两条操作都必须通过 Sub2API 原生受控 CLI 显式 confirm,使用精确名单、写后回读和公告字段对账,禁止扩大到 YAML 排除员工或管理员,完成任务后将详细报告写入[任务报告](./details/sub2api-upstream-reliability/R3.6_Task_Report.md)。 + +### R3.7 [completed] + +在 Sub2API 公告 skill 与 CLI create 预览中固化明确范围规则:补偿公告必须在用户可见正文列出故障或补偿时间窗、全部实际接收用户、每人金额和总额;邮箱允许脱敏但必须保留稳定用户 ID,`targeting` 仅表示投递范围、不能替代补偿资格名单。本次只记录并验证 dry-run 展示,不重新发布或修改既有公告,完成任务后将详细报告写入[任务报告](./details/sub2api-upstream-reliability/R3.7_Task_Report.md)。 diff --git a/scripts/src/platform-infra-sub2api-codex/announcements.ts b/scripts/src/platform-infra-sub2api-codex/announcements.ts index c4384617..a4af14cd 100644 --- a/scripts/src/platform-infra-sub2api-codex/announcements.ts +++ b/scripts/src/platform-infra-sub2api-codex/announcements.ts @@ -169,6 +169,8 @@ function renderAnnouncements(response: Record): RenderedCliResu const announcement = record(report.announcement); const mismatchedFields = Array.isArray(report.mismatchedFields) ? report.mismatchedFields.join(",") : "-"; lines.push(`WRITE attempted=${text(report.writeAttempted)} reconciled=${text(report.reconciled)} id=${text(announcement.id)} mismatched-fields=${mismatchedFields || "-"}`); + lines.push("SCOPE-CHECK manual-required: 正文必须明确时间范围和接收范围;targeting 不能替代业务范围说明"); + lines.push("COMPENSATION-CHECK manual-required: 列出全部接收用户 ID、可脱敏邮箱、每人金额和总额"); lines.push(`TITLE ${text(announcement.title)}`, `STATUS ${text(announcement.status)} NOTIFY_MODE ${text(announcement.notify_mode)}`, `STARTS_AT ${text(announcement.starts_at)} ENDS_AT ${text(announcement.ends_at)}`, `TARGETING ${JSON.stringify(record(announcement.targeting))}`, "CONTENT", String(announcement.content ?? "")); } if (typeof report.error === "string") lines.push(`ERROR ${text(report.error)}`); @@ -184,7 +186,9 @@ function renderAnnouncementsHelp(): RenderedCliResult { "platform-infra sub2api codex-pool announcements list [--page 1] [--page-size 20] [--status draft|active|archived] [--search text] [--sort-by created_at] [--sort-order asc|desc] [--target PK01] [--json]", "platform-infra sub2api codex-pool announcements get --id [--target PK01] [--json]", "platform-infra sub2api codex-pool announcements create --title (--content |--content-file ) [--announcement-status draft|active|archived] [--notify-mode silent|popup] [--targeting-json ] [--starts-at ] [--ends-at ] [--target PK01] [--confirm] [--json]", - "create defaults to dry-run; only --confirm calls the native Sub2API create API and then reconciles every planned announcement field after reading the returned ID back.", + "create 默认 dry-run;只有 --confirm 才调用 Sub2API 原生创建 API,并按返回 ID 回读对账全部公告字段。", + "范围要求:正文必须明确时间范围和接收范围;--targeting-json 只控制投递,不能替代业务适用范围。", + "补偿公告:必须列出故障或补偿时间窗、全部实际接收用户 ID、可脱敏邮箱、每人金额和总额;禁止只写‘符合条件的用户’。", ].join("\n"); return { ok: true, command: "platform-infra sub2api codex-pool announcements --help", renderedText, contentType: "text/plain", projection: { ok: true, mutation: false } }; }