Skip to content

Latest commit

 

History

History
108 lines (58 loc) · 18.6 KB

File metadata and controls

108 lines (58 loc) · 18.6 KB

质量归因:受控对照实验

这项产品服务于多账号、多出口的 Build 服务运营者。用户要知道的是异常跟随账号还是出口,以及现在应当保留哪个资源、暂停哪个资源。完成多少任务、积累多少错误、显示多高分数,都不等于回答了这个问题。

一次事件只触发暂时保护。正式归因必须来自隔离变量的比较:固定涉案出口换账号,固定案件账号换出口;发现异常后再增加一条匹配对照,检验比较资源本身是否可用。结论是“更可能”,不是已经证明根因,更不是已校准的概率。

内部职责与依赖

journal.AccountAllowed 以原生 SQL 联查 registry 拥有的 q_account_state/q_case_party 表(最终准入判定);这两张表的列名与状态值是 journal/registry 的显式共同合同,变更须两侧同步。

model 定义案件、当事方、任务、持久事件和证据快照,并提供确定性的聚合与互证规则,不依赖数据库或业务服务。court 通过 StateStoreProbeReader 编排立案、有限实验和结案;investigator 通过任务与测量端口执行;events 通过 journal 端口消费已持久接受的事实;enforcement 通过状态、节点与轮换端口执行出口处置。management 通过配置应用接口和只读查询接口提供管理用例。

registry 实现案件/身份/限制的原子存取与资格投影,journal 实现持久事实和可恢复 outbox,evidence 实现观测存储及滑窗发布。这三个包不被业务流程直接导入。组合根创建存储、注入端口并关闭资源;court 不创建任务存储,management 不持有可执行 SQL 的 Store。接口返回 model 中的值,不返回 GORM 或实现包 DTO。

拆分保持原有表、JSON 字段、事件身份、协调租约和条件更新。证据策略配置与 logger 分别注入;热改窗口仍先重载成功再发布。类型位置改变不代表可以改变案件协议或解除旧限制。

court 与 enforcement 的构造函数不启动任务;组合根调用非阻塞 Run,随后由 Close(ctx) 取消并等待循环退出。Close 在未启动时关闭启动入口,重复调用仍等待同一个完成信号;一次关闭超时不代表任务已退出,也不能让下一次关闭绕过等待后提前关闭数据库。court 的周期评估在首个间隔后执行,enforcement 启动后立即观察一次出口。

当前实验协议

协议版本:controlled-comparison-v2。每个案件创建时保存规则、最低样本数、尝试上限和绝对截止时间,后续调整设置只影响新案件。历史未结案案件首次评估时补录当前协议,原始测试没有新证据字段时不能凭空补出有效控制。

默认初始计划为 3 条账号比较和 4 条出口比较,每条异常比较最多补充一次匹配控制请求。每案最多 6 条账号比较、8 条出口比较,因此真实推理请求至多 28 次;正常结果不追加匹配请求,常见路径低于此上限。IP 探活请求另计。默认 10 分钟截止,后台评估间隔 15 秒。

比较 主测 异常后的匹配控制 回答的问题
固定出口换账号 独立正常候选账号 → 涉案出口 同一候选账号 → 独立比较出口 是否仅在涉案出口异常?
固定账号换出口 案件账号 → 比较出口 正常候选账号 → 同一个比较出口 比较路径正常时,是否只有案件账号异常?

两个方向使用同一个 Build 探测入口和冻结的 thinking-presence-v2 实验样本,继续由生产守卫分类。探针使用固定的简短问候请求,不评估答案正确性。原请求的工具、推理档位和客户端协议只保留为触发来源,不限制立案取证;主测与控制统一使用无工具、low 推理档位的 Responses 请求,并匹配原模型、策略 revision、规则版本及同一个样本。缺失物理身份、规格不支持或策略变化的结果不可采。v2 收到有效思考增量即可记为 clean 并关闭、回收上游流,不等待正文或 response.completed;仅有空白增量、usage 中的推理 token 声明或密文不算思考证据。输出上限为 128 token,超时或证据不足仍为不可采,不据此推断降智。测量正常不代表完整生成,物理调用仍按实际观测记账。账号资格、凭据、配置与业务面的失败不等同于响应异常。匹配控制的账号与出口随计划持久化,主测和匹配结果分别存储。探测针对同一账号身份串行,防止调查并发制造假象。

结果独立保留为:正常、降智、响应异常、无法测试、等待结果、取消。传输错误不会变成降智票;FailureKind 在故障发生位置记录来源、阶段和原因,不从自由文本反推。内部资源、持久化、取消、完成预算、未知错误和缺少来源的历史错误不能形成可用性定罪;明确的上游 5xx、准入首事件/零证据截止和空流等仍需独立对照。已观察的路径指纹、IP 变化验证和匹配控制共同决定是否支持账号可用性嫌疑。路径指纹来自已解析的出口地址,多个节点使用同一地址集合只计一次;去重不能隐藏后来的正常反证。它表示可观察的出口身份,不证明不同运营商或完全独立的基础设施。

决策规则

  • 更可能是账号质量问题:涉案出口上至少 4 个独立账号正常,没有该方向的降智反证;案件账号在至少 3 个独立比较路径持续降智,覆盖至少 2 个节点;这些路径上的匹配正常账号通过,且案件账号没有有效的正常反证。
  • 更可能是账号可用性问题:涉案出口上的正常控制成立;案件账号在至少 3 个已验证独立路径反复发生响应异常(也可以是响应异常与降智混合),同路径匹配正常账号通过。单独展示为“账号可用性异常”,不声称这些错误证明内容降智。暂停账号调度,保留人工复核入口。
  • 更可能是出口/IP问题:至少 4 个独立账号参与有效比较,至少 3 个在涉案出口降智、在独立出口恢复;案件账号也在不同出口恢复;账号比较方向没有降智或已确认持续传输异常反证。
  • 无法区分:样本不足、匹配控制失败、路径未核实、双方均异常或未形成稳定模式。补充尚未测试的资源,直到满足规则、候选/预算耗尽或截止时间到达。随后释放本案施加的临时冻结并结案。

对于“涉案出口其他账号都正常,案件账号跨出口反复失败”这类关键场景,报告始终记录账号重复异常。若同路径匹配正常账号通过,则形成账号可用性归因;若无法完成独立性/匹配控制验证,报告写明“已发现重复异常,尚缺独立对照确认”,列出限制,按期限释放。不会把它简化成从未观察到异常,也不会仅凭失败次数永久限制资源。

不存在跨业务面兜底判决,也没有用其他方向的大量票数抵消有效反证的分数计算。

独立释放

两个方向各自满足完整的正常对照门槛后,可以先解除被排除一方的本案冻结,不必等待另一组测试完成:涉案出口上的独立账号全部正常时释放出口;案件账号在足够的已验证独立路径和节点全部正常时释放账号。等待、失败、缺少路径验证、重复资源或正常/异常冲突都不能被当作完整正常对照。

这项排除只影响本案的临时限制,不能提前定罪。另一方继续原有补测和归因,并保留原截止时间。释放在下一次后台评估时执行,默认评估间隔 15 秒;不承诺在最后一个测试完成的同一瞬间执行。

registry/clearance.go 在一个事务中更新当事方处置和释放证据,再发布资格快照。early_releases 保存时间、原因和协议版本。其他案件的冻结或判决仍然有效。计划器不会重新冻结已经释放的当事方,同一事件也不会因提前释放再开一个案件。事务失败回滚、重放、重启、其他案件持有限制、另一组仍等待和最终结案均有回归覆盖。

释放不只在调度轴上生效:本次动作确实把账号从羁押变为可用时,组合根注入的通知让账号轴立即清掉它携带的质量标记与随之而来的瞬态冷却(quality_idle_timeoutmissing_thinking),被证明无罪的账号不必再等这段冷却自然到期。仍被另一个案件羁押的账号不被通知,因此一个案件不能替另一个案件解禁;当前限制若是纯传输事实(如上游 429),也不在解除范围内——那属于账号轴,出口裁决不得抹掉它。通知失败只记日志,不改写已提交的裁决,也不回滚释放。

持久化、恢复与处置

court/protocol.go 是无数据库和网络副作用的确定性规则函数。court/workflow.go 编排读取、补测和结束。court/planner.go 选择有界的未测试资源。registry/experiment.go 提供两个事务:

  1. 建立案件、登记双方、写双方调度冻结,然后一次发布内存资格快照。
  2. 结案、保存解释、更新双方处置与调度状态、取消未完成任务,然后一次发布快照。

结案条件更新只接受 investigating,重放不会改写既有结论。结案后迟到的探测写回被拒绝。测试结果先独立持久化为案件证据,再写滚动聚合窗口;聚合统计故障不会抹掉已取得的测试结果。单个案件评估出错会被报告,其他案件继续评估。

8 个工作槽独立认领 pending;running 保存进程 owner 与 3 分钟租约,每 30 秒续租,结果写回检查未过期 owner。重启仅回收过期或旧版无 owner 的工作;活跃副本不被取消,工作中断不被计算为账号异常。done 与观测投影意图原子提交,独立恢复循环按稳定事件 ID 去重补写。截止时间从案件创建时计算,重启和设置变化都不能重置它。数据库不可写时不能承诺成功结案,系统保留保护、报告失败;数据库恢复后的评估继续收口。

IP epoch 改变后旧出口方退出,不把旧结论施加到新 IP。固定与 webhook 出口按当前 epoch 禁用;池出口沿用当前 epoch 保护,变化后释放。出口身份是双地址族的:任一非空族变化即翻 epoch(与 egress 轮换验证同一把尺子,WARP/MicroWARP 类隧道重启后 IPv4 稳定而 IPv6 轮换是常态);旧档案缺失的一族首次观测到时只采纳补写基线(current_ipv6 列,AutoMigrate 加列,旧行默认空串),不翻 epoch——升级本身不得释放仍有效的限制。轮换成功记账后由组合根立即驱动执行所的单节点观测(ObserveNodeExit),解禁不再等下一个检测节拍;周期轮询仍是兜底。账号归因只限制案件账号,不把其他健康对照账号连带限制。

人工可以填写复核原因并解除本案限制。节点人工解禁则在一个事务中解除该节点当前 epoch 的全部案件限制,保留各案件原始裁决与解除原因,不释放账号;已解除的出口方不会被同案后续裁决重新限制,新事件仍可正常开案。原始结论和证据完整嵌入复核记录;其他仍有效的案件继续持有自己的限制。首次升级不清空案件、证据或状态。普通已释放案件与完整测试统一保留 30 天;限制类判决保留到人工解除后再进入保留周期。独立孤儿终态测试保留 14 天。

多实例部署使用 PostgreSQL 与 Redis。主请求和探针共享账号并发与响应缓冲预算;探针额外共享最多 2 个测量槽、每个账号或身份组 1 个槽。测量最长 90 秒,全部探针容量租约为 2 分钟,失联后无需等待生产长请求 TTL;短探针租约不会缩短同键生产租约。

轮换执行入口使用共享节点租约和 Redis 滚动一小时额度。每次尝试在调用 webhook 前持久化次数与开始时间;失败、超时及进程退出都保留该次消耗。自动巡检不重置次数,只有人工触发可在取得同一节点租约后重开周期。单次执行最多 4 分钟,所有权租约为 4 分 30 秒;依赖不可用或尝试预留写入失败时不发出 webhook。轮换 worker 支持禁用后热启用,执行所关闭会取消正在读取的节点与巡检工作。

court 使用有 owner 的跨实例协调租约,事务内再次验证所有者。过期案件先于流量聚合、新开案与维护工作处理,每案最多 1 秒;未到期案件最多 5 秒,供较大候选池查询与补测计划使用。两者都只占总轮次剩余预算的一部分;处理游标持久化,慢案件不会反复占据队首。同一补测轮次的两个方向及匹配控制复用一次账号候选查询和一次节点查询;执行时仍检查当前资格与身份。仍有大量积压时需要多个轮次,数据库整体不可写时无法保证释放成功。

当前代际单独存储于 q_node_epoch,与追加档案事务更新。状态快照按 revision 重载,未变化时跳过;探针入队只锁定并读取关联案件,不重建全局状态。最终账号/出口准入直接查库。PostgreSQL 首次建表及升级在 advisory lock 保护的事务中串行,支持并发启动。代际指针和完成标记在同一事务初始化,失败可重试;升级前应排空旧工作进程,不能混跑仍只写历史代际的旧版本。

出口探测在发起网络测量前,由数据库递增节点的 probe_sequence;结果携带该版本写回,只有最新已发起且尚未提交的版本可以写入 probe_revision。执行所消费这个版本,登记处将 observation_revision 与 IP 代际、旧限制释放和旧当事方撤下放在同一事务。重复或迟到版本无权推进代际;同 IP 的新观测也推进版本水位。顺序不依赖各实例本地时钟。观测身份按地址族比较:探活的 ipv4_exit_ip/ipv6_exit_ip 分别构成身份两侧,聚合 exit_ip(IPv4 优先)仅用于展示与台账。升级前保存的无版本 IP 仅作历史信息,需新探测后才可作为自动解除依据;旧工作进程必须排空,因为旧写入方不会遵守版本校验。

案件去重使用 q_incident_closure 保存每个 (account_id, node_id, epoch) 的最新结案时间,随结案事务更新。首次升级从历史回填,回填与初始化标记一起提交;失败可重试,后续启动不重复扫描历史。单事件按键查询,周期发现仅批量读取待处理事件;该投影不进入全局状态快照,并保留到显式质量状态重置,以防迟到事件在原始案件清理后重新立案。出口与账号持有方查询有对应复合索引,健康准入不再扫描全部案件历史。

主请求完成事实与恢复、门控/交付和资源预算的详细契约见 实时响应守卫

管理界面

质量防护默认进入归因案件。案件详情展示:实际账号和出口名称/邮箱/IP 档案、当前处置、固定的截止时间、两组主测与匹配控制关系、支持账号的证据、支持出口的证据、反证、结束原因、人工复核操作。案件详情跟随当前查询结果更新,完整测试按 case_id 加载,不受全局最近测试窗口截断。

旧案件单独标记“历史规则”,保留原始测量和结论,不把旧分数当作新协议确认过的判断。账号名称按案件和探针实际引用的 ID 批量读取,每批最多 500 个;不扫描整个账号池或加载凭据、额度和审计。受限账号数量使用账号管理查询的分页前质量筛选,只统计仍存在的账号。名称与受限数量共享账号缓存失效范围,删除、人工复核后刷新,重新进入页面强制读取并每 10 秒轮询。没有可用名称的已删除资源仍显示保留 ID;历史记录不补造名称,名称不可用时明确提示。

任务完成不代表响应正常。探针主测展示实际被测账号与出口,匹配对照单独显示结果;路径核实不代表对照正常,也不代表已确认出口有罪。首事件超时指收到响应头后等待首个 SSE data 事件超时,与拨号建连不同。异常样本缺少正常匹配对照、身份或路径验证失效时,仍需在已固定的案件预算内补测;最终归因以案件保存的协议和评估为准。

主测因本地容量、身份、规格、持久化或未知来源失败而不可采时,不再发送无法修复该证据缺口的匹配控制请求;保留原始失败并交由现有有限补测计划收口。明确降智及可用于独立可用性比较的上游错误仍执行匹配控制。规格校验在测量之前进行,旧案件不重开、不改判,任务和物理尝试上限不增加。短暂事件落库故障只重试同一份事实,不重跑实验或增加证据票。

验证与后续迭代

新增规则回归覆盖账号降智、重复响应失败、出口异常、两边正常、两边降智、单次异常、共享 IP、未核实路径、匹配控制失败、凭据不可用、正常反证、缺少出口校准、陪审不足、重复账号、等待与取消、别名路径反证。

事务故障注入验证开案/结案回滚、双方资格一致、重放与迟到结果;生命周期验证设置变化不延长期限、一个失败案件不阻塞另一案件结束、共享资源释放与 IP epoch 退出。修改规则时先用人工构造的最小案件样本固定要改变的行为,再修改纯判断函数;协议版本与案件规则保留,历史不能静默改判。

下一步运行数据应围绕人工复核结论、被推翻的假设、匹配控制不可用比例、独立路径不足和实际结案时延迭代。只有经过真实样本验证和校准,才考虑引入概率模型;不应再通过任意增加权重来修复单个案件。

本地验证

backend/ 运行 go test ./...,并对质量包、应用接线和管理接口执行 go test -race。在 frontend/ 运行 pnpm testpnpm exec tsc -bpnpm lint

部署实例、真实案件、请求样本与本地环境记录不随源码提交。测试语料使用构造数据或最小化后的解析失败输入。

实验规格随案件与任务持久化。已保存的 reasoning-capability-v1 保留原请求轮廓匹配、固定题目和成功完成要求,已结案件不自动重开;新立案件使用 v2。升级应先排空旧工作进程,旧程序不认识 v2,不能与新调查员混跑。回退不能把 v2 任务重标为 v1;应先完成或按既有取消流程结束 v2 调查,保留其证据和结论。实验不可支持与调查对象缺失有独立结案原因,不记作证据已齐。