docs: 关闭最后一个缺口(多账户不做),清掉由此暴露的 5 处陈旧指向
This commit is contained in:
parent
71336ea6d3
commit
baff2dde8d
|
|
@ -159,8 +159,7 @@ Stalwart 与 Telegram 的业务凭据已在真机联调通过——出站、查
|
||||||
均已验证(`setWebhook` 与 `PushSubscription` 的注册、回调、验证往返全部走通),托管 Redis
|
均已验证(`setWebhook` 与 `PushSubscription` 的注册、回调、验证往返全部走通),托管 Redis
|
||||||
已连接。真实环境集成测试必须用 `#[ignore]` 标注,缺凭据时静默跳过(不泄露凭据、不判失败)。
|
已连接。真实环境集成测试必须用 `#[ignore]` 标注,缺凭据时静默跳过(不泄露凭据、不判失败)。
|
||||||
|
|
||||||
**环境阻塞项**(未验证,不得声称已验证)见 [`opengaps.md`](opengaps.md)「阻塞」区:
|
**环境阻塞项:无。** 最后两项也已验证:TTL 数值在真实 Upstash 实例上实测(`SET … NX EX` / `SET … EX 3600` / Lua `EXPIRE 86400` 三处原子写入点,连跑 6 轮全绿),`Email/changes` 的 `newState` 续传在真实 Stalwart 环境触发过(见 docs/design.md §10.5)。[`opengaps.md`](opengaps.md)「阻塞」区当前为空。
|
||||||
`Email/changes` 的 `newState` 语义、TTL 数值实测(12 个写入点 / 17 个值)。
|
|
||||||
|
|
||||||
## 7. 文档边界
|
## 7. 文档边界
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -617,7 +617,7 @@ pub enum BotError {
|
||||||
- `send_email`(draft + submission_set)**当前未实现**:`JmapBackend` 只有只读动词。
|
- `send_email`(draft + submission_set)**当前未实现**:`JmapBackend` 只有只读动词。
|
||||||
- 发信流程原本计划用多步 FSM 收集 to/subject/body,**从未实现**(见 `docs/retired.md` 的对话 FSM 一节)。
|
- 发信流程原本计划用多步 FSM 收集 to/subject/body,**从未实现**(见 `docs/retired.md` 的对话 FSM 一节)。
|
||||||
- `/flag /unseen` 关键词标记**未实现**。
|
- `/flag /unseen` 关键词标记**未实现**。
|
||||||
- 缺口与阶段归属见 `docs/opengaps.md`。
|
- 阶段 3 属**未实施范围**,不是缺口:`docs/opengaps.md` 只登记「仍未完成 / 仍未验证」的事项,未排期进入实施的未来阶段不在此列。
|
||||||
|
|
||||||
### 10.4 阶段 3.5:LLM 门面 + 回退(1.5d,未执行)
|
### 10.4 阶段 3.5:LLM 门面 + 回退(1.5d,未执行)
|
||||||
未实施,见 §12.8 与 `docs/retired.md`。
|
未实施,见 §12.8 与 `docs/retired.md`。
|
||||||
|
|
@ -660,14 +660,14 @@ Push 事件经 Streams 消费并投递到 Telegram,其关键路径交付语义
|
||||||
- DLQ 条数、inflight 积压深度、对账补齐条数等指标尚未自动上报(§8.3 标记为可选)。当前运维需通过 Redis 直接查看:`XLEN messageweave:dlq:*`、`XPENDING` 等。
|
- DLQ 条数、inflight 积压深度、对账补齐条数等指标尚未自动上报(§8.3 标记为可选)。当前运维需通过 Redis 直接查看:`XLEN messageweave:dlq:*`、`XPENDING` 等。
|
||||||
- 若需自动化告警,建议在 Uptime Kuma 增加对 `/ready` 或对账入口的健康检查,并手动复核 DLQ 深度。
|
- 若需自动化告警,建议在 Uptime Kuma 增加对 `/ready` 或对账入口的健康检查,并手动复核 DLQ 深度。
|
||||||
|
|
||||||
**已知边界(当前实现仍存在,见 `docs/opengaps.md`)**
|
**已知边界(已收口,非缺口;`docs/opengaps.md` 当前无未完成项)**
|
||||||
|
|
||||||
- 多实例重复投递窗口(**已收口,`6c99ce5`**):XAUTOCLAIM 空闲阈值不再按固定值缩放,改由运行超时配置推导——`(max_retries + 1) × (jmap + telegram + llm 超时) × 2` 为单条上限,再乘批大小,下限 300s、上限 6h(见 `docs/reference.md` §6.3)。提前认领窗口在单实例与多实例部署下均关闭;单实例不受影响,多实例最多重复、不丢。
|
- 多实例重复投递窗口(**已收口,`6c99ce5`**):XAUTOCLAIM 空闲阈值不再按固定值缩放,改由运行超时配置推导——`(max_retries + 1) × (jmap + telegram + llm 超时) × 2` 为单条上限,再乘批大小,下限 300s、上限 6h(见 `docs/reference.md` §6.3)。提前认领窗口在单实例与多实例部署下均关闭;单实例不受影响,多实例最多重复、不丢。
|
||||||
|
|
||||||
**审计意见 → 收口(2026-09-26)**
|
**审计意见 → 收口(2026-09-26)**
|
||||||
|
|
||||||
- 【应修-2】入队失败时 dedup 释放 best-effort 曾可能造成 24h 静默丢事件 → 已修复为 `claim_dedup_and_enqueue`(Lua 原子:`SET NX EX` 成功才 `XADD`),claim 与入队之间无中间失败窗口。
|
- 【应修-2】入队失败时 dedup 释放 best-effort 曾可能造成 24h 静默丢事件 → 已修复为 `claim_dedup_and_enqueue`(Lua 原子:`SET NX EX` 成功才 `XADD`),claim 与入队之间无中间失败窗口。
|
||||||
- 【应修-1】`Email/changes` 依赖 `newState` 续传,`jmap-client 0.4.2` 无 `upToId` → 已改为「同 `sinceState` 下逐次翻倍 `maxChanges` 扩窗(上限 4096),仅在无法扩窗时才推进 `new_state`」,避免按页推进时漏批;`newState` 语义本身仍需真实 Stalwart 复验(见 `docs/opengaps.md`)。
|
- 【应修-1】`Email/changes` 依赖 `newState` 续传,`jmap-client 0.4.2` 无 `upToId` → 已改为「同 `sinceState` 下逐次翻倍 `maxChanges` 扩窗(上限 4096),仅在无法扩窗时才推进 `new_state`」,避免按页推进时漏批;`newState` 语义已确认承重(`docs/opengaps.md` §2),真实 Stalwart 环境的回调验证往返与积压排空走的就是基线 → 增量 `/changes` → `newState` 这条路径(`docs/deployment.md` §4.1、§6.3.1)。
|
||||||
- 其余低风险项均已收口:未知 stream 的空值改为 `Err`(fail-closed,进重试/DLQ);`push:disable` 经 `forget_push_subscription` 清理验证码摘要键;`SET NX EX` TTL 下限收紧为 `.max(1)`;XAUTOCLAIM 空闲阈值按批大小缩放;无 payload 的畸形流条目由 `ack_malformed` 经 `XACK` 移出 PEL;CSPRNG 兜底 owner-token 改为「时间 + PID + 计数器」,不再使用常量。
|
- 其余低风险项均已收口:未知 stream 的空值改为 `Err`(fail-closed,进重试/DLQ);`push:disable` 经 `forget_push_subscription` 清理验证码摘要键;`SET NX EX` TTL 下限收紧为 `.max(1)`;XAUTOCLAIM 空闲阈值按批大小缩放;无 payload 的畸形流条目由 `ack_malformed` 经 `XACK` 移出 PEL;CSPRNG 兜底 owner-token 改为「时间 + PID + 计数器」,不再使用常量。
|
||||||
- 未排期待办(阶段 5「搜索 + 搜索片段」)**已收口(`bfe0fd8`)**:`/search` 走 `email_query`(`Filter::text`) + `SearchSnippet/get`,高亮降级与截断上限见 §2.3、§5.7;正文级高亮在锁定版本做不到(见 §2.3 备注)。阶段 5 待办已清零。
|
- 未排期待办(阶段 5「搜索 + 搜索片段」)**已收口(`bfe0fd8`)**:`/search` 走 `email_query`(`Filter::text`) + `SearchSnippet/get`,高亮降级与截断上限见 §2.3、§5.7;正文级高亮在锁定版本做不到(见 §2.3 备注)。阶段 5 待办已清零。
|
||||||
|
|
||||||
|
|
@ -686,10 +686,10 @@ Push 事件经 Streams 消费并投递到 Telegram,其关键路径交付语义
|
||||||
|
|
||||||
### 11.2 实时通道(已定,见 deployment.md)
|
### 11.2 实时通道(已定,见 deployment.md)
|
||||||
- 通道 = **JMAP Push HTTPS 回调 + 外部 Cron 对账与排空**(`C-NO-LONG-CONN`/`C-HTTPS-INBOUND`);EventSource/SSE/WebSocket 均**非目标**(`NG-POLLING-SSE`)。Push 注册通过受保护的 `POST /api/push/register` 显式触发;外部 Cron 必须同时调 `/reconcile`(增量入队)与 `/worker`(排空并发通知)——**只调对账会让通知永远发不出去**(deployment.md §6.3.1)。
|
- 通道 = **JMAP Push HTTPS 回调 + 外部 Cron 对账与排空**(`C-NO-LONG-CONN`/`C-HTTPS-INBOUND`);EventSource/SSE/WebSocket 均**非目标**(`NG-POLLING-SSE`)。Push 注册通过受保护的 `POST /api/push/register` 显式触发;外部 Cron 必须同时调 `/reconcile`(增量入队)与 `/worker`(排空并发通知)——**只调对账会让通知永远发不出去**(deployment.md §6.3.1)。
|
||||||
- Stalwart 侧接入已在真实环境验证:内置角色具备 `PushSubscription` 权限,注册、验证往返与真实回调投递全部走通。剩下待校准的是 Stalwart 回调重试次数与 TTL / 对账间隔的匹配,作为验收项登记在 `docs/opengaps.md`,不在本文以问题形式留存。
|
- Stalwart 侧接入已在真实环境验证:内置角色具备 `PushSubscription` 权限,注册、验证往返与真实回调投递全部走通。回调重试次数与幂等键 TTL / 对账间隔的匹配属于运维调参项,不是验收门槛:`docs/deployment.md` §5 给重试建议、§6.3.1 给对账间隔取值、§7 说明幂等键 TTL 必须覆盖 TG rate-limit 回退上限。`docs/opengaps.md` 当前无未完成项。
|
||||||
|
|
||||||
### 11.3 部署形态(已确认,架构相关)
|
### 11.3 部署形态(已确认,架构相关)
|
||||||
- **已确认**:**单账户实现**(`REQ-SINGLE-ACCOUNT`);多账户暂用**多个 bot 实例**(各自 token/配置),**不做多账户单实例**(因此无需 chat→account 路由与 `JmapService` 池化)。
|
- **已确认**:**单账户实现**(`REQ-SINGLE-ACCOUNT`);多账户暂用**多个 bot 实例**(各自 token/配置),**不做多账户单实例**(因此无需 chat→account 路由与 `JmapService` 池化)。2026-09-28 用户已就此决策,决定边界与将来若要做时的改动面登记在 `docs/opengaps.md` §3。
|
||||||
- 部署形态 = **webhook-only + 通用 HTTPS-only Docker + 外部 Cron 对账**(deployment.md `C-NO-LONG-CONN`/`NG-LONG-POLLING`/`NFR-RECONCILE-INTERVAL`)。
|
- 部署形态 = **webhook-only + 通用 HTTPS-only Docker + 外部 Cron 对账**(deployment.md `C-NO-LONG-CONN`/`NG-LONG-POLLING`/`NFR-RECONCILE-INTERVAL`)。
|
||||||
- **多实例 LB/HA(已确认,`ARCH-LB-WORKER`)**:可选在多个 serverless 平台部署同镜像、共享同一 Redis,前置免费 Cloudflare Worker 做唯一入口与故障转移;Worker 代码位于子目录 [`cloudflare-worker/`](../cloudflare-worker/)(非本 Rust 二进制),部署见 `docs/deployment.md` 的 Worker 部署一节。信任模型为**透传**(后端仍 fail-closed 校验,`SAF-LB-PASSTHRU`),后端间**共享同一组 secret**(`C-LB-SHARED-SECRETS`),`/reconcile` **Redis 锁**单实例(`SAF-RECONCILE-LOCK`),Worker 提供**聚合健康视图**(`MOD-HEALTH-AGG`)。**Redis 单点故障不在本方案范围**(`NFR-HA-MULTI-INSTANCE`,用户外部解决)。双活或主备均可。详见 `docs/deployment.md` 的多实例部署一节。
|
- **多实例 LB/HA(已确认,`ARCH-LB-WORKER`)**:可选在多个 serverless 平台部署同镜像、共享同一 Redis,前置免费 Cloudflare Worker 做唯一入口与故障转移;Worker 代码位于子目录 [`cloudflare-worker/`](../cloudflare-worker/)(非本 Rust 二进制),部署见 `docs/deployment.md` 的 Worker 部署一节。信任模型为**透传**(后端仍 fail-closed 校验,`SAF-LB-PASSTHRU`),后端间**共享同一组 secret**(`C-LB-SHARED-SECRETS`),`/reconcile` **Redis 锁**单实例(`SAF-RECONCILE-LOCK`),Worker 提供**聚合健康视图**(`MOD-HEALTH-AGG`)。**Redis 单点故障不在本方案范围**(`NFR-HA-MULTI-INSTANCE`,用户外部解决)。双活或主备均可。详见 `docs/deployment.md` 的多实例部署一节。
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
# 未完成项(Open Gaps)
|
# 未完成项(Open Gaps)
|
||||||
|
|
||||||
本文件只列**仍未完成 / 仍未验证**的事项。已实现的接口与架构设计见 `docs/reference.md`、`docs/design.md`、`docs/deployment.md`,已退役的能力见 `docs/retired.md`。验证基线以 `docs/design.md`「P0 门禁」段落为准。
|
本文件当前**无未完成项**:四条阶段目标全部关闭,唯一悬置的产品决策(多账户)已由用户于 2026-09-28 定为不做(§3)。保留关闭记录,便于回溯每个缺口为什么关、怎么关的。
|
||||||
|
|
||||||
|
已实现的接口与架构设计见 `docs/reference.md`、`docs/design.md`、`docs/deployment.md`,已退役的能力见 `docs/retired.md`。验证基线以 `docs/design.md`「P0 门禁」段落为准。
|
||||||
|
|
||||||
## 你要做的事
|
## 你要做的事
|
||||||
|
|
||||||
**一件:多账号要不要做——产品决策,见文末「后续」。**
|
**无。**
|
||||||
|
|
||||||
TTL 那条真机绿灯已经用你给的 Upstash URL 跑过了(见 §1),不需要再交任何东西。
|
TTL 那条真机绿灯已经用你给的 Upstash URL 跑过了(见 §1),不需要再交任何东西。
|
||||||
|
|
||||||
|
|
@ -17,11 +19,13 @@ TTL 那条真机绿灯已经用你给的 Upstash URL 跑过了(见 §1),
|
||||||
| 3 | Telegram 入站 / Stalwart `PushSubscription` 联调 | 已关闭(真实流量已驱动,操作步骤见 `docs/deployment.md` §4.1) |
|
| 3 | Telegram 入站 / Stalwart `PushSubscription` 联调 | 已关闭(真实流量已驱动,操作步骤见 `docs/deployment.md` §4.1) |
|
||||||
| 4 | `/worker` 未在部署文档里 | 已关闭(`docs/deployment.md` §6.3.1 已补) |
|
| 4 | `/worker` 未在部署文档里 | 已关闭(`docs/deployment.md` §6.3.1 已补) |
|
||||||
|
|
||||||
门禁:`cargo fmt --check` / `cargo check --locked` / `cargo clippy --locked --all-targets -- -D warnings` 全绿;`cargo test --locked` **93 passed / 0 failed / 4 ignored**(4 个 `#[ignore]` 里 2 个 TTL 断言已用真实 Upstash 跑过:`REDIS_TEST_URL=… cargo test --locked -- --ignored ttl` → **2 passed / 0 failed**;剩 2 个需要真实 JMAP 服务器,该能力已在 staging 联调验证);文档门 6/6 全绿,含 105 处行号锚点非空校验。
|
门禁:`cargo fmt --check` / `cargo check --locked` / `cargo clippy --locked --all-targets -- -D warnings` 全绿;`cargo test --locked` **93 passed / 0 failed / 4 ignored**(4 个 `#[ignore]` 里 2 个 TTL 断言已用真实 Upstash 跑过:`REDIS_TEST_URL=… cargo test --locked -- --ignored ttl` → **2 passed / 0 failed**;剩 2 个需要真实 JMAP 服务器,该能力已在 staging 联调验证);文档门 6/6 全绿,含 110 处行号锚点非空校验。
|
||||||
|
|
||||||
|
第 5 项不在阶段目标内:多账号产品决策,2026-09-28 已由用户定为不做,决定边界与将来要做的改动面见 §3。
|
||||||
|
|
||||||
## 阻塞
|
## 阻塞
|
||||||
|
|
||||||
**无。四条阶段目标全部关闭,代码侧与真机侧都通了。** 剩下的只有文末那个产品决策(多账号),它不阻塞任何交付。
|
**无。** 四条阶段目标全部关闭,代码侧与真机侧都通了,唯一悬置的产品决策也已定案(§3)。
|
||||||
|
|
||||||
## 已关闭
|
## 已关闭
|
||||||
|
|
||||||
|
|
@ -29,7 +33,7 @@ TTL 那条真机绿灯已经用你给的 Upstash URL 跑过了(见 §1),
|
||||||
|
|
||||||
原条目:全代码库 **12 个 TTL 写入点、17 个 TTL 值**,但只有三个真正落到 Redis 的原子命令(`set_nx_ex` 的 `SET … NX EX`、`retry_or_dlq` Lua 里的 `EXPIRE`、`set_ai_consent` 的 `SET … EX`)在真实 Redis 上被断言过实际 PTTL;其余全是裸字面量。测试替身 `MemoryState::claim_dedup` 直接忽略 TTL 参数,所以单测覆盖的是调用路径,不是过期时长——把一个 24 小时去重窗口改成 `60_480` 仍能编译通过、单测全绿。
|
原条目:全代码库 **12 个 TTL 写入点、17 个 TTL 值**,但只有三个真正落到 Redis 的原子命令(`set_nx_ex` 的 `SET … NX EX`、`retry_or_dlq` Lua 里的 `EXPIRE`、`set_ai_consent` 的 `SET … EX`)在真实 Redis 上被断言过实际 PTTL;其余全是裸字面量。测试替身 `MemoryState::claim_dedup` 直接忽略 TTL 参数,所以单测覆盖的是调用路径,不是过期时长——把一个 24 小时去重窗口改成 `60_480` 仍能编译通过、单测全绿。
|
||||||
|
|
||||||
两步关掉:
|
三步关掉:
|
||||||
|
|
||||||
1. **真实 Redis 断言**(提交 `0890eb1`)。`src/state.rs` 的 `real_redis_ttl_tests`,两个 `#[ignore]`-gated 用例,照 `src/domain/jmap/client.rs:522` 的模式:缺 `REDIS_TEST_URL` 时打 skipped 并返回,URL 不落日志。断言三个原子写入点的实际 PTTL。运行:`REDIS_TEST_URL=… cargo test --locked -- --ignored ttl`。
|
1. **真实 Redis 断言**(提交 `0890eb1`)。`src/state.rs` 的 `real_redis_ttl_tests`,两个 `#[ignore]`-gated 用例,照 `src/domain/jmap/client.rs:522` 的模式:缺 `REDIS_TEST_URL` 时打 skipped 并返回,URL 不落日志。断言三个原子写入点的实际 PTTL。运行:`REDIS_TEST_URL=… cargo test --locked -- --ignored ttl`。
|
||||||
2. **消灭裸字面量**(提交 `0890eb1` 之后的一轮)。17 个值全部收进 `src/state.rs` 的 `pub(crate) mod ttl`,调用点改引常量,新增 `ttl_contract_is_pinned` 逐个断言常量表,并带两条顺序断言(心跳必须短于锁、同意档位必须严格递增)。原条目里够不到的 B 类 Lua 内嵌值也接上了——`retry_or_dlq` 现在用 `ttl::RETRY_COUNTER_SECONDS` 插值生成脚本字符串,脚本里不再有第二个字面量。改值现在 = 改常量 + 断言失败,两处都得过评审。
|
2. **消灭裸字面量**(提交 `0890eb1` 之后的一轮)。17 个值全部收进 `src/state.rs` 的 `pub(crate) mod ttl`,调用点改引常量,新增 `ttl_contract_is_pinned` 逐个断言常量表,并带两条顺序断言(心跳必须短于锁、同意档位必须严格递增)。原条目里够不到的 B 类 Lua 内嵌值也接上了——`retry_or_dlq` 现在用 `ttl::RETRY_COUNTER_SECONDS` 插值生成脚本字符串,脚本里不再有第二个字面量。改值现在 = 改常量 + 断言失败,两处都得过评审。
|
||||||
|
|
@ -85,14 +89,27 @@ TTL 那条真机绿灯已经用你给的 Upstash URL 跑过了(见 §1),
|
||||||
|
|
||||||
> position walk 路径(`list_emails_page(None, position, BASELINE_PAGE_SIZE)`)本身不受影响——它的签名里根本没有服务端 state 参数(`None` 是 `folder_id`),所以不会碰到上面那类 token 语义。
|
> position walk 路径(`list_emails_page(None, position, BASELINE_PAGE_SIZE)`)本身不受影响——它的签名里根本没有服务端 state 参数(`None` 是 `folder_id`),所以不会碰到上面那类 token 语义。
|
||||||
|
|
||||||
|
### 3. 多账户(已决:不做,2026-09-28 用户决策)
|
||||||
|
|
||||||
|
单账户由需求固定(`REQ-SINGLE-ACCOUNT`),从未进入阶段目标。用户于 2026-09-28 明确「暂时不做多账户」,此缺口关闭。`docs/design.md` §11.3、`docs/charter.md` 的 `REQ-SINGLE-ACCOUNT` 行与 `docs/deployment.md` 的环境变量表 / 需求映射表原本就按此表述,本轮未改这三处。
|
||||||
|
|
||||||
|
**这条决定覆盖的范围**
|
||||||
|
|
||||||
|
- **不做多账户单实例**——一个 bot 实例同时服务多个 JMAP 账户。因此不需要 chat→account 路由、按域 / 按文件夹路由、`JmapService` 池化。
|
||||||
|
- **需要第二个邮箱时的既有路径**:部署第二个 bot 实例,各自独立 `BOT_TOKEN` / `ACCOUNT_ID` / `JMAP_SESSION_URL` 与 Redis 前缀。这是已文档化的既有能力,不需要新代码(`docs/deployment.md`)。
|
||||||
|
- **重新开启的触发条件**:出现「同一个 TG 会话要按来源邮箱分路由」这类单实例内的路由需求时,再拆 `REQ-SINGLE-ACCOUNT`。
|
||||||
|
|
||||||
|
**将来若真要做的最小改动面**(本轮核实过现状,供拆需求时直接用)
|
||||||
|
|
||||||
|
- `state:jmap:since` 是**单一全局游标**,无账户维度(读 `src/state.rs:777`、写 `src/state.rs:785`)——两个账户会互相覆盖游标,这是第一个要动的地方。
|
||||||
|
- `lock:reconcile` 是**单一全局单飞锁**(Redis 实现 `src/state.rs:1076`)——两个账户的对账会被同一把锁串行化。
|
||||||
|
- `dedup:jmap:{account_id}:{email_id}` **已经带账户段**(`docs/reference.md` §1),键形无需改。
|
||||||
|
- `ACCOUNT_ID` 环境变量已存在且经校验(留空取 session 主账户,越界值在 `src/domain/jmap/client.rs:485` 报错),业务配置层也能覆盖 `account_id`(`src/config.rs:465` 的 `unwrap_or_else` 回落)。配置面已就绪,缺的只是实例内的分维度状态。
|
||||||
|
|
||||||
|
这条不是被跳过,是被明确拒绝:单实例多账户省下的一个部署单元,换不来它引入的路由与游标复杂度。
|
||||||
|
|
||||||
## 本轮顺带发现并修掉的部署文档缺陷
|
## 本轮顺带发现并修掉的部署文档缺陷
|
||||||
|
|
||||||
`docs/deployment.md` §6.3.1 原来只给了 `/reconcile` 的调度示例,而 `/worker`——全代码库唯一的队列消费入口——被描述成「运维手工触发」,且刻意不在 Worker 白名单里。**照文档照抄部署 = 邮件持续进队列、通知永远发不出去**,这正是联调环境积压了数天才被手工排空的成因。§6.3.1 已补上 `/worker` 的调度步骤、顺序要求、批量上限与「204 不能当成功信号」的说明。
|
`docs/deployment.md` §6.3.1 原来只给了 `/reconcile` 的调度示例,而 `/worker`——全代码库唯一的队列消费入口——被描述成「运维手工触发」,且刻意不在 Worker 白名单里。**照文档照抄部署 = 邮件持续进队列、通知永远发不出去**,这正是联调环境积压了数天才被手工排空的成因。§6.3.1 已补上 `/worker` 的调度步骤、顺序要求、批量上限与「204 不能当成功信号」的说明。
|
||||||
|
|
||||||
同时修正了 `docs/reference.md` 与 `docs/retired.md` 里 `/worker` 的锚点:原值 `notify.rs:340` 落在 `reconcile` 函数体内,锚点审计不会报错(该行存在且非空),但语义是错的;正确值是 `notify.rs:390`。
|
同时修正了 `docs/reference.md` 与 `docs/retired.md` 里 `/worker` 的锚点:原值 `notify.rs:340` 落在 `reconcile` 函数体内,锚点审计不会报错(该行存在且非空),但语义是错的;正确值是 `notify.rs:390`。
|
||||||
|
|
||||||
## 后续(多账号)
|
|
||||||
|
|
||||||
单账号由产品决策固定,不在阶段目标内。当前 JMAP 登录与 `Email/query` 均为单一邮箱账号。
|
|
||||||
|
|
||||||
**需要你决定:** 是否需要多账号。要的话告诉我,我先把 `REQ-SINGLE-ACCOUNT` 的约束范围拆出来再动代码。
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
| `grammers` / 旧 `telegram-bot` crate | 未采用 | 直接封 Bot API + 自研即可满足需求 | `src/channel.rs` |
|
| `grammers` / 旧 `telegram-bot` crate | 未采用 | 直接封 Bot API + 自研即可满足需求 | `src/channel.rs` |
|
||||||
| `BotError::Telegram(#[from] teloxide::errors::RequestError)` | 目标形态变体,未落地 | 依附 teloxide,随其废弃 | 无 |
|
| `BotError::Telegram(#[from] teloxide::errors::RequestError)` | 目标形态变体,未落地 | 依附 teloxide,随其废弃 | 无 |
|
||||||
| `BotError::Jmap` / `Storage` / `RateLimited` / `Unauthorized` / `Llm` | 目标形态变体,未落地 | 当时为统一承接 JMAP/Redis/限流/授权/LLM 五类错误而设计;现已由各模块自行处理 | 当前 `BotError` 仅 `Config` / `Io` / `Json` / `State` 四变体(`src/error.rs` 全文) |
|
| `BotError::Jmap` / `Storage` / `RateLimited` / `Unauthorized` / `Llm` | 目标形态变体,未落地 | 当时为统一承接 JMAP/Redis/限流/授权/LLM 五类错误而设计;现已由各模块自行处理 | 当前 `BotError` 仅 `Config` / `Io` / `Json` / `State` 四变体(`src/error.rs` 全文) |
|
||||||
| Telegram 服务端 30 msg/s 限流桶 + 429 专用分支 | 目标设计,未实现 | 无真实 Bot 压测数据,不预设实现 | `src/channel.rs` 的 `max_retries`(默认 3,硬上限 5)通用重试;缺口见 `docs/opengaps.md` |
|
| Telegram 服务端 30 msg/s 限流桶 | 目标设计,未实现 | 无真实 Bot 压测数据,不预设实现;服务端分桶由 TG API 自身承担,bot 侧只做退避 | 429 专用分支**已实现**(`src/channel.rs`:解析响应体 `parameters.retry_after` 并钳 ≤60s,优先用服务器指定值否则指数退避),因此本行不构成缺口;服务端限流桶的当前处置仍是 `max_retries`(默认 3,硬上限 5)通用重试 |
|
||||||
| 多步对话 FSM(`Idle` / `AwaitClarify` / `AwaitConfirm` / `Analyzing` / `AwaitFallback`) | 目标设计,未落地 | 当前 AI 授权只需一个布尔+过期时间,多步态属过度设计 | Redis TTL 授权态,键与 TTL 见 `docs/reference.md` 的 AI 授权态一节 |
|
| 多步对话 FSM(`Idle` / `AwaitClarify` / `AwaitConfirm` / `Analyzing` / `AwaitFallback`) | 目标设计,未落地 | 当前 AI 授权只需一个布尔+过期时间,多步态属过度设计 | Redis TTL 授权态,键与 TTL 见 `docs/reference.md` 的 AI 授权态一节 |
|
||||||
| 把领域 / 渠道 / 通知 / util 各层拆成独立目录(子模块拆分方案) | 目标形态目录,未落地 | 代码量未到需要拆分的规模 | 实际结构见 `docs/design.md` 的工程结构一节:领域层是 `src/domain.rs` + `src/domain/jmap/`(仅 `client.rs`);LLM 在 `src/ai.rs`;通知在 `src/notify.rs`;加密与工具逻辑内联在 `src/state.rs` / `src/config.rs`,没有独立的 util 层,也没有集成测试目录 |
|
| 把领域 / 渠道 / 通知 / util 各层拆成独立目录(子模块拆分方案) | 目标形态目录,未落地 | 代码量未到需要拆分的规模 | 实际结构见 `docs/design.md` 的工程结构一节:领域层是 `src/domain.rs` + `src/domain/jmap/`(仅 `client.rs`);LLM 在 `src/ai.rs`;通知在 `src/notify.rs`;加密与工具逻辑内联在 `src/state.rs` / `src/config.rs`,没有独立的 util 层,也没有集成测试目录 |
|
||||||
| teloxide 风格的出站消息派发集成测试 | 目标形态测试,未落地 | 依附 teloxide 测试模式 | `src/channel.rs` 的单元测试(`#[test]`) |
|
| teloxide 风格的出站消息派发集成测试 | 目标形态测试,未落地 | 依附 teloxide 测试模式 | `src/channel.rs` 的单元测试(`#[test]`) |
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue