返回设计文档

EXECUTION · 06/08

Six-Step Model

Evidence 到 Campaign 的 canonical execution order。

真相源
docs/DESIGN_6STEP.md
读取方式
构建时本地读取
规模
540

Status: active Scope: six-step execution model, evidence states, Steps 4-6 / fail2pivot boundary Owner: nexrur.engines Related: DESIGN_五桶证据.md, DESIGN_DIAGNOSIS.md, DESIGN_ENGINES_CAMPAIGN.md, DESIGN_AISKILLS.md Tracking: dakoolfrank/nexrur#95


1. 定位

本文冻结 nexrur 的六步执行模型,以及 Steps 4-6、fail2pivot、AI-skills trace、 active promotion、campaign execution 之间的顺序边界。

它不是新的 engine,也不是替代 diagnosis / campaign / evidence / projection 设计文档。它只回答一个问题:

一个 app/subagent/module 从 evidence 到 production,再到失败治理,底座按什么顺序调度?

2. 六步模型

六步模型固定为:

1. Evidence
2. Product
3. Schema
4. Re-evidence
5. Diagnosis
6. Campaign

含义:

  • Step 1 Evidence 收集、压缩并组装 Product 输入;facts / digest / obligations 是 Evidence 内部组成,不是三个顶层 Step。
  • Step 2 Product 生成业务结果,并拥有本轮 Product status/reason/reason_code。
  • Step 3 Schema 机械验证 Product,不做 root-cause / route。
  • Step 4 Re-evidence 在 Product + Schema 落盘后重新组装 Diagnosis 输入。
  • Step 5 Diagnosis 解释事实并生成 diagnosis_result
  • Step 6 Campaign 消费 Diagnosis 并生成 campaign_control
  • fail2pivot = Step 5 Diagnosis + Step 6 Campaign;它消费 Step 4 Re-evidence,但 Re-evidence 本身不属于 fail2pivot。

程序只负责证据、合同、落盘和调度;业务解释交给 diagnosis,执行控制交给 campaign。

2.1 Product 返回即封存

Step 2 Production 一旦返回 Product,本 cycle 的 Product 事实即封存。这里的 “封存”是字段所有权约束,不是新增 envelope、receipt、hash、文件或第二条 Product 总线。

Production 拥有并封存的字段包括:

status / reason / reason_code / failure_kind
artifact_refs / evidence_refs / warnings / errors
以及 producer 明确返回的其他业务字段

后续步骤必须遵守:

  • Step 3 Schema 只追加机械校验 finding。
  • Step 4 Re-evidence 只追加诊断证据。
  • Step 5 Diagnosis 只写自己的 diagnosis_result / result_code
  • Step 6 Campaign 只写自己的 campaign_control / result_code
  • Orchestrator 和 Parent 只追加执行坐标、运行事实及控制回执,并原样传递 Product。

Product 已经存在后,如果 evidence handoff、projection、active promotion、identity check 或其他 runtime/infrastructure 动作失败,该失败可以停止当前执行图,但只能 进入独立的 execution/runtime incident channel;不得用执行失败的 status、reason 或 code 覆盖 Product。只有 Campaign 在新 cycle 中重跑拥有该 Product 的 Production,且 producer 返回新结果,Product 才可能改变。


3. Evidence State

底座 evidence state 固定为三种:

evidence
step6_evidence
restart_evidence

对应 envelope:

envelopes/evidence.json
envelopes/step6_evidence.json
envelopes/restart_evidence.json

对应 digest lane:

digest/evidence/
digest/step6_evidence/
digest/restart_evidence/

规则:

  • evidence 是 Step 1 输出,也是正常首轮 / 顺跑 Product 输入。
  • step6_evidence 是 Step 4 Re-evidence 在 Step 2 Product / Step 3 Schema 已落盘后生成、供 Step 5 Diagnosis 消费的现有物理 envelope 名。
  • restart_evidence 是 campaign 接受 repair/restart 后下一次 attempt 的输入。 它进入下一 cycle 的 Step 1 Evidence,不构成第七步。
  • 如果 restart target 是当前 campaign-owned trace 的任意 orchestrator 阶段, 下一次 attempt 必须是同一 trace_id 下的新 cycle_no / cycle_segment
  • trace_id 只来自新的 CLI campaign 或 campaign 内新的 asset attempt。
  • restart_evidence 不得追加到已经完成的旧 cycle;它必须写入新 cycle 的 独立 lane。

4. Steps 4-6 / fail2pivot 顺序

Steps 4-6 的底座执行顺序固定为:

Step 4 Re-evidence -> step6_evidence
  -> Step 5 Diagnosis -> diagnosis_result
  -> Step 6 Campaign -> campaign_control
  -> trace.py 写 step6.json
  -> campaign execution

解释:

  1. Step 4 Re-evidence 产出 step6_evidence,作为 Diagnosis 输入。
  2. Step 5 Diagnosis 产出 diagnosis_result
  3. Step 6 Campaign control builder 消费 diagnosis_result 和 app campaign assets, 产出 campaign_control
  4. trace.py 把 Steps 5-6 结果写入当前 trace/cycle 的 envelopes/step6.json
  5. campaign execution 根据 campaign_control 执行 restart / halt / route。
  6. 只有整个 subagent product graph 成功关闭时,orchestrator 才调用 nexrur_projection_active,把完整 cycle 投影到 active。

fail2pivot.py 只组合并执行 Step 5 Diagnosis 与 Step 6 Campaign control 生成;它不重新执行 Step 4 Re-evidence,也不把 Evidence 内部子阶段提升为顶层 Step。

Steps 5-6 的 code 命名空间固定分离:

production_result.reason_code
  -> producer-owned Product 事实,后续层只读并原样保留

diagnosis_result.result_code
  -> Diagnosis 对事实的独立分类,不是 Product reason

campaign_control.result_code
  -> Campaign 消费并携带的 Diagnosis route key

step6.execution_result_code
  -> Steps 5-6 自身执行结果,例如 diagnosis unavailable;不是 Product reason,
     也不是 Diagnosis 分类或 Campaign route key

diagnosis_resultcampaign_control 中禁止出现 Diagnosis reason_code 兼容字段。Campaign 不得用 production_result.reason_code 作为 result_code 的 fallback;fail2pivot、Steps 5-6、child graph 和 parent graph 也不得 把 result_code 提升或改写成 Product reason_code

Steps 5-6 自身失败时仍然遵守同一边界:diagnosis_unavailableprompt_a_failedgolden_no_eligible_cardscampaign_handoff_failed、projection failure 等只能进入 step6.execution_result_code、对应组件的 execution_statuserrors。它们不得写入、覆盖或替换 production_result.reason_code。如果 step6.json 为兼容投影保留顶层 reason_code,该字段只能是原 Product reason_code 的原样副本或空值,不能承载 Step6 执行码。Parent handoff 同样必须传播原 Product code,而不是选择 Step6 执行码作为新的 Product 原因。

关键边界:

  • campaign_control 已生成,不等于 campaign execution 已完成。
  • step6.json 是本次失败/restart 的 Steps 5-6 诊断与控制真相;失败 cycle 不更新 active。
  • restart evidence 同时读取本次 Step6 trace 和 last-known-good active,不能把失败 cycle 冒充业务成功快照。
  • graph_role=module 的嵌套模块只落本模块 Steps 4-6 现场,不发布共享的父级 active;父级 active 只由完整 subagent graph 成功收口后统一晋升。
  • 当前 cycle 没有真实业务文件,或完整 product graph 未成功关闭时,不得发布, 也不得覆盖上一版 active。
  • 如果 campaign_control.statusrestart_requestedhaltescalation_requested,fail2pivot 必须在 trace + active 完成后返回一个 非 completed 图状态,让 orchestrator 停止继续普通 downstream 并把控制权交给 campaign。
  • 如果 campaign_control.status=continue_with_repair,fail2pivot 必须返回 partial,而不是伪装成 successpartial 是 orchestrator 的 completed dependency status:当前 graph 继续执行 downstream,但 Steps 5-6、checkpoint、 active 和 Admin 仍保留问题与待修复目标。
  • 如果 campaign_control.statuscontinueno_failure 或同类无需修复的 状态,fail2pivot 才返回 success,让 orchestrator 正常继续 / 完成。

4.1 Production-wide non-blocking partial

partial 不是 Mirror 特例。任何 Step 2 Product leaf、nested module 或 subagent 都必须能用同一份结果合同报告“已有可用业务产物,但仍有质量问题”:

status: partial
reason_code: <producer-owned factual reason or empty>
failure_kind: <factual class or empty>
errors: []
warnings: []
artifact_refs: [<real usable business artifacts>]
evidence_refs: []

该合同的固定语义是:

  • partial + 真实可用 artifact_refs 是非阻断质量事实,不是 success,也不是 restart 指令。
  • Production 只报告自身事实和 refs;不得决定 continue_with_repair、target、 restart 或 halt。
  • Orchestrator 把 partial 视为已完成依赖,继续执行剩余 Product 工作、Step 3 Schema、Step 4 Re-evidence、Step 5 Diagnosis 和 Step 6 Campaign;不得因为 上游不是 success 就制造 *_upstream_result_failed 二次误诊。
  • Step 4 Re-evidence 必须把该问题收入 phase_issue_facts 并设置 requires_diagnosis=true。Step 5 Diagnosis 必须解释,Step 6 Campaign 必须 给出正式控制结果。
  • Diagnosis 判断为可延后修复且 campaign.yml 存在合法 continue_with_repair 路由时,当前 graph 继续,repair target 留在当前 campaign_control / checkpoint 中供后台处理。
  • failed / blocked,或声明的业务产物不存在、不可读、不可作为本轮交付时, 仍是阻断事实,必须进入 restart / halt / escalation,不得借 partial 放行。

因此,非阻断不是 Python 对某个 reason code 的硬编码,也不是绕过 Diagnosis:

Production partial
  -> Step 4 Re-evidence phase_issue_facts
  -> Step 5 Diagnosis result_code + non_blocking_repairable intent
  -> Step 6 Campaign continue_with_repair
  -> fail2pivot partial
  -> downstream continues; repair remains visible

4.2 Nested / outer Re-evidence 的物化复用边界

nested module 和 outer subagent 都必须完整执行自己的 Step 4 Re-evidence。两层的 production、schema、runtime、phase facts 和 diagnosis scope 不同,因此禁止跨层复用 完整 facts bundle、digest、obligations、handoff 或 diagnosis_evidence_packet

但 Step 4 重新运行不等于相同 upstream 文件必须重复物化。对于相同的 upstream source group,底座只允许复用其物理 raw copy / inventory refs:

Mirror Step 4
  -> 独立组装 Mirror Re-evidence
  -> raw_evidence source receipt miss
  -> 一次 batch projection,写入 raw_evidence inventory

Outline Step 4
  -> 独立组装 Outline Re-evidence
  -> 相同 raw_evidence source receipt hit
  -> 复用 inventory refs
  -> Outline production/schema/runtime facts 仍重新收集与组装

复用判断必须按:

state + source_id + target subtree + source fingerprint

不同 source id 必须分别判断;不能对整个 upstream lane 共用一个大 fingerprint。 source fingerprint 不得包含 run_id / step_run_id,完整 Evidence cache 则继续保留 这些 scope identity。两套机制不能合并。

物化必须通过 projection 的 write_aiskills_bundle 一次提交 batch;运行 receipt 写入 docs/ai-runs/.engines/.projection-materialization/,不得进入业务 aiskills、 envelope、artifact/evidence refs 或 active。详细 fingerprint、临时目录、逐项 os.replace、completed receipt 与 hash 校验协议,以 DESIGN_五桶证据.mdDESIGN_AISKILLS.md 为准。

该优化只改变底座物理写入与复用方式,不改变六步顺序、Step 4 输入范围、Step 5 Diagnosis 或 Step 6 Campaign 语义,也不得通过增加 ToolLoop timeout 代替修复。

同一 trace/cycle 内 nested Step 4 首次提交 source group 时,receipt 必须记录目标文件 hash、size 与 mtime。outer Step 4 对未变化目标只做边界、数量和 size/mtime 快速校验; 元数据变化才回退到 SHA-256。source inventory 已取得的 stat 事实必须复用,禁止 reader 为了 fingerprint 再做一轮逐文件 resolve/stat。该快速路径只减少重复 I/O,不复用两层 各自的 facts bundle、diagnosis scope 或完整 Evidence cache。

如果 upstream source 有 canonical manifest,首次 Step 4 还必须写 source-inventory receipt;同一 trace/cycle 的后续 Step 4 只验证该 manifest marker 并复用逐文件 inventory facts。这样 nested 与 outer Step6 都仍独立执行,但不会在每层再次递归扫描相同原始资料。


5. step6.json 的含义

step6.json 是 Step 5 Diagnosis + Step 6 Campaign 的组合结果落档,可以包含:

diagnosis_result:
  execution_status: success | failed
  result_code: <diagnosis-owned classification>
  explanation: <diagnosis explanation>
campaign_control:
  result_code: <exact diagnosis route key>
execution_result_code: <step6 execution outcome; empty when execution completed>
reason_code: <exact producer-owned Product reason_code copy or empty>
step6_evidence: {}
diagnosis_evidence_packet: {}
artifact_refs: {}
warnings: []
errors: []

step6.json 的存在只说明:

Step 5 diagnosis result + Step 6 campaign control contract 已经生成并落 trace。

它不说明:

campaign execution 已经完成。

因此,step6.json 可以包含 campaign_control,但 campaign 的 route / restart / halt 执行必须发生在 active promotion 之后。


6. active promotion 的位置

active promotion 是 projection 能力,由 orchestrator 的 product-completion boundary 触发,不是 fail2pivot 内联逻辑。

固定职责:

组件职责
trace.py只写 trace/cycle 文件,包括 step6.json
active.py只把明确 cycle promote / project 到 active
fail2pivot.py执行 Steps 5-6,写 step6.json 并交付 diagnosis/campaign control,不碰 active
orchestrator.py完整 subagent product graph 成功后调用 active projection
campaign.py根据 Step6 control 执行 restart / halt / route

正确顺序:

fail2pivot.py
  -> projection trace writes step6.json
  -> returns success for clean continue, partial for continue_with_repair,
     or blocked for restart / halt / escalation
  -> campaign execution consumes campaign_control when graph is interrupted

completed subagent product graph
  -> orchestrator calls nexrur_projection_active
  -> active becomes the complete last-known-good snapshot

orchestrator 必须把最近一次 Schema result 的 validation_passed=true|false|null 原样交给 active projection。该字段只描述验证观察;falsenull 不得阻断已经 完成的 Product graph 晋升,也不得被伪造成 true

禁止:

  • trace.py 直接写 active。
  • fail2pivot.py 复制 active promotion 实现。
  • active.py 解释 Diagnosis result_code 或 campaign route。
  • campaign.py 回头改写 trace/cycle 的 step6.json

7. restart evidence 与 business 关系

restart 时 business evidence 必须能读到本次失败 Steps 5-6 和此前成功 active。

固定口径:

step6.json 落 trace
  -> campaign 执行 restart
  -> 同 trace / 新 cycle 跑 restart_evidence
  -> business reader 读取 last-known-good active + current Steps 5-6 diagnosis/reference

restart_evidence 的 business 结构以 DESIGN_五桶证据.md 为准:

business/
  upstream/
  diagnosis/
    step6.json
  reference.json

business/diagnosis/step6.json 是 restart-only,用于突出转入 restart 的 Step 5 Diagnosis + Step 6 Campaign result。


8. 反模式

禁止以下模式:

  • Steps 5-6 或中间 module 成功就提前更新整个 product active。
  • failed / blocked / restart_requested cycle 覆盖 last-known-good active。
  • campaign_controlstep6.json 拆走后又没有其它可追溯落档。
  • 把 active promotion 代码复制进 fail2pivot.py
  • 用 app owner 手工拼 Steps 4-6、active 或 restart evidence。
  • 在 Step 2 Product / Step 3 Schema / active 阶段解释 root cause 或决定 campaign route。
  • 在 fail2pivot / orchestrator Python 中按 Product reason_code 或 Diagnosis result_code 硬编码“partial 放行”。
  • diagnosis_result / campaign_control 中保留 Diagnosis reason_code 别名, 或用 Product reason_code 兜底缺失的 Diagnosis result_code
  • 把 Diagnosis/Campaign result_code 提升成 Steps 5-6、child graph 或 parent graph 的 Product reason_code
  • diagnosis_unavailableprompt_a_failedgolden_no_eligible_cards 或其他 Step6 执行码写入 Product reason_code,导致 parent 丢失 producer-owned 原因。
  • 把 Production partial 改写成 success,导致 Diagnosis 和后台看不到问题。
  • continue_with_repair 当成立即 restart,重复执行已经可用的当前 graph。
  • 因 nested/outer scope 不同而重复逐文件物化同一个 upstream source,形成 N+1 projection/schema 调用。
  • 为消除重复写入而跨 scope 复用完整 Step6 Evidence,导致 module facts 冒充 parent facts。
  • 用提高 ToolLoop hard timeout 掩盖 materialization N+1 或重复物化。

9. 验收口径

任何 Steps 4-6 / fail2pivot / projection active / campaign 调整,都必须能回答:

  1. step6_evidence 从哪里来?

    • Step 2 Product / Step 3 Schema 落盘后,由 Step 4 Re-evidence 生成。
  2. step6.json 写在什么时候?

    • Step 5 diagnosis_result 和 Step 6 campaign_control 生成后,由 trace 写入 当前 cycle。
  3. active 什么时候更新?

    • 完整 subagent product graph 成功关闭后,由 orchestrator 统一提升。
  4. campaign_controlstep6.json 里是否代表 campaign 已执行?

    • 不代表。它只是控制合同落档。
  5. restart production 读的 business 是什么?

    • last-known-good active,加当前失败 cycle 的 Steps 5-6 diagnosis/reference。
  6. restart 后是新 trace 还是新 cycle?

    • 同一 campaign-owned trace 内的 restart 都是同 trace 的新 cycle;新的 CLI campaign 或新的 asset attempt 才是新 trace。
  7. Production 已有可用产物但存在质量问题时怎么办?

    • Step 2 Product 返回 partial 和原始 refs;Step 4 Re-evidence 收集问题, Step 5 Diagnosis 诊断,Step 6 Campaign 只能通过声明式 continue_with_repair 让当前 graph 继续并登记修复目标。
  8. continue_with_repair 是 success 吗?

    • 不是。fail2pivot 返回 partial;它允许依赖图继续,但问题仍进入 Admin、 checkpoint、active 和后续修复治理。
  9. 三层 code 如何传递?

    • Product reason_code 原样保留;Diagnosis 只输出 result_code;Campaign 只按该 result_code 路由。三者不得别名、fallback、双写或相互覆盖。
  10. Product 返回后又发生 runtime/infrastructure failure 怎么办?

    • 原 Product 继续原样保留;运行故障进入独立 execution/runtime incident channel,必要时停止执行图。不得就地改写 Product;只有新 cycle 重跑 Production 才能产生不同 Product。
  11. Prompt A 过滤后没有 Golden 候选怎么办?

    • eligible_card_count=0run_prompt_a=false,不调用 LLM;Required Golden 报告独立的 Step6/Diagnosis asset-contract failure,同时原 Product reason_code 继续原样传递。
  12. nested module 与 outer subagent 是否都要跑 Step 4?

    • 都要。两层 Re-evidence scope 不同,facts、digest、obligations 和 diagnosis packet 必须分别生成。
  13. 两层共享相同 raw evidence 时是否必须重复写 inventory?

    • 不需要。只按 source id 命中 substrate materialization receipt 并复用物理 refs; 其它 source 和两层各自的 Step6 Evidence 仍独立处理。
  14. materialization receipt 是 Step 4 业务产物吗?

    • 不是。它只属于 .engines/.projection-materialization/ 运行事实,不能进入 aiskills、envelope、artifact/evidence refs 或 active。

10. 一句话总结

Step 1 Evidence -> Step 2 Product -> Step 3 Schema -> Step 4 Re-evidence
-> Step 5 Diagnosis -> Step 6 Campaign。
fail2pivot = Step 5 + Step 6;它消费 Step 4 的 step6_evidence,生成
diagnosis_result 和 campaign_control,再写 step6.json,
再 active,最后 campaign execution;active 是 campaign restart 前的真实状态快照。
campaign 内 restart 是 same trace new cycle;新 CLI campaign / 新 asset 才是 new trace。
Production partial 必须被 Diagnosis 看见,并由 Campaign 以
continue_with_repair 显式放行;不得跳过诊断或伪装 success。
Product `reason_code` 始终属于 Production;Diagnosis 与 Campaign 只使用独立
`result_code`,不得回写或提升为 Product code。
Production 返回即封存;后置运行故障单独记录并可以停图,但只有新 cycle 重跑
Production 才能改变 Product。

11. Step5/6 截止时间合同

nexrur_fail2pivot 是 Step 5 Diagnosis 与 Step 6 Campaign 的组合父级,其 execution watchdog floor 必须不短于本轮已接纳的 Diagnosis child、Campaign 确定性路由、结果组装与 Projection 收尾。通用 120 秒不能作为固定父壳,因为 Diagnosis 的单个 admission-aware LLM child 只要仍有进展就可以合法超过 120 秒。

Diagnosis 若存在 Prompt A 重试/候选筛选、Prompt B 解释等串行调用,可声明保守的 watchdog floor 防止父级短于 child;并发调用按 wave 暴露同类安全下限。该计算不构成 完成时限。Step6 graph floor 由 Orchestrator 单调发布,只能延长 Worker 的 operator watchdog,不能缩短它。

Step6 自身超时属于 Step6 runtime incident,不拥有 Production Product。即使 Diagnosis 未返回、Campaign 未收口或外层进程终止,也必须原样保留已经封存的 Product status/reason/reason_code/artifact_refs;不得以 diagnosis_unavailableTOOLLOOP_BATCH_ERROR 或任何 Step6 code 替换。只有新 cycle 重跑 Production 才可能 改变 Product。

验收至少覆盖:单个 Diagnosis child 长于旧 120 秒仍可成功、Prompt A 重试、Prompt B、 合法排队、Campaign 收尾、Step6 局部失败,以及 nested/outer Step6 的 watchdog 均不会 误杀仍有进展的 child。