chick
|
274e25961a
|
fix(agent): 手机已经放弃的请求不再执行
中继答 504 并说"可能已经执行了,重试前请先确认"——这句话诚实的前提是它保持为真。
批次是串行处理的,所以满邮箱里第八个信封可以在它被签名之后 8 个上游超时才轮到;
那时手机早已被告知失败、用户可能已经重试。再执行它,就把一次诚实的"未知"变成了
一条重复发出的短信。
现在 agent 在动任何东西之前先比对自己的截止时间(策略里的 requestTtlSeconds),
超龄一律以 expired 拒绝并落审计。判定放在新鲜度检查之后、策略判定之前:它比签名
更便宜,而且一个过期请求无论路径是否在白名单里都不该执行。
为了让这条规则**可达**,策略新增一条断言:TTL 不得大于时钟偏移窗口。否则新鲜度
检查会先触发,这条规则永远不会被执行——而"永不触发的规则"是出事时才会被发现坏了
的那种东西。
单个上游调用的超时也移进了策略(agentUpstreamTimeoutSeconds)。"中继期限必须长于
一次上游调用"这个比较,与二进制里的常量是比不了的;现在两侧从同一个文件读,策略
加载时就能拒绝一组自相矛盾的数值。原来那个 20s 常量保留为默认值的来源,不再硬编码。
测试两项:一个请求在期限内被转发、一个超龄请求被拒且**没有被转发**(计数按路径,
否则首次转发前的 /api/auth/status 探测会让断言以错误的理由通过);另一项断言策略
本身满足上述两个关系。变异验证:关掉判定,第一项失败。
Go 全包、Node 119 项、Swift 101 项通过。
|
2026-09-17 07:12:44 +08:00 |
|
chick
|
9608a7ebc0
|
fix(agent): 审计写入失败不再静默
审计日志是证据而不是控制手段:写失败不能让请求失败,否则磁盘写满会变成一次远程
拒绝服务——已经执行成功的指令会因为日志追加不上而开始报错,那是坏错了地方。
但它也不能消失。静默丢审计条目是那种"运维以为自己有记录、其实没有"的失败,而这份
日志的全部意义就是事后能回答"谁在什么时候要求了什么"。现在写失败会进 agent 自己的
日志,磁盘写满表现为一行反复出现,而不是一片空白。
顺带把 Close 之后的语义写清楚:Close 会丢掉 sink,此后的写入返回 nil——这是刻意的,
因为一个正在关闭的进程与在途请求赛跑时,为每一个恰好到达的请求报一次失败是噪声
而不是信息。这条差别在 agent 日志里看得见。
测试用真实失败路径(写一个已关闭的文件)而不是填满文件系统,并断言 exec.record 把
它报了出来。
Go 全包、Node 112 项、Swift 101 项通过。
|
2026-09-17 01:52:59 +08:00 |
|
chick
|
3a9eec5de2
|
fix(agent): 危险写限流改为滑动窗口,与中继侧同一算法
节点侧的限流器此前也是固定窗口(按自然分钟重置计数器),而注释声称的性质是
"任意 60 秒内至多 N 次危险写"——与中继侧那个缺陷完全相同,只是这一侧还没有
人测过它。注释同样以该性质为由选择了固定窗口,所以代码与自己的理由相反。
现在两端是同一个算法:保留被放行的写时间戳,窗口满时最早那笔离开窗口才放行。
这两个限流器从两侧约束同一个操作(节点自己、以及中继对设备的预算),一侧比
另一侧宽一倍是那种要等到事后复盘才会被发现的不一致,所以保持一致比任何一侧
单独正确更重要。
测试里有一处值得记下来:这个性质不能按"花完预算、过一分钟、再花一次"来测——
那样固定窗口也会通过,因为所有写都过期之后两种实现没有分歧。必须把预算花在
自然分钟边界**之前**,再断言边界之后一笔都放不进去。第一版就是这么写错的,
变异验证(把实现改回按自然分钟重置)没有失败,才发现测试本身没在测它。
内存代价同中继侧:每节点至多 N 个时间戳,而不是一个整数。
Go 全包、Node 112 项、Swift 101 项通过。
|
2026-09-17 01:46:32 +08:00 |
|
chick
|
443af20e0a
|
feat: agent 本机 SimAdmin 登录与会话维持;中继设备侧限流与 agent Retry-After
- runtime.NodeAuth:agent 自查 /api/auth/status,需要时自行 POST /api/auth/login 并持
simadmin_session Cookie 转发;错误密码进入 60s 冷却(对齐控制台 ensureAuthenticated),
节点回 401/403 即失效重探,SimAdmin 重启无需重启 agent
- 节点密码进 agent 配置(nodePassword),永不经中继、永不下发到手机;登录路径仍被策略
挡在电话可达面之外(TestAuthPathsAreUnreachable)
- 新拒绝分类 node_auth_failed:与 upstream_error 区分,手机可提示'该节点需重新配置'
- 中继:/v1/request 每设备固定窗口限流(默认 30/分钟),未鉴权调用不消耗预算
- transport:解析 Retry-After 并入退避;main loop 对 429 直接遵从中继指示
- contracts/envelope.schema.json 补 InnerResponse.outcome 字段
- 设计文档与 README 同步:WSS 改为长轮询的实现修订、响应方向已临时×临时、P2/P3 状态
|
2026-09-16 09:15:25 +08:00 |
|
chick
|
54d9696a4d
|
baseline: P1 契约、agent 核心与中继投递(既有工作首次入库)
|
2026-09-16 08:41:13 +08:00 |
|