feat(server): 同步引擎与 seed(阶段 4)

- 引擎:tick(5 分钟 + 防重入 + 启动即跑)· 单轮串行遍历 active key · 日志整批单事务入库(ON CONFLICT DO NOTHING + log_synced_at 取请求发起时刻)· 额度采集(上游字段全组,独立 try)· QPU 采样(基线 / 值变化才追加)· 每轮摘要与超期 warning
- 401 状态机:N=3 摘除(disabled_source=auto_401);403/500/网络不计数;解密失败跳过不计数
- 纯逻辑抽层:policy(计数 / 合并判定)· dedupe(去重键与内容指纹)· log-row(日志映射,与 seed 共用)
- seed 脚本(幂等):假 key + 984 条日志 + QPU 基线 + 示例购买
- 实测:401 端到端 1→2→3 摘除且摘除后不再轮询;幂等重跑新增 0 条
- 实证发现:错误行 request_id 不唯一(8 组 ×3)——记入实施计划「待定问题 #5」与 upstream 文档,待作者裁决
- AGENTS.md / 根 package.json 增 seed 命令
This commit is contained in:
2026-09-15 00:46:46 +08:00
parent 4b5d21a418
commit e1c6d2153e
14 changed files with 623 additions and 37 deletions
+79
View File
@@ -0,0 +1,79 @@
/**
* 401 状态机与轮次结果合并的单测(同步引擎设计 §3.4 + 实施计划「实现假设」#15)。
*/
import { describe, expect, test } from 'bun:test'
import {
combineRoundResult,
MAX_CONSECUTIVE_401S,
nextKeyCounter,
type KeyCounterNext,
} from './policy'
const active = (consecutive401s = 0): KeyCounterNext => ({
consecutive401s,
status: 'active',
disabledSource: null,
removed: false,
})
describe('combineRoundResult(两个调用合并为「本轮结果」)', () => {
test('任一 401 → unauthorized(401 优先于成功)', () => {
expect(combineRoundResult(['ok', 'unauthorized'])).toBe('unauthorized')
expect(combineRoundResult(['unauthorized', 'failed'])).toBe('unauthorized')
})
test('无 401 且任一成功 → ok', () => {
expect(combineRoundResult(['ok', 'failed'])).toBe('ok')
expect(combineRoundResult(['ok', 'ok'])).toBe('ok')
})
test('全失败 → failed(不动计数)', () => {
expect(combineRoundResult(['failed', 'failed'])).toBe('failed')
})
})
describe('nextKeyCounter(401 计数 / 摘除 / 清零)', () => {
test('成功 → 计数清零(不摘除)', () => {
const next = nextKeyCounter(active(2), 'ok')
expect(next.consecutive401s).toBe(0)
expect(next.status).toBe('active')
expect(next.removed).toBe(false)
})
test('其他失败(403/500/网络)→ 计数不动', () => {
const next = nextKeyCounter(active(1), 'failed')
expect(next.consecutive401s).toBe(1)
expect(next.removed).toBe(false)
})
test('连续 401 累加;未达阈值不摘除', () => {
let state = active(0)
for (let i = 1; i < MAX_CONSECUTIVE_401S; i++) {
const next = nextKeyCounter(state, 'unauthorized')
expect(next.consecutive401s).toBe(i)
expect(next.removed).toBe(false)
expect(next.status).toBe('active')
state = next
}
})
test('第 N 次(N=3)连续 401 → 摘除且 disabled_source = auto_401', () => {
let state: KeyCounterNext = active(0)
for (let i = 1; i <= MAX_CONSECUTIVE_401S; i++) {
state = nextKeyCounter(state, 'unauthorized')
}
expect(state.consecutive401s).toBe(MAX_CONSECUTIVE_401S)
expect(state.status).toBe('disabled')
expect(state.disabledSource).toBe('auto_401')
expect(state.removed).toBe(true)
})
test('中途成功会打断连续性(计数回零)', () => {
let state: KeyCounterNext = active(2)
state = nextKeyCounter(state, 'ok')
state = nextKeyCounter(state, 'unauthorized')
expect(state.consecutive401s).toBe(1)
expect(state.removed).toBe(false)
})
})