721371d806
根因:付费连接凭证硬编码 24h TTL(paidCredentialTTL),而客户端只在 _connect() (用户/看门狗前台重连)才重签,服务端从不因流量续期。macOS sysext(root)隧道独立于 GUI app 常驻,用户关窗后 Dart 看门狗根本不运行 → 凭证 24h 到期、下次 agent 重注册 用「未过期」快照整表覆盖并重渲染 sing-box → REALITY 会话被剔除、永久黑洞。该逻辑 四端共用同一份 Dart,故为全端共性(macOS 最易现形)。 修法(方案 A,服务端、与客户端生命周期无关,一改修四端): - ReportUsage 收到某 dp_uuid 有流量,若属付费套餐(!AdGate)即把其凭证 expires_at 顶到 now+PaidCredentialTTL。活跃会话永不过期;免费凭证 TTL 编码日额度、绝不续期 (否则击穿日限)。每报按 user 缓存一次 entitlement 查询。 - 新增 NodeStore.RenewCredential(纯 UPDATE,WHERE expires_at>now 不复活已过期会话)。 - 24h 提为 nodes.PaidCredentialTTL 单一真相源,httpapi 引用它消除漂移。 - 纯 DB 续期,无需再 push agent(现有 REALITY 用户仍在,只要 DB 行不过期,下次 重注册快照仍含它)。可移植 SQL(? 占位 + Go 端算时间,无 MySQL 专属构造)。 测试:handler 层付费续期/免费不续期(mock);store 层真 SQLite 续期/不复活已过期。 go test ./... 全绿、go vet 干净。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD