任务:重复策略(V07):动态层按声明的次数和聚合方式汇总,混合的结果记确定的“间歇”

依据:

  • 决定 35 第 13、16 项(docs/hub-r4-progress.md):V07(重复策略)要做。
  • 模型:V07 DEF、R[0]–R[5];W02 F[6];V03 F[1]、R[4]、R[5];P07 R[1]、R[3];V04 R[0]、F[5];V05 R[7](首因不丢);B06 F[0](意图键带次序);W03 F[0](次数与时长预算);展示规则 16(displayRules[16]:重复执行的结论显示观测分布)。用 node tools/show-element.ts V07 W02 V03 P07 V04 V05 B06 W03 读。
  • 所有者的规矩:未知只是过渡状态。V07 R[0] 现在写“聚合方式为‘全部’时,结果混合记未知(间歇)”。各轮都过了完整性规则时,混合是看到了的事实:哪几轮通过、哪几轮失败都清楚,不缺事实,也没有哪一步能把它变成别的结论,所以不该记未知。R[1] 对 k-of-n 按阈值给判定,k 等于次数时就是“全部”,R[0] 的未知和它也对不上。
  • 对照模型的复核第 2 节第 3 条:V07 没进引擎。上真实台架的设计第 5 节写“一个 S 只派发一次”;同一批写的 gateway-request-ids.md 第 10 条把 dispatch.bytes:<S> 改成按尝试记,第 13 条加逐台只读探测,第 16 条在结果归属认证以后给逐用例的通过和失败。这一件在它们之上按轮做。

  • 集成者先做(模型文字归集成者),开分支前提交:
    • V07 R[0] 改成:每一轮先看它合不合期望的结局;聚合方式为“全部”时,各轮都合期望才合期望;有一轮不合就是不合;既有合又有不合的,标“间歇”,附观测分布。间歇的原因(被测对象、环境、执行上下文)只作假设,不进归责(V04 R[0])。
    • 限定标记加 intermittent(间歇),归 V07,这一件用它。
    • V07 R[5] 的默认次数:所有者 10-21 定了,决定表第 19 行按推荐(node tools/show-element.ts --pending):验证与复现默认 3 次,Web 默认首轮通过、失败再重跑。所以:
      • 加一个“工作类”轴,归 V07,取值:验证、复现、Web;
      • 默认的重复策略:验证和复现是 3 次、聚合方式“全部”;Web 是首次通过、2 次(首轮通过就停,失败再跑一次);
      • 工作流包声明自己的工作类,没写重复策略的要求项按工作类取默认;包没声明工作类的才是一轮;
      • case-compile 的派发那一行照旧写它自己的次数,写了的以写的为准。
    • 上真实台架的设计第 5 节那一句:次数只来自冻结的重复策略和效果表的次数预算。
  • 分支和工作树:v07-repetition,目录 circle-hub-v07-repetition。从 hub-redesign 开出;等 hub-unknown-exits(第 10 条把派发结局接进动态层)、dispatch-gateway(gateway-request-ids 第二步)、d03-p11-boundary(写声明和预算)和 w10-criterion-change(同改 contracts/src/pack.ts、run.ts、validation.ts、evaluate.ts、text.ts)合并以后,由集成者开出并通知。
  • 可以改的路径(行号照现在的写,合并以后以函数为准):
    • contracts/src/pack.ts(RequirementTemplate 的 repetition,工作流的工作类)、contracts/src/run.ts(RequirementSummary 带出它)、contracts/src/validation.ts(动态层结果的轮次和观测分布),照生成器重新生成 contracts/generated/**;
    • hub/runs/packs/validate.ts;
    • hub/runs/packs/ports.ts:只改 packSummary;hub/runs/engine/start.ts:只改 requirementSummary。两处都带出生效的重复策略(第 1 条);
    • hub/runs/engine/repetition.ts(新,纯函数)、terminals.ts 的 dynamicLayer、evaluate.ts 里动态层取派发结局的那一段、README.md;
    • hub/dispatch/**(按轮派发);
    • hub/server/cli-job.ts:只改 output() 和状态那一行(逐轮列出);
    • hub/server/text.ts、console/pages.ts(显示观测分布);
    • tests/acceptance/oracle/** 的动态层规则;
    • 对应的测试。
  • 规则:同前(不推送、不建 PR、不发布、不部署;不碰 7420、钥匙串、环境配置文件和任何真实系统;测试只用合成数据,版本线 10.6 以后,地址只用 192.0.2.0/24 和 2001:db8::/32;git commit -s)。所有者的规矩:
    • 未知只是过渡状态,写明缺的事实和下一步动作;
    • 枚举只来自生成的词表:聚合方式用 aggregation 轴,终态用 dynamic_terminal 轴;
    • Hub 只核验,不生成内容,不调用模型:每一轮派发的都是核验过的同一份字节;
    • 核心里没有产品的字。
  • 验证:npx tsc --noEmit;node tools/gen-contracts.ts --check;node --test --test-concurrency=1 对 contracts/**、hub/runs/**、hub/dispatch/**、hub/server/**、tests/acceptance/oracle/**。每条先写改前失败、改后通过的测试。

要做的

  1. 重复策略的形状(V07 DEF、W02 F[6]):
    • RequirementTemplate 加可选的 repetition:次数(1 到 10,上限写进 README);聚合方式;k(只在 k-of-n 时写,1 ≤ k ≤ 次数);是否换新上下文;是否先证基线;时间窗(秒,可选)。
    • 只许写在声明了动态层的要求项上:静态检查不重复(架构第 1 节)。
    • 没写的,按工作流声明的工作类取默认(集成者先做的那一条);工作流也没声明工作类的,就是一轮:次数 1、聚合方式“全部”,结论照样写“1/1”。
    • RequirementSummary 带出生效的那一份(写的,或者默认的,标明是哪种),模型和客户端看得到。摘要有两处在拼:start.ts 的 requirementSummary 和 ports.ts 的 packSummary,两处都要带。
    • 测试:发布校验和合约逐条正反例;三种工作类的默认值各一;写了的盖过默认值;两处摘要给出的相同;现有的包不改照样读。
  2. 按轮派发(B06 F[0]):
    • 一个条目的每一轮是一条单独的效果,意图键的次序就是轮次。dispatch-gateway 已把 dispatch.bytes:<S> 改成按尝试记,这一件再按轮分:同一(S,轮次)至多派发成功一次,尝试照它的规则。轮次不超过冻结的次数,也不超过效果表那一行的次数预算,超了被效果前边界拒绝(d03-p11)。
    • 首次通过:有一轮通过就停,后面的轮不派发。
    • 换新上下文:每轮取新的网关租约和会话,不沿用上一轮的。
    • 先证基线(P07 R[1]):每轮之前,在同一个网关租约里做环境核对和逐台只读探测(dispatch-gateway 第 13 条)。不过的,这一轮记未运行,理由码 integrity_unproven,出口是重跑这一轮;不算失败。
    • 时间窗:从第一轮开始计。窗外才开始的轮不派发,但留在分母里,记未运行,理由码 budget_exhausted(时长预算用完),出口是开新修订重跑(W06 R[0])。这样 k 等于次数的 k-of-n 在窗外有轮时判不了通过,写明缺哪几轮。
    • 谁跑第 2 到 n 轮:
      • 一次 circle-hub job dispatch 就是一个作业,在同一条命令里按次序跑完冻结策略的全部轮次,每一轮都重新过效果前边界。
      • 进程中途退出以后,job resume 只读、只对账已经开始的轮,不开新轮。
      • 后面的轮只由新的一次 job dispatch 接着开,从下一轮起,照样每轮过效果前边界。
    • job status 逐轮列出。
    • 测试:
      • 桩网关上三轮;首次通过在第二轮停;
      • 换新上下文时三轮的租约号各不相同;
      • 基线不过的那一轮;窗外的轮在分母里;
      • 同一(S,轮次)再派发被拒;
      • 第 1 轮和第 2 轮之间进程退出:job resume 不开第 2 轮,新的 job dispatch 从第 2 轮接着跑。
  3. 汇总(repetition.ts,按聚合方式的一张表,satisfies Record<Aggregation, …>):
    • 输入:逐轮的动态层终态(已过完整性规则,V03 R[5]),加这个要求项期望的结局。
    • 每一轮先判它合不合期望,照 terminals.ts 的 meets()。期望通过时,通过合、失败不合;期望失败(对照或反向的用例)时,带期望码的失败合、通过不合。
    • 汇总按“合不合”算:
      • 全部:各轮都合 → 终态取合期望的那个。有一轮不合 → 终态取不合期望的那个,码取第一次不合的(首因不丢);既有合又有不合 → 同时标 intermittent,要求项不满足。
      • k-of-n(R[1]):合的轮数 ≥ k → 合期望的终态;不合的轮数 > 次数 − k → 不合期望的终态;否则缺判定。
      • 首次通过(R[2]):有一轮合 → 合期望的终态,之前不合的轮照样列在分布里;各轮都不合 → 不合期望的终态;否则缺判定。
      • 缺判定(有轮是无判定、未运行、未完成,又定不下来):取其中最弱的,写明缺哪几轮,出口是重跑这几轮(hub-unknown-model 的 exit)。
    • 观测分布(R[3]):次数,各终态的个数,逐轮列表(轮次、终态、码、合不合期望),全部保留。
    • 测试:
      • 每种聚合方式的表格用例:全合、全不合、间歇、缺轮;
      • 每张表都加期望失败的几行:期望失败时,三轮全失败是满足;两次失败一次通过是间歇、不满足;
      • 性质测试:k 等于次数的 k-of-n,对任意轮次序列和任意期望,都和“全部”给出同样的终态和满足状态。
  4. 完整性和目标自报(V03 R[5]、D02 R[6]):
    • “结果按派发身份归属”在这个网关版本上没认证时,每一轮都是无判定,汇总也是无判定(完整性未证明),出口是认证这条前提(管理员,dispatch-gateway 第 12 条)。
    • 目标逐轮的报告另外汇总成一条观察主张,带“目标对本次派发的报告”,也写观测分布,例如“目标报告:3 次里 2 次通过、1 次失败(间歇)”。这是确定的观察,不满足只收事实的要求项。
    • 测试:认证和没认证各一。
  5. 间歇的归责(V04 R[0]、R[1]、F[5]):
    • 只有汇总的终态不合期望时才带归责(V04 R[1]),记 unattributed(待归因)。
    • 被测对象缺陷、环境、执行上下文三种原因写成假设集,经 hub-unknown-exits 第 4 条加的 V08 记录写,不进归责。
    • 测试:合期望的间歇不带归责;不合期望的带 unattributed,并有一份假设集。
  6. 显示(展示规则 16):答复和控制台写观测分布,例如“3/3 次未见失败”“间歇:3 次里 1 次失败(第 2 次)”。动态层没运行时,静态的“通过”旁边写规则@版本和动态层的状态,不用“未上设备”这类领域词。测试:text.test.ts、console.test.ts 各几条。
  7. oracle:tests/acceptance/oracle 的动态层规则加上汇总,差分测试照新规则;引擎 README 的终态一节同步。

不做:两次运行之间的自动比较。V07 R[4] 只约束比较怎么做,Hub 现在没有运行之间的比较,决定 35 第 13、16 项也没要。以后加比较的地方要照 R[4] 写“重复策略不同,不可比”,README 记一句。

完成后在终端里回报:提交号、测试数量、没做完或拿不准的地方。