返回设计文档

ENGINE · 04/08

Diagnosis

五桶输入、bounded cognition、result contract 与边界。

真相源
docs/DESIGN_DIAGNOSIS.md
读取方式
构建时本地读取
规模
3,516

Status: active Scope: diagnosis input ownership, schema ownership, ai-runs ownership, local/crossdomain cognition boundaries See also: DESIGN.md, DESIGN_SCHEMA.md, DESIGN_GOLDEN.md, APP_MIGRATION_HANDBOOK.md Tracking: dakoolfrank/nexrur#140

版本: v1.1 所属: nexrur 底座
状态: 核心设计文档(系统级)
定位: program-first LLM agent 的统一诊断中枢设计


目录

  1. 一句话定位
  2. 为什么 Diagnosis 是核心中的核心
  3. Diagnosis 在系统中的位置
  4. 核心原则
  5. Diagnosis 的五桶 evidence 输入体系
  6. Diagnosis 的输出体系
  7. 底座与应用层边界
  8. Consumer Diagnosis Asset Pack 标准
  9. Diagnosis 与 ToolLoop / Campaign / Orchestrator 的关系
  10. 与 core / memory 的关系
  11. 标准数据流
  12. 文件归属与目录设计
  13. 为什么不能让 app 继续长 diagnosis engine
  14. 与 Cross-Domain / Cognition 的统一关系
  15. Diagnosis Input Ownership
  16. Diagnosis And Multi-App Execution
  17. ai-runs Ownership Model
  18. Future runroot Refactor Constraints
  19. 迁移路线
  20. 完成定义
  21. 反模式与禁止事项
  22. 一句话总结

1. 一句话定位

Diagnosis 是 nexrur 的统一诊断中枢:它是 program-first agent 的“眼睛与大脑”,统一消费五桶 evidence 与 consumer diagnosis assets,并向 campaign 提供可执行路由前的解释与建议。

它不是普通 helper,不是 campaign 的附属品,也不是某个 consumer 的局部技巧模块。它是:

  • nexrur 的核心智能解释器
  • fail-to-pivot 的核心判断器
  • diagnosis_result 的统一产生器
  • 证据链的最大消费者

2. 为什么 Diagnosis 是核心中的核心

很多系统会先拥有:

  • Orchestrator
  • Campaign
  • ToolLoop
  • Evidence
  • 显式 memory / cognition / cross-domain 输入
  • Memory

但如果 Diagnosis 没有真正站在这些资产的中心消费它们,就会出现一个典型问题:

四肢很强,但大脑失明

也就是:

  • orchestrator 在排步骤
  • campaign 在跑循环
  • toolloop 在做局部工具探索
  • evidence 在积累事实
  • memory 在积累经验

但是最核心的 LLM 判断层没有统一消费这些依据,导致:

  1. 路由建议不稳定
  2. fail-to-pivot 缺乏统一解释器
  3. route hint 变成局部 patch,而不是全证据链判断
  4. cross-domain lesson 无法真正进入主脑
  5. cognition(brief/validation)无法变成可计算的上游依据

所以 Diagnosis 的意义不只是“多一个诊断模块”,而是:

把 program-first 架构辛苦积累的全证据链真正交给大脑去解释。


3. Diagnosis 在系统中的位置

                  ┌──────────────────────────────────────────┐
                  │        Consumer Apps / Domain Skills     │
                  │      WQ-YI / AGV / AUDIT / others        │
                  └──────────────────────┬───────────────────┘
                                         │
                                         │ 提供标准化 diagnosis assets
                                         ▼
                  ┌──────────────────────────────────────────┐
                  │     Consumer Diagnosis Asset Pack        │
                  │  evidence / catalog / golden     │
                  │  cases / counterexamples / patterns      │
                  └──────────────────────┬───────────────────┘
                                         │
                                         │ consumer semantics
                                         ▼
┌────────────────────────────────────────────────────────────────────────────┐
│                           nexrur Diagnosis Substrate                      │
│                                                                            │
│  core     -> app run ledger / manifest / outcome / audit refs              │
│  engines  -> orchestrator / campaign / toolloop bounded execution facts     │
│  aiskills -> app active business artifacts / schema / diagnosis projections │
│  memory   -> contentstore / vectorstore historical recall units             │
│  golden   -> approved diagnosis positive cases / counterexamples / patterns │
│                                                                            │
│                          context.py                                        │
│    select / normalize / deduplicate / bound material -> DiagnosisInput     │
│                          diagnosis.py                                      │
│    DiagnosisInput -> diagnosis_result                                      │
│    result_code / confidence / evidence_refs / explanation                  │
└──────────────────────────────┬─────────────────────────────────────────────┘
                               │
                               │ validated diagnosis result only
                               ▼
                  ┌──────────────────────────────────────────┐
                  │              campaign.py                 │
                  │  continue / continue_with_repair         │
                  │  restart / reroute / halt / budget       │
                  │  restart target subagent from phase 1    │
                  └──────────────────────────────────────────┘

最关键的一点:

  • Diagnosis 解释
  • Campaign / Orchestrator 裁决与执行

这正是 program-first 的核心分工。


4. 核心原则

4.1 Program-first,不是 LLM-governed

Diagnosis 再强,也只能:

  • 解释证据
  • 归纳根因
  • 输出独立 diagnosis_result.result_code
  • 说明 why_not_others

Diagnosis 不能直接:

  • 改 checkpoint
  • 改 budget
  • reset/replay
  • halt campaign
  • 强行改 final route

这些必须由:

  • campaign.py
  • orchestrator.py
  • 未来的 controller 层

来决定。


4.2 Diagnosis 是统一解释层,不是业务真身

底座 Diagnosis 负责:

  • “怎么诊断”
  • “怎么合并证据”
  • “怎么做 flash/pro review”
  • “怎么输出 suggestion”

consumer 负责:

  • “在这个业务域里,什么信号意味着什么”
  • “哪些 Diagnosis result code 存在”
  • “diagnosis result_code -> target_step 如何映射”
  • “重复失败如何升级”

4.3 底座统一,应用收窄

Diagnosis 的未来不是每个 app 都各写一套 toolloop_diagnosis.py
Diagnosis 的未来是:

  • 底座只有一个 engine
  • app 只提供标准化资产包

就像 Claude Code:

  • skill 可以不同
  • knowledge 可以不同
  • 但 agent 大脑不应该每个 app 自己重写一份

4.4 Product 结果所有权与 Diagnosis 命名空间

Production 拥有本轮 Product 结果的唯一定义权:

production_result.status
production_result.reason
production_result.reason_code

这三个字段是当前 cycle 的业务事实。Evidence、Schema、Step6、 Diagnosis、Campaign 和 Orchestrator 都只能读取、记录和原样转运, 不得覆盖、补全、canonicalize、压缩或重新选择它们。

Diagnosis 回答的是“Diagnosis 如何解释这个 Product 结果”, 必须使用独立命名空间:

diagnosis_result.result_code
diagnosis_result.explanation

diagnosis_result 中禁止再出现 reason_code,也不保留兼容别名或 双写。result_code 是诊断分类,不是 Product reason;它可以与 production_result.reason_code 文本相同,但字段所有权和语义仍然分离。

Diagnosis 不输出 Product-like pass / partial / stopgovernance_classrecommended_disposition。Campaign 可以读取 diagnosis_result.result_code 决定后续 cycle 的 continue / rerun / halt, 但不得因此改写当前 cycle 的 Product 结果。只有后续 cycle 重新运行 Production,才可能产生新的 Product status/reason。

Step6 只组合 Diagnosis 与 Campaign 的独立结果,不得把 diagnosis_result.result_code 提升为 Step6、child graph 或 parent graph 的 Product reason_code。若 Production 未返回有效结果而是突然崩溃,底座 可以另行记录 runtime incident,但不得冒充 Product reason。


5. Diagnosis 的五桶 evidence 输入体系

Diagnosis 必须统一消费五桶 evidence,而不是只看某个 step 的局部日志,也不是把 memory / cognition / cross-domain 当成绕过 evidence bundle 的独立判断层。

BucketDiagnosis 中的作用典型来源
core当前 app trace/cycle 的运行账本与 artifact refs.core manifest / outcome / audit / evidence refs
engines底座执行事实的 deterministic indexorchestrator checkpoint index、campaign state、toolloop events index
aiskillsapp 业务真值与 active projectionproduction / schema / diagnosis / envelopes / digest refs
memory历史经验与 recall,不是当前事实contentstore / vectorstore bounded retrieved units
golden已审核 diagnosis 案例 groundingpositivecases / counterexamples / patterns

五桶共同回答:

  • 发生了什么事实?
  • 哪一步失败或降级?
  • failure signal 来自 production、schema/validation、engines runtime,还是 app 业务约束?
  • 是否有 memory/cognition/crossdomain 经验支持某个解释?
  • 这个解释能否追溯到 artifact/evidence refs?

硬约束:

  • Diagnosis 不接受一句话 error 作为充分输入。
  • Memory/cognition/crossdomain 只能作为 memory bucket 证据,不能直接触发 route / halt。
  • Golden 只能作为 approved case grounding;selector result 不是 diagnosis verdict。
  • App 的 source truth 必须来自 app-owned manifest / asset pack;底座只解释和读取。
  • evidence_refsartifact_refs 必须可审计。

5.1 Evidence Context And Diagnosis Evidence Share One Evidence Contract

Consumer apps may use evidence.py or equivalent adapters to build Step 1/2/3 context, but the generic source truth must be an app-owned evidence manifest. For WQ-YI this manifest is:

.gemini/skills/_shared/engines/evidence/evidence.yml

The substrate diagnosis/evidence line owns the generic mechanism:

evidence.yml
  -> five-bucket readers: core / engines / aiskills / memory / golden
  -> evidence bundle
  -> evidence digest
  -> pre-LLM selector digest
  -> obligations
  -> current_scope / upstream_feedback

The substrate prompt asset for this pre-LLM evidence line is src/nexrur/prompts/evidence.md. It owns two sections:

evidence.md::evidence_digest
  -> consumed only by build_evidence_digest

evidence.md::pre_llm_selector
  -> consumed only by build_evidence_digest selector builder
  -> writes selector trace into golden digest for later handoff

The old standalone digest.md prompt has been renamed into evidence.md::evidence_digest and must not remain as a separate active prompt truth. Legacy pre-LLM selector text that used to live in app selector.md files or diagnosis prompt preambles belongs in evidence.md::pre_llm_selector; app-owned selector profiles may still supply owner/module goals and forbidden scope.

The five-bucket readers remain the same across first evidence, Step 6 diagnosis preparation, and campaign restart. The substrate builder, not the reader, selects the assembly contract through evidence_assembly_mode:

facts_evidence   -> first phase-1 evidence for Production
step6_evidence   -> bounded Step 6 handoff with diagnosis_evidence_packet
restart_evidence -> campaign restart feedback projected into phase-1 evidence

production_evidence and step6_evidence are active total handoff envelopes, not selector-only traces. build_obligations.py may copy existing digest manifest / bucket refs / selector trace into them, but it must not run digest or selector LLM. Both must embed the evidence core: facts summary, obligations, current_scope, upstream_feedback, missing/degraded/fallback facts, and evidence/artifact refs. A evidence_ref may be present for debug/lineage, but it is not sufficient as the active LLM handoff.

step6_evidence additionally contains validation facts, not full schema truth; runtime failure facts, not a full runtime dump; production/schema refs; and a canonical diagnosis_evidence_packet. That packet is the fail2pivot input. It must expose requires_diagnosis, trigger_signals, failure_kind, bounded validation/schema/production/runtime/phase facts, refs, and the diagnosis-mode pre_llm_selector / Prompt A result when golden cognition is enabled. The selector result is not the diagnosis verdict: it only chooses approved positive cases, counterexamples, or patterns for Diagnosis Prompt B/C. step6_evidence may also carry an explicitly prepared memory_recall bucket. Diagnosis does not open a RAG/vector client or perform runtime retrieval. That bucket is historical_auxiliary_recall_not_current_truth: Prompt A/B/C may read it as similar-case context, but it must not replace current evidence, prove a fact, raise schema confidence, or choose a campaign route. Campaign route, halt, restart, and Diagnosis result_code stay out of step6_evidence. The original Production reason_code may appear only inside the canonical Production facts and must remain an exact copy of the producer-owned value. step6_evidence_packet is not the canonical diagnosis input; if present, it is legacy/index-only. An envelope with diagnosis_ready: true but no diagnosis_evidence_packet is invalid for fail2pivot. Fail2pivot accepts one strict transport envelope. The caller must provide app_root, an explicit projection_identity, and exactly one of inline step6_evidence or step6_evidence_ref. The inline value must be a canonical step6_evidence_envelope; the referenced file must be named step6_evidence.json, remain below app_root, stay within 256 KiB, and contain the same projection_identity. Generic top-level evidence, phase-result scanning, artifact-ref discovery, and identity aliases such as top-level product / asset_id / trace_id / cycle_no, workspace, or canonical_id are not fallback sources and must fail closed.

projection_identity.scope=asset requires asset_id and writes StepSix under <product>/<asset_id>/<trace_id>/<cycle>/; scope=trace forbids asset_id, requires the Product projection contract to allow unbound traces, and writes under <product>/<trace_id>/<cycle>/. Fail2pivot must not invent a placeholder asset, infer identity from a directory, or silently skip Projection. A failed Projection changes the StepSix result to failed. restart_evidence requires diagnosis_result and campaign_control, then mechanically projects them into canonical upstream_feedback and current_scope before the target subagent reruns from phase 1.

Step 2 digest is the substrate build_evidence_digest contract. It reads only the evidence.md::evidence_digest section. It is LLM-assisted but program-validated: each read content unit from the five-bucket bundle must have a compact JSON representation and source ref. Digest failure is a diagnosis-ready failure, not a deterministic fallback success. Step 3 obligations may only assemble a schema-gated envelope from app-owned declarations, this digest, and evidence refs. The same obligation surface may then run evidence.md::pre_llm_selector in mode=production or mode=diagnosis and write production_evidence.json or step6_evidence.json. Those files must carry the evidence core inline before adding selector results or failure facts. Digest, Memory selector/arbitrator and pre-LLM selector profiles must be supplied explicitly by the App execution envelope. Evidence has no provider or model default. Digest and selector profiles remain separate contracts.

This evidence context is shared by production and diagnosis. Diagnosis must not require consumer owners to re-parse source-specific artifacts at Step 6, and production must not maintain private upstream scanners. If a downstream restart needs failure context, campaign/diagnosis facts must be represented as generic upstream_feedback in the evidence context through the restart_evidence assembly contract.

Substrate code must stay app-neutral. It interprets manifest declarations and normalizes evidence mechanics; it must not hardcode WQ diagnosis result codes, WQ artifact names, or app-specific route semantics. Consumer apps own the business source declarations, diagnosis/catalog semantics, production prompt context, campaign assets, and schema truth.

The allowed adapter role is narrow: app evidence wrappers may project the substrate evidence/digest/obligation envelope into their local production shape, but they must not define a second source truth, scan historical app directories independently, or introduce private feedback channels such as evaluate_feedback, field_updater_feedback, or previous_evaluate_outcome.


5.2 Evidence Payload JSON-Safe Contract

Five-bucket evidence payloads are runtime contracts, not Python object transport. Any value that crosses the ToolLoop, evidence reader, audit/evidence stream, checkpoint, orchestrator step result, or diagnosis bundle boundary must be JSON-safe.

Allowed payload values:

  • null, string, number, boolean;
  • arrays and objects composed only of JSON-safe values;
  • path refs as normalized strings, preferably POSIX-style relative paths;
  • assets_input, artifact_refs, current_scope, upstream_feedback, and memory_backend_status represented as JSON-safe objects.

Forbidden at those boundaries:

  • raw AssetRef or app-specific runtime objects;
  • Path, datetime, Enum, dataclass, namedtuple, or custom class instances;
  • open file handles, client/session objects, callables, or other live runtime handles.

Callers must convert runtime objects to JSON-safe values before entering the Evidence boundary. Evidence itself only compiles the explicit identity envelope through compile_current_scope(...), which validates:

artifact_refs
current_scope
current_artifact_refs
memory_backend_status
trace/run/step identifiers

AssetRef-like runtime objects should become standard evidence refs, for example:

{
  "kind": "abbreviation",
  "id": "ALTI",
  "path": "docs/ai-skills/evidence-papers/pending/ALTI",
  "metadata": {
    "source_type": "academic"
  }
}

When richer context is available, apps may include run_id, trace_id, artifact_kind, source_step, business_path, or nested artifact_refs, but the resulting object must still pass json.dumps(...).

This contract is substrate-owned and app-neutral. Apps must not patch around serialization failures by calling str(asset_ref) in local skill code, because that loses refs and leaves dataset/evaluate/other consumers exposed to the same boundary bug.


6. Diagnosis 的输入与输出体系

Diagnosis 的输出不是执行动作,而是给 campaign 消费的解释与建议。

6.1 Step 6 最小输入 envelope

每个 app 的 Step 6 diagnosis 输入必须先由底座 Step6 evidence handoff 规整成 diagnosis_evidence_packet

{
  "kind": "diagnosis_evidence_packet",
  "version": 1,
  "status": "ready",
  "subject_id": "...",
  "source_subagent": "...",
  "source_phase": "...",
  "requires_diagnosis": true,
  "trigger_signals": [],
  "failure_kind": "...",
  "validation_facts": {},
  "schema_errors": [],
  "production_failure_facts": {},
  "runtime_failure_facts": {},
  "phase_issue_facts": [],
  "phase_failure_facts": {},
  "diagnosis_facts": {},
  "evidence_refs": [],
  "artifact_refs": []
}

Fail2pivot 的外层调用不是上述 packet 本身,而是:

{
  "app_root": "<explicit app root>",
  "projection_identity": {
    "product": "<declared product>",
    "scope": "asset | trace",
    "asset_id": "<required only for asset scope>",
    "trace_id": "trace-...",
    "cycle_no": 1
  },
  "step6_evidence": {
    "kind": "step6_evidence_envelope",
    "step": "step6_evidence",
    "phase": "step6_evidence",
    "diagnosis_ready": true,
    "projection_identity": {},
    "diagnosis_evidence_packet": {}
  }
}

step6_evidence 可替换为唯一的 step6_evidence_ref,但二者不能同时出现。 需要实际 Diagnosis 时还必须显式提供 current_stepdiagnosis_assets_rootcampaign_contract_pathrequires_diagnosis=false 也必须携带完整 canonical packet, 不得以缺 packet 表示“不需要诊断”。两个合同路径按 app_root 解析且必须留在 该 root 内,不能借外部 contract 授予 Candidate 权限。未知输入字段和旧别名必须 fail closed。

说明:

  • validation_facts 对应 Step 5 Validation (schema-driven) 的机械事实。
  • production_failure_facts 对应 Step 4 输出里的 failure / degradation signal。
  • runtime_failure_facts 来自 engines bounded index,不是 full checkpoint/events。
  • phase_issue_facts 按执行顺序保留所有 Production / Schema / runtime 的原始 partial / degraded / failed / blocked 问题;它是完整诊断输入,不含 route verdict。
  • phase_failure_facts 只保留实际阻断当前 graph 的主故障兼容投影,不得替代 phase_issue_facts
  • diagnosis_facts 是 app-owned opaque mapping。唯一传输链是 leaf result.control_envelope.diagnosis.facts -> Orchestrator phase_failure_facts.diagnosis_facts -> Step6 diagnosis_evidence_packet.diagnosis_facts -> DiagnosisInput.evidence。 底座只做类型、深度、条目数和字节上限检查,不枚举 role、不解释数值,也不据此 直接生成 reason 或 route。超限正文必须由标准 refs 指向,packet 只保留 bounded copy 或 shape index。
  • refs 必须指向五桶 digest / source refs;app 不得在 Step 6 手拼 raw envelope。

所有 Production 都通过 App ToolLoop 合同的 control_envelope 显式声明 哪些 producer status 允许当前图继续。WQ 的 Product 合同把 partial 映射为 graph.disposition=continue,表示“本轮结果有问题,但可继续消费”。底座只读取 编译后的 disposition,不维护 partial/degraded/missing_required 等隐式允许列表。 这一决定不以 artifact_refs 存在为前提;artifact 缺失或不可读只是独立 evidence fact,不是隐藏的 Product status gate。

partial 可以令 requires_diagnosis=true,但 Step6 / Diagnosis / Campaign 不得将它在本轮就地升级为 failed / stop,也不得改写 producer 给出的 reason。若后续需要修复,Campaign 只能安排后续 cycle 重新运行 Production。当前 graph 必须按显式 graph.disposition=continue 继续。 skipped 不是第四种 Product status;合法 skip 由 producer 返回 status=partial 及其原始 reason,后续层仍只能原样转运。

6.2 diagnosis_result envelope

标准输出至少包括:

{
  "execution_status": "success | failed",
  "result_code": "...",
  "explanation": "...",
  "confidence": 0.0,
  "failure_class": "schema | evidence | coverage | business_semantics | upstream_dependency | runtime | unknown",
  "why_not_others": [],
  "evidence_refs": [],
  "artifact_refs": [],
  "metadata": {}
}

diagnosis_result.execution_status 只表示 Diagnosis 这次执行是否产生了合法 诊断,不是 Product status。Diagnosis 不输出 active target_step / target_subagentrecommended_disposition 或 Product-like status。最终 route / halt / continue 必须由 Campaign 根据 diagnosis_result.result_codecampaign.yml 控制,且不改写当前 production_result

6.2.1 Diagnosis result classification

Step 6 evidence may contain multiple factual signals, including the producer's immutable reason_code plus schema/runtime facts. Diagnosis may classify those facts into one independent advisory result_code, but it does not select a replacement Product reason. The substrate may perform this classification only through generic rules:

  • candidate facts come from the evidence bundle;
  • signal_class, fallback_only, overridden_by_signal_classes, and priority come from the consumer diagnosis catalog/golden assets;
  • fallback reasons may be suppressed by stronger signal classes declared in assets;
  • priority is only a tie-breaker after asset-declared suppression rules;
  • diagnosis returns an advisory result_code only inside diagnosis_result.

Diagnosis still must not execute campaign restart, halt, budget mutation, or checkpoint changes. Campaign remains the only layer that validates and executes the resulting route. No arbitration result may be copied back into Product facts.

6.2.2 Non-blocking Production issue diagnosis

Diagnosis 不能靠“忽略 partial”实现放行。对于 Production 上报的非阻断质量 问题,Diagnosis 必须:

  1. 消费 phase_issue_facts 中该 producer 自己的原始 reason、errors、warnings 和 refs;
  2. 原样保留 production_result.status/reason/reason_code
  3. 从当前 step scoped diagnosis.yml 选择受证据支持的 diagnosis_result.result_code,并给出 explanation
  4. 保留 why_not_others,说明其他诊断分类为何不成立;
  5. 把后续 cycle 的执行权交给 Campaign。

Diagnosis 不判定 partial “能否继续”;这已由 Production 的 status=partial 定义。即使 Diagnosis 失败或无法给出合法 result_code,也只能记录独立 Diagnosis runtime incident,不得把已有 Product partial 改成 stop。

6.3 campaign_control handoff

Campaign 消费 diagnosis 之后应返回独立控制结果,例如:

{
  "status": "continue | continue_with_repair | restart_requested | halt | failed",
  "target_subagent": null,
  "restart_from_phase_1": false,
  "internal_phase_hot_repair_allowed": false,
  "routing_decision": {}
}

Diagnosis 不直接产出:

  • reset 行为
  • halt 行为
  • budget 扣减
  • replay 执行
  • lifecycle mutation
  • middle-phase restart
  • prompt-level patch-and-continue

6.4 Diagnosis fallback_alarm semantics

Fallback is an alarm, not recovery. fallback 是报警,不是恢复成功。

Diagnosis LLM unavailable, no result, no suggestion, adapter signature mismatch, asset pack mismatch, and malformed diagnosis output must produce fallback_alarm or an equivalent failed diagnosis envelope. They must not be normalized into successful diagnosis output.

Minimum failed diagnosis envelope:

{
  "diagnosis_result": {
    "execution_status": "failed",
    "fallback_alarm": {
      "triggered": true,
      "kind": "llm_unavailable | diagnosis_missing_result | diagnosis_no_suggestion | adapter_mismatch | unknown",
      "source": "diagnosis",
      "severity": "failed",
      "diagnosis_ready": true
    }
  }
}

Diagnosis must not return a fake result_code, fake target_subagent, fake suggestion, or execution_status=success to hide fallback. no_suggestion is not success. If diagnosis cannot produce a valid result, Campaign receives a failed Diagnosis envelope and decides the Diagnosis retry/escalation or later-cycle engineering action. That failure remains separate from the already returned Product result and cannot reclassify a valid Product partial.


7. 底座与应用层边界

Diagnosis 的底座/应用边界必须像 ToolLoop 一样被明确钉死。


7.1 底座负责什么

放在 nexrur:

  • src/nexrur/engines/diagnosis/
  • src/nexrur/prompts/diagnosis.md
  • five-bucket evidence readers/builders/interpreters where generic
  • diagnosis asset pack loading and generic matching shell
  • asset-driven diagnosis result classification
  • diagnosis result envelope normalization

负责:

  • 消费 app diagnosis asset pack
  • 消费 app-provided evidence bundle / refs
  • 解释 Validation (schema-driven)、production、runtime、business/local evidence 的 failure signal
  • 产出 diagnosis_result
  • 保持 app-agnostic,不硬编码 consumer 业务词

7.1.1 Diagnosis Prompt pack

所有 nexrur-owned Diagnosis LLM 文本必须只存在于 src/nexrur/prompts/diagnosis.md。该文件使用既有的

```prompt:<section_name>
...
```

命名块合同,覆盖 Flash、Pro、Golden A/B/C、历史学习以及 learning research planning/synthesis。Python 只允许加载、变量渲染、hash、预算和 Schema 校验,不得 保留 _DEFAULT_*、应急 Prompt 或字符串 fallback。

多个运行角色可以显式绑定同一个命名块,但绑定表只能描述底座 Prompt 角色,不得 包含 App/provider 语义。Prompt 文件缺失、命名块缺失或命名块为空时必须 fail closed;不得退回 Python 内嵌文本。App-owned 业务 Prompt 仍留在 App 的 scripts/skills/*.md,不得搬入本文件。

旧的 root-level Markdown compatibility 已退场:DiagnosisMarkdownAssetpatterns_textcounterexamples_textexamples_text 以及相应的目录扫描、选择 和渲染链均不属于 active contract。Golden 只能通过已登记的 index/full assets 进入 Prompt A/B;底座不得重新扫描 patterns/examples/counterexamples/ 拼接自由文本。

nexrur.engines.diagnosis 包入口必须使用显式 import 与 __all__ 白名单,只公开稳定 边界、输入组装、Golden handoff、Engine 和公共诊断入口。禁止 from .context import * 或把 context 内部 helper 自动升级成公共 API。

7.1.2 Diagnosis boundary / context / execution split

engines/diagnosis/boundary.py 只拥有声明:输入输出 dataclass、运行 Protocol、Schema role 常量、Schema 读取和声明结构的机械校验/序列化。它不得读取消费方资产、解析 evidence、计算 evidence fingerprint、渲染 Prompt JSON、生成 diagnosis id、校验 LLM 响应或执行 Campaign route。DiagnosisAssets 不得保留 targets 等 Campaign-shaped 兼容字段;LLM 协议只保留唯一正式名称 LLMClient

engines/diagnosis/context.py 只拥有输入侧工作:消费方资产读取、Golden 文件解析、 catalog/evidence 事实规范化、DiagnosisInput 组装、Prompt pack 加载,以及 Prompt A/B/C 所需的 bounded material preparation。Prompt A 的 eligible cards、Prompt B 的 selected full-asset handoff、Prompt C 的 episode/scope/approved/inactive comparison、 historical fact bundle 都必须在这里准备完成。它不得调用 LLM、裁决 Prompt 输出、选择 最终 Diagnosis result、编译或写入新的 learning candidate。

context.py 的正式 material API 必须直接以公开函数定义存在;禁止先定义 _private helper、再在文件末尾批量赋值成公开别名。Diagnosis 和 StepSix 只能导入这些显式公开 接口。Golden YAML 只要存在就必须严格解析为 mapping;损坏、空 index、路径穿越或 真实路径逃出显式 Golden root 时一律 fail closed。

engines/diagnosis/diagnosis.py 只拥有判断与结果:调用 Prompt A/B/C、规范化并校验 模型输出、形成唯一 Diagnosis result、编译 learning candidate、持久化 inactive candidate、编译同 episode Candidate Trial handoff,并形成最终 DiagnosisSuggestion。所有写入仍须保持 proposed/inactive、幂等去重、真实路径约束、 原子发布和 fail-closed;该边界不授予 Diagnosis active promotion 或 Campaign route 权限。

diagnosis.py 内部按唯一责任顺序组织为七段:Prompt 输出规范化/校验、Candidate 编译/持久化、Candidate Trial handoff、Diagnosis 结果构造/校验、Engine、ToolLoop LLM 适配、公共 facade。这里的“规范化”只允许合同明示的 Prompt A 解释字段别名; 规范化后必须删除别名并按正式 Schema 验收。Flash、Pro、Golden A/B/C 或 ToolLoop 返回任何 Schema 违规都必须拒绝该次输出,不能只记 warning 后继续采用。

DiagnosisInput.subject_id 是调用方给出的诊断主体真值。模型输出不得包含或覆盖 target_subject_id;Diagnosis ID 与 RepairScope.subject_id 只能从该显式输入生成。 Diagnosis 也不得输出 target_covered、route basis、lifecycle verdict 等 Campaign-shaped 字段。Engine 不保留未参与裁决的 confidence threshold;可采用性由 Schema、catalog/evidence gate 和明确的零置信度失败规则共同决定。

两个模块之间只允许显式公开接口。diagnosis.py 不得导入 context.py_private helper;context.py 也不得反向导入 diagnosis.py。材料准备与判断执行不得再因为一次 大块迁移而混在同一文件。

Episode identity 只能由顶层 projection_identity.trace_id + cycle_no 和 canonical diagnosis_evidence_packet.source_phase 编译;cycle_id 机械写成 cycle-000N。可选 phase_path 也只能来自同一个 diagnosis packet。底座不得从 metadata、顶层 source_phase / cycle_id / source_scopefailed_phase / phase 别名、目录名或相邻结构补值;缺失或冲突必须 fail closed。 Golden card 的 app/subagent/module scope 同样只读显式 source_scopeasset_ref 目录仅用于文件寻址,不得反推业务身份。

Inactive candidate queue 是受治理输入。读取时必须验证真实路径仍位于明确绑定的 Diagnosis asset root 内,并校验 candidate schema、review_status: proposedactive_runtime_allowed: false。任何损坏、越界或冲突文件都必须阻断比较、编译和写入, 不得静默跳过。新候选必须先写入同目录临时文件并原子发布到最终路径;不得直接向最终 文件写入半成品,也不得覆盖已有文件。

历史学习中的文件读取不属于 Diagnosis 执行。engines/evidence/read_golden_artifacts.py 拥有 app-relative source 校验、Markdown heading 定位、表格/围栏代码/行内代码/ 数值与声明文本事实抽取,以及 source file hash、line span、span hash 和事实单元身份 编译。它只返回带明确来源的 bounded fact units,不调用 LLM、不生成 Candidate、 不执行 Prompt C。diagnosis.py 只能消费这些已编译事实来运行历史 Prompt C 和后续 candidate 逻辑,不得再次直接解析历史 Markdown。

Learning Research 也不属于 Diagnosis 执行。engines/stepsix/fail2pivot.py 独占 learning_research / learning_research_eligibility 合同编译、是否允许外部学习的 判断、query planning、search/read 调度、synthesis context 和 grounded unit 编译。 StepSix 只能把编译完成的标准 learning_research_units 和已验证的 app provenance evidence_role 显式交给 Prompt C; diagnosis.py 不得读取 Learning Research 合同、猜测 app evidence_role,也不得 组织 search/read 或重新编译 units。Prompt C 只把这些 units 当作 learning-only 参考材料,不能将其升级为普通 Diagnosis evidence、approved Golden 或 route 权限。 Candidate persistence 和 Candidate Trial 的授权只能来自 app diagnosis.yml::contracts 中值严格为 boolean truelearning_candidate_persistence_enabled / learning_candidate_trial_enabled。 运行 payload、options、旧别名或 truthy 字符串/数字都不能授予权限。

同一 episode 的 step6.json 是 replay receipt。文件不存在表示首次执行;文件一旦 存在,就必须是可读 JSON mapping,并带匹配的 episode_keyreplay_complete: true、Diagnosis verdict 和 Campaign control。损坏、缺字段、 episode 冲突或 Projection 无法解析都必须 fail closed,禁止把坏 receipt 当成 “首次运行”而再次搜索、生成或持久化 Candidate。


7.2 应用层负责什么

放在 consumer 仓库:

  • _shared/engines/diagnosis/

只负责:

  • evidence
  • catalog
  • golden positive cases
  • golden counterexamples
  • golden patterns
  • golden learning candidates
  • app-specific diagnosis result families

应用层不再负责:

  • diagnosis engine 主流程
  • route/halt 执行
  • review merge
  • diagnosis.py 真身
  • app 自己的 ai_diagnosis.py
  • result-to-target mapping in owner Python

7.3 Diagnosis + Campaign Sovereignty

Diagnosis + Campaign 是 nexrur 的 fail-to-pivot 主脑,不是 consumer app 内部某个 phase 的 helper。

底座主脑负责:

  • context acquisition through five-bucket evidence
  • evidence bundle construction
  • LLM/root-cause diagnosis
  • independent diagnosis_result.result_code explanation
  • campaign routing handoff by Diagnosis result_code
  • campaign route / halt / restart orchestration

consumer app 只能提供:

  • evidence asset pack: evidence.yml
  • diagnosis asset pack: diagnosis.yml and golden/index.yml plus selected full assets under golden/; legacy targets.yml material belongs under _archived/ only
  • thin Step 6 adapter that gathers subject/run refs and calls substrate diagnosis
  • app-owned business artifacts and local validation artifacts

consumer app 不允许实现:

  • local detector engine
  • _build_candidate_root_causes
  • hardcoded result -> target routing
  • phase-local root cause classifier
  • LLM diagnosis replacement
  • app-local campaign route / halt / restart controller

Step 6 的职责是薄适配:

evidence subject_id / trace_id / current phase refs
  -> call nexrur build_evidence_bundle
  -> call nexrur diagnosis engine with consumer diagnosis assets
  -> receive diagnosis_result
  -> hand off to campaign

Step 6 不得维护大段业务 detector。需要更强 evidence reading 时,优先扩展 substrate five-bucket readers、evidence.yml contract,或 consumer diagnosis asset pack,而不是在 app owner Python 中重写诊断器。


7.4 Phase Boundary For Diagnosis Signals

Phase 1/2/3 evidence wrappers 只能负责:

  • facts
  • digest
  • obligations
  • artifact refs / lineage refs
  • readiness
  • blockers
  • warnings

它们可以给 Diagnosis 提供原材料 refs,但不能替 Diagnosis 加工诊断语义。

禁止在 Step 1/2/3 evidence.py 中加入:

  • upstream semantic diagnosis summary
  • _summarize_curate_business
  • _summarize_dataset_l1
  • _summarize_field_updater
  • _summarize_dataset_l2
  • _build_upstream_diagnosis_context
  • candidate root cause hints
  • Diagnosis result_code -> target suggestion

Phase 4 Production 不得判断 root cause、不得给 campaign route target、不得做 diagnosis summary。但每个 Production leaf/module/subagent 必须能够原样返回自己的 status=partial、事实型 reason_code / failure_kind / errors / warnings 和真实 artifact_refs / evidence_refs。这是 Diagnosis 输入,不是 Production 的路由 裁决。Production 不得把该问题吞掉、包装成 success,或复制上游问题冒充自身 失败。这些 Product 字段一旦返回,后续所有层只能原样转运。

Phase 5 Validation/schema wrappers 只能输出 schema-driven validation facts。 完整命名与禁止边界见 DESIGN_SCHEMA.md

  • validation_passed
  • validation_facts
  • schema_errors
  • diagnosis_ready
  • artifact_refs

Phase 5 不得升级为 diagnosis classifier,也不得把 validation failure 直接解释成 restart dataset_l2curate is weakevidence source too weak 等 campaign target 决策。这些解释属于 Step 6 调用底座 Diagnosis 后的结果。

8. Consumer Diagnosis Asset Pack 标准

Diagnosis 的 app 边界不是 Python 真身,而是标准化资产包。

标准目录(目标态):

_shared/engines/diagnosis/
  evidence.yml
  diagnosis.yml
  golden/
    index.yml
    positivecases/
      <subagent>/
        <module-or-layer>/
          <subagent>-<module-or-layer>-<case-slug>.md
    counterexamples/
      <subagent>/
        <module-or-layer>/
          <subagent>-<module-or-layer>-<case-slug>.md
    patterns/
      <subagent>/
        <module-or-layer>/
          <subagent>-<module-or-layer>-<case-slug>.md
    candidates/
      positivecases/
        <subagent>/
          <module-or-layer>/
            <subagent>-<module-or-layer>-<case-slug>.md
      counterexamples/
        <subagent>/
          <module-or-layer>/
            <subagent>-<module-or-layer>-<case-slug>.md
      patterns/
        <subagent>/
          <module-or-layer>/
            <subagent>-<module-or-layer>-<case-slug>.md
  _archived/
    legacy_classified_markdown/
      patterns/
      examples/
      counterexamples/

8.0 evidence.yml

作用:

  • 定义 Step 6 可消费的 five-bucket evidence truth
  • 声明 required / optional sources、current_scope、upstream_feedback、 digest / obligation views
  • 告诉 production、schema、diagnosis 读取哪些 step artifact 与 envelope

evidence.yml 是证据真相源,不是 diagnosis result catalog。它只说 "证据在哪里、是否必需、如何归入五桶",不解释 root cause,不输出 target。


8.1 diagnosis.yml

作用:

  • 定义本 consumer 支持的 Diagnosis result ontology
  • 解释每个 result_code 的语义、family、severity、evidence gates
  • 明确区分 Product 输入 reason_code 与 Diagnosis 输出 result_code; 二者不共用字段、不做别名、不双写
  • 声明 contradiction guards

diagnosis.yml 不声明 continue / restart / reroute / halt、 recommended_disposition 或 Product status 语义。这些控制规则只属于 campaign.yml

示意:

result_codes:
  - code: L2_FIELD_BINDING_BAD
    description: 字段绑定不合理
    family: business_semantics
    severity: high
  - code: REPORT_DRAFT_USABLE_WITH_REFERENCE_GAPS
    description: 底稿可继续消费,但引用缺口需后台修复
    family: coverage
    severity: medium
  - code: curate_skeleton_invalid
    description: 骨架结构本身不可修
    family: business_semantics
    severity: high
  - code: PLATFORM_NOISE_DIAGNOSTIC_ONLY
    description: 平台噪声,仅用于诊断归档
    family: runtime
    severity: low

8.1.1 Current-Step Scoped Result Catalog

diagnosis.yml may be stored under an app-level shared path such as _shared/engines/diagnosis/, but shared storage is not a global runtime candidate pool. Runtime diagnosis must scope the result catalog by the active orchestrator step before any diagnosis chooser sees the codes.

Default scope is derived from the catalog block name:

current_stepeligible catalog blocks
outlineoutline, mirror, common
paperspapers, extractors, common
reportsreports, qcc, penetration, common

Rules:

  • common is the only global block. It may contain platform-level or cross-step codes, but must not contain step-owned business codes.
  • Step-owned blocks are not globally visible. A papers result code must not be a candidate during an outline diagnosis unless that code explicitly declares a valid current-step override.
  • Optional valid_current_steps on a result code narrows or extends the derived block scope. If present, runtime must intersect it with the current step before exposing the result to diagnosis.
  • Golden index cards and selected full golden assets must expose only related_result_codes that are valid in the same current-step scoped catalog. A golden pattern may be shared across steps, but its out-of-scope related result codes must be hidden from Prompt A/B for the current run.
  • Campaign routing remains in campaign.yml. Diagnosis only decides which scoped result_code is allowed to leave the diagnosis layer.

Failure example that must be rejected:

current_step=outline
diagnosis candidate=PAPERS_EVIDENCE_CONTEXT_MISSING

This is invalid because the papers result is outside the outline-scoped catalog. The run should remain an outline diagnosis failure/blockage until an outline/mirror/common result is supported by evidence.


8.2 Deprecated targets.yml

diagnosis/_archived/targets.yml is deprecated as active executable truth. Diagnosis no longer owns result_code -> target_step / target_subagent / restart / route policy. Runtime loaders must not read or convert the archived sample. It is history-only migration reference and cannot participate in route arbitration.

The replacement split is:

diagnosis.yml             -> result ontology, evidence gates, classification hints
campaign.yml            -> result_code -> lifecycle / disposition / executable target
alphas_campaign.yml     -> run-level budget and execution limits
checkpoint / trace      -> step status, artifact validity, resume facts

Prompt B must not output target_step, target_subagent, campaign_control, or repair_plan as route verdict. If a compatibility envelope still contains these fields, they must be campaign lookup projections, not diagnosis truth.


8.3 Diagnosis result / Campaign lifecycle boundary

Diagnosis-side targets.yml / halt.yml / escalation.yml are not active assets. Diagnosis has exactly one structured classification truth entrypoint: diagnosis.yml.

  • diagnosis.yml 只定义 result_code 的诊断语义和 evidence gates。
  • halt / diagnostic-only / non-retryable / continue-with-repair semantics are written only in campaign.yml.
  • 当前 Product 是否可继续消费,只由 production_result.status 决定;Diagnosis 和 Campaign 不得再做一次当前轮状态判定。
  • 需要后续修复的 result_code 可由 Campaign 映射为 continue_with_repair,但该映射只决定后续行动,不改写当前 Product。
  • repair / retry / stop / escalate / manual_review is decided by Campaign from the validated Diagnosis result_code, Product facts, history, budget facts, settings, and campaign.yml; Diagnosis / LLM does not emit that disposition.
  • executable target projection and fatal runtime guards are written in campaign.yml.
  • budget values are written in run config / CLI, not campaign assets.
  • step status, resume, and artifact validity are checkpoint / trace facts.
  • loader must not continue reading or converting diagnosis-side halt.yml / escalation.yml; archived targets.yml is history-only migration reference.

Campaign side campaign.yml is the target execution boundary contract; see DESIGN_ENGINES_CAMPAIGN.md §10.


8.3.1 External Provider And Authentication Failures

External authentication is an MCP/toolhost runtime concern until its bounded retry policy is exhausted. Diagnosis must not authenticate, refresh provider sessions, or repeat an external call.

The canonical handoff is:

MCP/toolhost bounded auth retry exhausted
  -> leaf emits one stable raw reason_code plus bounded provider failure facts
  -> orchestrator uploads phase_failure_facts
  -> Step6 evidence points to those facts
  -> diagnosis emits an independently namespaced app-catalog result_code
  -> campaign applies halt/no-route policy

Rules:

  • A diagnosis-ready leaf must emit its stable Product reason itself. Orchestrator, evidence obligations, and Diagnosis must preserve that field exactly. Diagnosis may classify it into an independent result_code, but must not translate or replace the Product reason through aliases or error-string guesswork.
  • phase_failure_facts may carry tool name, provider-neutral failure class, bounded status, and redacted message. Credentials, auth headers, cookies, tokens, full provider responses, and retry request payloads are forbidden.
  • A leaf may also emit bounded diagnosis_context facts. Orchestrator preserves them inside phase_failure_facts; Diagnosis and golden assets interpret them. The leaf must not place a repair target or campaign route in that context.
  • An app diagnosis result representing unavailable credentials or exhausted provider authentication should normally receive halt_only handling in campaign.yml unless the app has a genuinely different executable repair target.
  • A provider authentication failure is not production quality failure and must not be routed back to the same production phase merely to try again.
  • MCP retry mechanics and session reset behavior are defined by DESIGN_MCP.md; Diagnosis consumes only the final bounded failure facts.

8.4 Archived patterns/, counterexamples, examples

Root-level patterns/, examples/, and counterexamples/ are retired. If an app keeps them for migration history, they must live under _archived/legacy_classified_markdown/ and must not be loaded as active diagnosis assets.

Active case-grounding knowledge belongs in golden/:

  • golden/positivecases/
  • golden/counterexamples/
  • golden/patterns/
  • golden/candidates/

Case-grounded cognition belongs only to diagnosis golden. Any material currently under campaign/_archived/examples, campaign/_archived/counterexamples, or campaign/_archived/patterns that explains why a diagnosis is right or wrong must move to the corresponding diagnosis golden folder:

Current campaign materialDiagnosis golden target
diagnosis case / positive route rationalegolden/positivecases/
anti-diagnosis guard / tempting wrong explanationgolden/counterexamples/
abstract failure mechanism / reusable semantic patterngolden/patterns/

Campaign does not consume these cognition assets. The pre-LLM selector and Prompt B may consume approved diagnosis golden assets through the golden retrieval chain; Prompt C may automatically write inactive learning candidates under golden/candidates/{positivecases,counterexamples,patterns}/<subagent>/<module-or-layer>/. The substrate default for candidate persistence is opt-in, because nexrur must not write app knowledge for every consumer by default. An app may, however, declare candidate persistence as required app contract. In that case Prompt C is attempted at fail2pivot end-of-episode after the diagnosis result and campaign outcome are resolved. Auto-written candidates remain review queue material only.

The archived markdown is history-only. It cannot override evidence.yml, envelope, diagnosis.yml, campaign route assets, or golden index truth, and it must not be injected into the production diagnosis prompt.


8.5 Golden Library: case-grounded diagnosis knowledge substrate

Golden Library is not a pattern directory. It is the reviewed diagnosis knowledge substrate containing grounded cases, counterexamples, abstract patterns, retrieval index cards, and learning candidates. Patterns are one asset class inside golden, not the whole golden.

Golden exists to make diagnosis case-grounded without moving business judgment into Python. It provides reviewed cognition material for the LLM diagnosis chain; it does not own result ontology, prescriptions, campaign routes, or halt policy.

Canonical app-side physical layout:

.gemini/skills/_shared/engines/diagnosis/golden/
  index.yml
  positivecases/
    <subagent>/
      <module-or-layer>/
        <subagent>-<module-or-layer>-<case-slug>.md
  counterexamples/
    <subagent>/
      <module-or-layer>/
        <subagent>-<module-or-layer>-<case-slug>.md
  patterns/
    <subagent>/
      <module-or-layer>/
        <subagent>-<module-or-layer>-<case-slug>.md
  candidates/
    positivecases/
      <subagent>/
        <module-or-layer>/
          <subagent>-<module-or-layer>-<case-slug>.md
    counterexamples/
      <subagent>/
        <module-or-layer>/
          <subagent>-<module-or-layer>-<case-slug>.md
    patterns/
      <subagent>/
        <module-or-layer>/
          <subagent>-<module-or-layer>-<case-slug>.md

golden/ is already the asset root. Do not add an extra assets/ layer under it. asset_ref values are relative to golden/, for example counterexamples/evaluate-alphas/platform/evaluate-alphas-platform-cache-noise.md. Candidate file names must include the app diagnosis scope slug and module-or-layer names. The diagnosis scope slug is not necessarily the runtime campaign target or skill package name; apps should remove product/runtime prefixes so the convention remains portable across WQ-YI, AGN, AUDIT, and other consumers. For WQ-YI, use curate-knowledge, dataset-explorer, evaluate-alphas, and collect-papers instead of their brain-* runtime package names. dataset-explorer keeps l1, l2, and field_update as module-or-layer values rather than pretending they are separate subagents. Apps may pre-create empty candidate directories for known module-or-layer values; if a VCS placeholder such as .gitkeep is used, it is not a diagnosis asset and must not be loaded.

WQ-YI's current candidate scope scaffold is:

collect-papers/collect
curate-knowledge/skeleton
curate-knowledge/validation
curate-knowledge/fail2pivot
dataset-explorer/l1
dataset-explorer/l2
dataset-explorer/field_update
evaluate-alphas/settings
evaluate-alphas/metrics
evaluate-alphas/platform
evaluate-alphas/fail2pivot

8.5.1 Golden asset classes

ClassPurposeRuntime authority
positive_caseA reviewed episode where a specific evidence combination correctly supported a diagnosis result; stored under golden/positivecases/<subagent>/<module-or-layer>/advisory grounding only
counterexampleA reviewed episode or constructed guard showing why a tempting diagnosis is wrong; stored under golden/counterexamples/<subagent>/<module-or-layer>/advisory guard only
patternAbstract reusable failure mechanism distilled from multiple cases / counterexamples; stored under golden/patterns/<subagent>/<module-or-layer>/advisory reasoning frame only
index_cardLightweight retrieval summary in golden/index.yml used to decide which full assets are worth readingretrieval input only
learning_candidateProposed future golden asset distilled from an episode; auto-written under golden/candidates/<future-class>/<subagent>/<module-or-layer>/ when candidate persistence is enabledinactive until reviewed

Root-level patterns/, examples/, and counterexamples/ are no longer a transitional active surface. They are archived history only; target-state apps must use canonical golden/{positivecases,counterexamples,patterns}/ folders.

8.5.2 Golden index contract

golden/index.yml is a retrieval index, not a route map. An index card should be compact and must help choose full assets without carrying final diagnosis or target decisions.

Minimum index card fields:

id: evaluate-alphas-metrics-low-fitness-alone-is-not-skeleton-invalid
type: counterexample
summary: Low fitness alone is not enough to diagnose skeleton invalid.
trigger_signals:
  - weak simulation result
anti_signals:
  - schema-level skeleton defect
guards_against:
  - overdiagnosing structural failure
related_result_codes:
  - curate_skeleton_invalid
asset_ref: counterexamples/evaluate-alphas/metrics/evaluate-alphas-metrics-low-fitness-alone-is-not-skeleton-invalid.md
review_status: approved

Index cards must not define target_step, target_subagent, campaign_control, repair_plan, or any result_code -> target shortcut. Those remain diagnosis.yml / campaign asset truth; route truth belongs to campaign campaign.yml.routes.

type and asset_ref must agree:

typeCanonical asset_ref prefixActive Prompt B eligibility
positive_casepositivecases/eligible when review_status: approved
counterexamplecounterexamples/eligible when review_status: approved
patternpatterns/eligible when review_status: approved
learning_candidatecandidates/{positivecases,counterexamples,patterns}/never active; review/promote first

Learning candidates should normally stay out of active index.yml. If an app indexes them for review/audit, they must use type: learning_candidate, review_status: proposed, and active_runtime_allowed: false, and the pre-LLM selector must not select them for active Prompt B grounding.

review_status minimum enum:

StatusRuntime meaning
draftauthoring only; not eligible for runtime pre-LLM selector use
proposedlearning / review queue only; not eligible for runtime pre-LLM selector use
approvedeligible for runtime pre-LLM selector use after schema validation
deprecatedretained for audit/history; not selected unless explicitly enabled
rejectedretained only as review history; never selected

Only approved golden assets are eligible for active runtime pre-LLM selector selection by default. draft, proposed, and learning_candidate assets are offline-only. deprecated assets may be cited for audit/history only when an explicit debug/review mode enables them.

8.5.3 Full golden asset contract

A full golden asset may contain the detailed case narrative, evidence signature, why a diagnosis was right or wrong, related patterns, and anti-overgeneralization boundaries. It must include:

  • summary
  • applies_when
  • does_not_apply_when
  • required_evidence
  • contradiction_evidence or equivalent anti-signals
  • related_result_codes
  • source_episode or synthetic case provenance
  • review_status

related_assets is optional. A canonical family card may stand alone after its positive and counterexample evidence has been merged into one full asset. When the field is present, every referenced ID must still resolve to an indexed asset; self-references and synthetic siblings are not required.

Full assets can explain why a diagnosis is plausible or implausible, but they cannot introduce new active result codes. If a full asset needs a result not present in diagnosis.yml, the asset is not runtime-active until catalog / targets coverage is added and schema validation passes.

8.5.4 Prompt chain roles

Diagnosis golden retrieval is cognition, not mechanical business classification. Program code cannot enumerate semantic relevance by hand.

The diagnosis prompt chain is one instance of the broader controlled-LLM contract. It must use the same evidence/evidence substrate as Production and restarted Production, then add diagnosis-specific episode facts:

  • current production artifact and validation envelope;
  • runtime / simulator / toolloop failure facts;
  • upstream feedback and prior campaign handoff facts;
  • selected approved golden assets from the shared golden substrate.

Diagnosis must not create a private evidence world. If evidence is missing or polluted, fix evidence.yml, envelopes, schema validation, or golden assets; do not compensate with Python local arbitration.

phase_failure_facts.reason_code is the canonical leaf failure fact supplied by Orchestrator. context.py must expose that exact value as a diagnosis candidate and use it to scope Prompt A's eligible Golden cards when no explicit reason_candidates list is present. This is transport and selection scoping, not reason normalization: the value must not be renamed, aliased, or translated. If an explicit reason_candidates list is present, it remains authoritative. If the leaf fact and another legacy top-level reason disagree, both remain visible for Diagnosis arbitration rather than one silently replacing the other.

Step 3 obligations are part of that same evidence world. The substrate may assemble an obligation envelope from app-owned declarations, evidence digest refs, and schema validation results, but it must not interpret app-specific obligation semantics in Python. Relation formulas, field-family preferences, fallback policies, weak-pattern bans, required roles, and downstream route meaning belong to the app manifest/schema/assets. A generic build_obligations surface is valid only when it acts as a schema-gated assembler; missing declaration, missing schema, unresolved digest refs, or schema failure must become failed / diagnosis-ready evidence.

Canonical chain:

Program loads schema-valid golden index
  -> Program applies only mechanical gates / budgets
  -> evidence.md::pre_llm_selector reads evidence + eligible index cards
  -> pre_llm_selector selects relevant cases / counterexamples / patterns with reasons
  -> Program loads selected full assets
  -> Prompt B performs grounded diagnosis using evidence + selected full assets
  -> Program validates result_code against catalog / schema
  -> Campaign consumes validated diagnosis_result
  -> Prompt C proposes zero or more learning_candidates after the episode
  -> Candidate persistence may auto-write inactive candidate files when enabled

Allowed program gates before the pre-LLM selector:

  • schema-valid index card
  • review_status: approved for active runtime use
  • hard scope mismatch filtering when a card explicitly belongs to another app or incompatible canonical step family
  • token budget / count budget
  • audit recording for eligible / selected / rejected cards

Forbidden program gates before the pre-LLM selector:

  • business relevance scoring
  • semantic similarity judgment
  • result classification
  • route target selection
  • counterexample priority as a hard-coded route veto
  • app-specific if result -> target logic

The pre-LLM selector owns cognitive retrieval: it decides which eligible index cards are semantically useful for the current evidence and explains why. Program only loads and audits; it does not pretend to know which case is conceptually closest.

Minimum pre-LLM selector output contract:

If evidence.memory_recall is present, Prompt A treats it as historical similar-case context only. It may use recall snippets to notice analogies or avoid repeated confusion, but current-run claims still require current evidence/production/schema/runtime evidence refs.

Minimum Prompt A / pre-LLM selector output contract:

selected_assets:
  - id: evaluate-alphas-metrics-low-fitness-alone-is-not-skeleton-invalid
    type: counterexample
    asset_ref: counterexamples/evaluate-alphas/metrics/evaluate-alphas-metrics-low-fitness-alone-is-not-skeleton-invalid.md
    why_relevant: current evidence shows weak performance without structural defect
    expected_signal: performance symptom without schema/runtime skeleton failure
    confusion_to_avoid: do not classify weak fitness alone as skeleton invalid
rejected_assets:
  - id: platform-cache-permission-error
    why_not_relevant: no platform/cache/permission evidence in current envelope
budget_notes:
  truncated: false
  candidate_count: 12
  selected_count: 2

Pre-LLM selector output is an audit-visible retrieval decision, not a diagnosis. It must explain why each selected index card is relevant, what confusion it helps avoid, and why high-signal rejected cards were not selected. It must not output result_code, reason_code, target_step, target_subagent, campaign_control, or repair_plan.

Runtime predicate compilation must use meaningful values rather than key existence. Empty surfaces such as schema_errors: [], validation_facts: {} or an empty runtime list do not establish a failure signal. Nested bounded facts are first-class: non-empty hard_fail_verdicts and execution_error_distribution inside phase_failure_facts.diagnosis_context must be visible to Prompt A. Mutually exclusive predicates must remain exclusive. In particular, a generic quality label may coexist with a hard provider error, but only_alpha_quality_failed is valid only when no hard runtime/physical execution fact is present.

When the current Step6 packet already carries one explicit leaf reason_code, Prompt A eligibility is mechanically scoped to approved index cards whose input_reason_codes include that code. related_result_codes is relationship metadata only and must never act as an implicit retrieval scope. Cards that need reason-scoped retrieval must declare input_reason_codes explicitly; the substrate must not infer or auto-fill that contract. The program does not choose the winning case or route; Prompt A still performs semantic selection inside the explicitly bounded set. Historical upstream feedback remains context and must not make unrelated cards outrank the current leaf fact.

input_reason_codes belongs to the Product-input namespace. Every value is an exact, producer-owned reason_code copied from a Product leaf or nested Product result. Diagnosis may validate its shape and compare it for exact equality, but must not translate it, normalize it into another semantic code, require it to be a Diagnosis result_code, or add it to the Diagnosis output catalog merely to make Golden retrieval pass. The app-owned Golden index is responsible for declaring which approved cards accept each Product input code. Adding a new Product reason without an eligible Golden mapping is therefore an explicit asset contract gap, not permission to scan all cards or reinterpret the reason.

Every deterministic filter that changes Prompt A eligibility must atomically recompute all three trace fields from the same final list:

eligible_index_cards: []
eligible_card_count: 0
run_prompt_a: false

If reason scoping or any later predicate leaves zero eligible cards, Prompt A is not called. This condition is non-correctable by the model and must be recorded as an explicit golden_no_eligible_cards / asset-contract failure. In golden_chain_mode: required it remains a failed Diagnosis, but the failure must not replace the incoming Product reason_code. A stale pre-filter eligible_card_count or run_prompt_a: true is invalid state.

Golden asset identity is available to Prompt A only through eligible_index_cards[].id and its registered asset_ref. Filesystem paths from the Golden reader are audit/source locations, never candidate IDs and never business evidence. Prompt A must not run with an empty candidate list or derive an asset identity from artifact_refs, evidence_refs, raw paths, filenames, or free text in the evidence packet.

An approved asset may optionally declare diagnosis_result_codes. When Prompt A selects such an asset, Prompt B's eligible catalog results are intersected with that explicit set and its output is mechanically checked against the same set. Every value in diagnosis_result_codes must reference a result_codes catalog entry. Raw Product reasons remain in input_reason_codes; related Diagnosis classifications remain in related_result_codes, but neither may be emitted as the final diagnosis unless it is explicitly present in diagnosis_result_codes. This separates a raw leaf reason used to retrieve an escalation pattern from the root-cause result that the pattern permits Prompt B to produce. Assets that omit diagnosis_result_codes retain the existing advisory behavior. Neither field may contain route targets. Every diagnosis_result_codes / related_result_codes value must exist in the app Diagnosis catalog and current-step scope; producer-owned input_reason_codes are exact-match retrieval inputs and are not required to become Diagnosis output catalog entries. App catalogs must map runtime current_step names to diagnosis blocks through scope.current_steps.<step>.blocks; otherwise scoped golden result metadata is not available to Prompt A/B.

current_step is an execution coordinate, not diagnosis material. Orchestrator must derive the canonical app-level current_step from the recursive graph path before Step6 calls Diagnosis. Local and nested identities remain separate facts in phase, source_phase, failed_phase, phase_path, and target_leaf.

Diagnosis context may validate those coordinates against the app catalog and use phase_patterns only as a scope-consistency predicate inside the already declared current_step. It must not promote a leaf name into current_step, rewrite a non-empty current_step, or infer graph ownership from diagnosis assets. Missing, undeclared, or internally inconsistent coordinates fail closed as an input-contract error and must be repaired at the Orchestrator producer.

When golden_chain_mode: required, Prompt A/B failure or post-LLM catalog gate failure is a failed diagnosis. The public diagnosis facade must not silently replace it with a raw leaf reason candidate as the Diagnosis result; that would bypass the required golden contract and create a false-success route.

The only exception is an app-catalog entry that explicitly declares:

adjudication:
  mode: exact_leaf_fact

This mode is for facts that have already been decided by the owning leaf, such as an exhausted external discovery contract. It is not a semantic root-cause shortcut. The substrate may form a diagnosis suggestion without Prompt A/B only when all of the following are true:

  • the current-step catalog contains exactly one eligible reason candidate;
  • phase_failure_facts.reason_code is identical to that candidate;
  • the entry declares diagnosis_reason: true and source: runtime_phase_fact;
  • the catalog evidence and contradiction gate has passed;
  • the current app-step scope is valid.

Missing opt-in, multiple candidates, a mismatched leaf reason, or a failed evidence gate keeps required Golden fail-closed. Exact-leaf mode preserves the raw reason and produces no target; Campaign remains the only route owner. The substrate must not infer this mode from reason names, error text, lifecycle class, or app identity.

Prompt A may make one bounded output-contract correction after a successful provider call returns model content that cannot be parsed or fails the deterministic selector contract. This means at most two Prompt A model calls in total: the initial call plus one correction call. The correction must carry only the validation errors and the original bounded eligible-card input; it must not widen retrieval scope, add a fallback diagnosis, or call Campaign. If the corrected response still fails, required mode remains fail-closed with an auditable prompt_a_failed result.

This correction is not provider retry. Diagnosis must not catch a generic LLM exception and issue another model call. Transport timeout, authentication, provider unavailability, rate limiting, connection failure, and other execution errors remain owned by the LLM facade's ErrorClassifier, RetryPolicy, and RecoveryLadder. After that owner reports failure, Prompt A fails without an additional diagnosis-level call. Missing/invalid DiagnosisInput, Golden registration failure, and an empty eligible-card set are also non-correctable and must not consume a correction call. Runtime audit must distinguish the initial call, the optional output-contract correction, and provider-internal retry counts. Pre-LLM selector validator/canonicalizer contract:

  • Hard-fail only on verdict/route fields, invalid selected asset identity, unregistered or non-approved assets, unresolved full assets, or non-list selected_assets / rejected_assets shapes.
  • Explanation fields are A-to-B audit hints. They must be canonicalized before Prompt B consumes the trace: relevance_explanation / reason / explanation may fill why_relevant, expected_signals may fill expected_signal, guards_against_confusion / mistake_to_avoid may fill confusion_to_avoid, and scalar budget_notes may become a structured {truncated: false, notes: ...} object.
  • Missing or aliased explanation text must not turn an otherwise valid, resolvable selector asset selection into a Step 6 hard fail. Prompt B receives the canonicalized selector result and the resolved full assets.

Production may use the same reviewed golden substrate, but production retrieval uses the same substrate evidence.md::pre_llm_selector prompt in mode=production. Concrete app subagents/modules own selector profiles and selection goals, not full duplicate selector prompt text.

Production flow:

owner builds production_golden_input
  -> owner/app supplies selector profile and eligible golden cards
  -> substrate runs evidence.md::pre_llm_selector(mode=production)
  -> substrate validates selected/rejected/budget output
  -> substrate resolves selected full golden assets
  -> substrate writes production_evidence.json with embedded evidence core
  -> owner injects selected_golden_context into the existing production prompt

Production selector output must explain generation relevance:

selected_assets:
  - id: string
    type: positive_case | counterexample | pattern
    asset_ref: string
    why_relevant: string
    expected_generation_help: string
    mistake_to_avoid: string
rejected_assets:
  - id: string
    why_not_relevant: string
budget_notes:
  truncated: false

Production selectors are retrieval only. They must not emit result_code, reason_code, target_step, target_subagent, campaign_control, repair_plan, routing_intent, or learning candidates. The existing production prompt remains the business-generation prompt; selected golden assets are advisory grounding, not final diagnosis or route authority. Production selector canonicalizer contract mirrors diagnosis selector: selected asset identity and route/verdict forbiddance are hard contract; explanatory aliases are normalized into why_relevant, expected_generation_help, mistake_to_avoid, and structured budget_notes before owner prompt injection. A valid selected asset must not be dropped merely because the selector used a recognized explanation alias.

Prompt B owns diagnosis reasoning but remains bounded by diagnosis.yml: it may choose only catalog results and cite actual evidence refs. It cannot invent or emit active route semantics. Campaign, not Prompt B, maps result_code to target_step / target_subagent through campaign campaign.yml.routes.

Prompt B must cite selected golden assets explicitly when it uses them:

result_code: L2_FIELD_BINDING_BAD
evidence_refs:
  - evidence://evaluate/step6_evidence/simulation_facts
selected_asset_refs:
  - counterexamples/evaluate-alphas/metrics/evaluate-alphas-metrics-low-fitness-alone-is-not-skeleton-invalid.md
why_selected_assets_matter: selected counterexample prevents overdiagnosing skeleton invalid
why_not_others: weak performance alone did not prove skeleton structure failure

Selected golden assets can support or constrain reasoning, but they are not a result_code allowlist. A card's diagnosis_reason_codes are retrieval and interpretation hints only: they describe reasons previously associated with the case, not reasons that Prompt B is authorized to emit. Final reason authority is owned exclusively by the current App diagnosis.yml catalog, current-step scope, required-evidence gate, and contradiction-evidence gate. Therefore a selected card must not veto another catalog reason whose current evidence gates are closed. Target route must come from campaign assets, primarily campaign.yml.

Prompt C is the mandatory post-episode learning branch when golden learning is enabled. It may return an empty list, but the branch itself must be attempted and audited. Learning candidates are never active in the same run. They must be schema-validated, reviewed, deduplicated, and promoted before becoming golden. When candidate persistence is enabled, Prompt C candidates are auto-written to the inactive candidate queue.

The substrate default is learning_candidate_persistence_enabled: false. This prevents a generic nexrur consumer from accidentally turning runtime episodes into app knowledge. App contracts may override this explicitly. If an app marks golden learning as required, the trigger is fail2pivot end-of-episode:

An app may also declare optional external learning material under contracts.learning_research. This is a provider-neutral contract. Its complete active surface is limited to runtime_binding, evidence_role, llm_profile, search_tool, read_tool, query_budget, result_budget, and timeout; unknown fields fail closed. evidence_role and llm_profile are required when the binding is active. Missing, empty, or malformed values make the learning contract invalid; the substrate must not infer either value from an app name, reason, phase, metric, source type, or installed provider.

learning_research:
  runtime_binding: active
  evidence_role: <app-owned-evidence-role>
  llm_profile: <registered-llm-profile>
  search_tool: <registered-search-tool>
  read_tool: <registered-read-tool>
  query_budget: 3
  result_budget:
    max_search_results_per_query: 8
    max_documents: 5
    max_unit_chars: 4000
    max_total_chars: 20000
  timeout: 60

The branch runs only after baseline diagnosis and provisional Campaign have completed. A bounded planning prompt compares the current failure facts with approved Golden context and decides whether external reading is useful. When it is useful, it emits two or three queries. The declared search tool must return canonical results[].source_id; the read tool must return canonical document.source_id and document.content. Provider-specific fields remain in the app adapter.

baseline diagnosis
  -> provisional Campaign
  -> compare bounded approved Golden context
  -> optional query planning
  -> declared search/read tools
  -> bounded source documents
  -> learning-only semantic synthesis
  -> bounded unreviewed units under the app-declared evidence role
  -> Prompt C only

The app-declared evidence_role is the external DiagnosisInput and provenance identity. The substrate must preserve that exact role when handing off and persisting evidence references. Prompt C does not receive the app-specific name: its bounded context always exposes the selected units as learning_research_units. This normalization prevents Prompt C and substrate code from depending on an app's evidence vocabulary. Both learning LLM calls use the exact declared llm_profile; no fixed Flash/Pro profile, provider name, or legacy use_flash inference is permitted in this branch.

The synthesis LLM may write only research_question, repair_pattern, applicability, and limitations against an exact program-supplied source_id/source_span. The compiler validates those references, assigns the unit identity and source-content hash, and fixes authority to unreviewed_external. It rejects unknown fields instead of repairing them.

Each final app-declared learning-evidence units[] item contains:

source_id: <provider-neutral source identity>
source_span: <exact canonical source span>
research_question: <question addressed by the source>
repair_pattern: <reusable source-grounded pattern>
applicability: <conditions where the pattern may apply>
limitations: <uncertainty and non-applicable conditions>
authority: unreviewed_external

Raw source text is synthesis input only and must not enter Prompt C. Prompt C receives three separate material classes: approved_golden, open_candidates, and the substrate-normalized learning_research_units. These units are not normal Diagnosis evidence, approved Golden, or a route authority. They must never be added to the baseline Diagnosis input, normal Golden retrieval, or evidence gate. Prompt C may use all three classes only to draft [], enrich_existing, or propose_new; it still cannot emit candidate identity, episode identity, fingerprint, evidence refs, reason, route, target, or additional execution-wave authority. Search, read, timeout, normalization, query-planning, or synthesis failure is a learning-side failure: preserve the baseline diagnosis and provisional Campaign outcome, stop Prompt C/candidate/Trial for this episode, and persist only the bounded failed learning receipt needed to prevent replay.

diagnosis_evidence_packet ready
  -> Prompt A/B diagnosis_result ready
  -> campaign outcome resolved
  -> candidate eligibility compiler matches one app learning_candidate_contract
  -> candidate compiler resolves canonical scope and compiles an observed-signal catalog
  -> candidate compiler retrieves bounded same-scope approved/candidate context
  -> Prompt C chooses [] / enrich_existing / propose_new
  -> candidate compiler validates novelty and assigns identity/provenance
  -> only propose_new candidates are persisted

An app-required Prompt C branch may return learning_candidates: []; that is a valid audited outcome. Prompt C failure is a learning-side failure and must not invalidate, rewrite, downgrade, or reroute the already completed diagnosis / campaign outcome.

Prompt C and the candidate compiler have different authority:

ConcernAuthority
whether the episode contains a reusable lessonPrompt C
future asset class and semantic learning boundaryPrompt C
candidate_family_key, candidate_id, fingerprint, scope, episode identity and pathcandidate compiler
evidence provenancecandidate compiler from known episode roles
observed-signal membership and approved/open-family coveragecandidate compiler
review and active-runtime flagscandidate compiler constants
promotion to active Goldenhuman review workflow

Enabling candidate persistence is not permission to learn from every diagnosed episode. The consumer app must additionally declare at least one contracts.learning_candidate_contracts entry. Before Prompt C is called, the substrate compiles eligibility from that declaration and the current bounded diagnosis_facts only:

learning_candidate_contracts:
  - id: reusable-wave-pattern
    fact_role: quality_wave_learning_facts
    required_observed_signals:
      - quality_wave_comparison_ready
      - current_wave_unqualified
    allowed_candidate_types:
      - pattern

An entry is eligible only when its declared fact_role exists as a non-empty value in diagnosis_facts, every required signal was produced by the app's observed_signal_rules, and the allowed candidate-type set is valid. No matching entry means Prompt C is not called and nothing is persisted. Missing, malformed, or ungrounded declarations fail closed; persistence enablement alone must never fall back to an unrestricted learning episode.

The same eligibility contract is enforced again after Prompt C. Every non-empty draft must match one eligible entry: its proposed type must be allowed, its trigger signals must include that entry's required observed signals, and its evidence roles must cite that entry's exact non-empty fact role. Matching scope or reason code is insufficient. This second gate prevents an LLM response from escaping the pre-call eligibility boundary.

Prompt C must not be asked to invent storage identity. The candidate compiler must be conservative:

  • never write active assets;
  • never update golden/index.yml;
  • never make a candidate eligible for normal Prompt A/B retrieval in the same run; an app-enabled one-shot trial may pass one newly persisted candidate through the explicit candidate_trial_context channel defined below;
  • never overwrite an existing candidate path by default;
  • resolve canonical scope from the consumer app contract, not LLM text;
  • reject absolute paths, URLs, filenames and Golden asset paths as episode evidence;
  • compile evidence roles into trace_id + cycle_id + artifact_role refs;
  • compile a bounded observed-signal catalog from structured episode evidence;
  • compile a bounded learning-candidate eligibility contract from the consumer app declaration and non-empty producer-owned facts before invoking Prompt C;
  • require every compiled candidate to match one eligible contract's candidate type, required observed signals, and evidence fact role;
  • require every proposed trigger signal to copy a concrete catalog entry; reason codes, evidence-role names, source phase, and generic failure words do not establish novelty by themselves;
  • derive one candidate_family_key from future asset type, canonical subagent/module scope, and sorted related reason codes;
  • allow at most one open inactive candidate in a candidate family; later episodes must choose enrich_existing or [];
  • skip proposals structurally covered by a relevant approved Golden card;
  • generate deterministic fingerprints and candidate IDs;
  • enforce max_candidates_per_episode: 2 across all invocations sharing the same trace_id + cycle_id + source_phase, not once per invocation.

Prompt C is opportunity-learning, not a fixed production step that emits every asset class on every diagnosis. The default output is an empty list:

learning_candidates: []

Candidate generation gates:

  • emit no candidate when the episode adds no new reusable boundary;
  • emit one candidate when the episode has a clear high-value learning signal;
  • emit two candidates only when the same episode contains two distinct lessons;
  • do not emit three candidates just to cover positive case, counterexample, and pattern buckets;
  • cap output at max_candidates_per_episode: 2 unless a future contract explicitly raises the budget.

Candidate class selection:

Proposed asset typeUse whenDo not use when
positive_casethe diagnosis / route has a strong closed-loop confirmation, such as later convergence, accepted campaign action, or human confirmationthe episode only has an unverified diagnosis
counterexamplethe episode exposes a tempting but wrong diagnosis and has explicit contradiction evidencethere is no concrete wrong interpretation to guard against
patternthe episode reveals a reusable judgment pattern, success pattern, failure pattern, or boundary signal that can generalize beyond one runthe lesson is only a one-off story with no reusable signal shape

Selection priority is:

clear misdiagnosis guard -> counterexample
reusable judgment pattern -> pattern
closed-loop proof that this diagnosis was right -> positive_case

Prompt C must compare the completed Prompt B diagnosis and Campaign decision with verified post-episode feedback. Explicit human review, repeated same-route/no-progress campaign history, and later verified evidence are learning facts: they cannot rewrite the completed diagnosis or route, but they can prove that the episode should propose a counterexample. A candidate that only restates or extends the selected approved asset without citing a new evidence boundary is not useful learning and must be omitted. When contradiction evidence disproves the tempting diagnosis or route, the candidate should cite those refs and use contrasts_with for the misleading related asset. When post_episode_feedback.contradiction_evidence_refs is present, a proposed counterexample must cite every declared contradiction ref or fail candidate validation. The observed episode itself must satisfy the candidate's generalization_boundary; verified episode facts must not be moved into anti_signals or anti_overgeneralization. If an upstream surface reports zero/empty while later verification finds usable source data, the lesson is a stale discovery/materialization boundary, not actual source exhaustion.

Before this comparison, the substrate must provide a bounded set of relevant approved Golden cards and inactive candidates. Retrieval is scoped first by the app-declared canonical source scope, then by reason codes and normalized trigger/anti signals. It must not send the entire approved index to Prompt C. The comparison context also contains the program-compiled observed-signal catalog. Prompt C may only copy concrete trigger labels from that catalog. The compiler must not treat reason-code values, failure-kind values, phase names, status values, tool names, or evidence-role keys as observed novelty. Those values only identify the diagnosis episode. A reusable trigger must be either an exact producer-declared trigger_signals item or the ID of a matched contracts.observed_signal_rules rule. The compiler must not walk arbitrary fact roles, inspect numeric signs, parse error prose, or synthesize labels from field names. Purpose, current scope, selector state, artifact references and handoff metadata remain comparison context rather than reusable failure signals.

App-specific facts enter Diagnosis only through app-declared evidence/catalog contracts. The substrate does not reserve a fact role, infer an episode kind, or add a special Prompt C output contract. Trace, asset, candidate, field and revision IDs are identity, not observed novelty signals. Prompt C should center any proposal on the most specific declared observed signal. A title or summary that only restates the current reason code and Campaign route is not a reusable lesson and should result in []. Empty remains correct for transient, unverified, covered, or non-reusable facts. Conversely, an uncovered concrete leaf that establishes a reusable distinction between diagnosis classes or repair actions should normally produce one proposal. The current Campaign outcome is an observed controller decision, not proof that the selected target repaired the failure or that the target phase owns a missing business product. Without explicit verified post-episode feedback, Prompt C must describe only the evidence boundary. The draft validator rejects positive prose that names the current Campaign target, even when the target is described as a producer or repair owner rather than as a restart action. This gate is compiled from the episode target; it must not hard-code app step names. More generally, an episode without post_episode_feedback.repair_outcome_verified: true cannot establish a repair prescription. Its candidate may capture a diagnosis boundary, but positive prose must not prescribe that a layer should/must restart, rerun, rebuild, generate, relax, route, or otherwise fix the product. why_worth_reviewing explains the value of the distinction, not an unverified solution. Prompt C canonicalization may omit existing_candidate_ref: null only for propose_new, where the field is contractually absent. It must not repair a missing enrich_existing reference or synthesize any semantic field. If a structured leaf error should become reusable learning input, the producer must expose a stable trigger signal or the app must declare a path rule for that fact. Diagnosis must not normalize the leading error token or infer business meaning from parameter text. Prompt C must not upgrade a missing binding/reference/input/handoff into source data unavailability or exhaustion without explicit episode evidence. The candidate should preserve the observed contract boundary and route distinction. For missing-binding episodes, the admissible fact is “the current handoff lacks the required binding.” Without verified post-episode repair evidence, a candidate must not prescribe inspection/rebuild of the Campaign target or claim the field was not produced. “Producer gap”, “field-generation gap”, and “field not produced” are unsupported without an explicit producer fact. Related asset IDs must be copied from supplied context. Observed leaf IDs and catalog reason codes remain separate namespaces: triggers come from observed_signal_catalog. Prompt C must not emit a reason code. The candidate compiler copies related_reason_codes from the completed Prompt B diagnosis and writes the same canonical codes into the persisted index-card draft. This keeps diagnosis ontology out of the learning LLM's output surface.

Candidate similarity has three deterministic layers:

  1. an approved-card coverage gate rejects lessons already represented by active Golden;
  2. a candidate-family gate prevents multiple open proposals for the same future type, canonical scope, and reason-code family;
  3. exact fingerprint matching rejects the same structural signal boundary.

Free-form title, summary, generalization_boundary, and anti_overgeneralization text cannot create a new identity or bypass these gates.

Prompt C outcomes have these meanings:

OutcomePersistence behavior
learning_candidates: []no new reusable lesson; write nothing
enrich_existingreport the matched candidate and enrichment suggestion in learning audit; do not overwrite
propose_newcompile identity/provenance and persist only if all gates pass

These are Prompt C's only actions. An empty list is the no-op action; each non-empty semantic draft must choose exactly enrich_existing or propose_new. Prompt C must not emit candidate IDs, storage locators, source scope, episode identity, diagnosis reasons, Campaign routes, or permission for another repair/quality wave. Those values are either compiler-owned or outside the learning side path entirely.

fail2pivot may receive this bounded feedback through the generic episode_feedback payload. The substrate copies it into Prompt C's episode_context.post_episode_feedback only after baseline Prompt B and a provisional Campaign outcome have finished. The feedback channel remains learning-only. It cannot directly rewrite Prompt B, Campaign, checkpoint state, or the active Golden index. When the consumer app explicitly enables one-shot candidate trial, one newly persisted candidate may be supplied to one fresh Prompt A/B diagnosis as bounded trial context. Only that standard diagnosis may produce a different app-declared result code; Campaign still routes solely from the final diagnosis result. Consumer-specific diagnosis result/route semantics remain owned by consumer assets.

pattern is not limited to failures. It may describe a successful convergence shape, a healthy-module signal, a failure mechanism, or a boundary rule.

Prompt C does not contain episode-specific candidate-type rules. It may return [], enrich_existing, or propose_new under the common candidate draft schema. Candidate type and semantic content are assessed from app evidence and normal Golden contracts, not from substrate predicates for a named workflow.

Minimum Prompt C semantic-draft contract:

learning_candidates:
  - decision: propose_new  # propose_new | enrich_existing
    proposed_asset_type: counterexample
    title: Zero qualified alone is not L2 physical failure
    summary: A candidate guard against overdiagnosing physical execution.
    why_new: observed confusion not covered by approved assets
    why_worth_reviewing: repeated failure mode with clear evidence boundary
    evidence_roles:
      - phase_failure_facts
      - diagnosis_facts
    related_assets:
      - id: evaluate-alphas-metrics-low-fitness-alone-is-not-skeleton-invalid
        relation: contrasts_with
    proposed_index_card:
      summary: Zero qualified alone is not L2 physical failure.
      trigger_signals:
        - zero qualified with executed simulations
      anti_signals:
        - tool execution failure
      guards_against:
        - confusing low performance with runtime failure
    generalization_boundary: applies only when platform/runtime errors are absent
    anti_overgeneralization: do not use this to suppress true schema failures
    existing_candidate_ref: ''  # required only for enrich_existing

The persisted candidate is a compiled artifact. The compiler adds:

candidate_fingerprint: sha256-of-canonical-learning-boundary
candidate_id: lc-<fingerprint-prefix>
candidate_family_key: sha256-of-type-scope-and-reason-codes
related_reason_codes:  # compiler copies exact Prompt B result codes
  - L2_FIELD_BINDING_BAD
source_scope:
  subagent: <app-declared canonical slug>
  module_or_layer: <app-declared canonical module>
  phase: <failed source phase>
source_episode:
  episode_key: trace-...:cycle-0001:<failed source phase>
  trace_id: trace-...
  cycle_id: cycle-0001
  source_phase: <failed source phase>
evidence_refs:
  - trace_id: trace-...
    cycle_id: cycle-0001
    artifact_role: phase_failure_facts
review_status: proposed
active_runtime_allowed: false

source_episode is valid only for a real runtime episode. An app may import a review candidate from a versioned historical experiment record, but it must not invent a nexrur trace or cycle. A persisted candidate therefore carries exactly one compiler-owned provenance form: source_episode or source_record.

source_record:
  record_key: sha256-of-canonical-source-record
  source_kind: historical_experiment_log
  source_ref: tools_ai/example/tracking/experiment_log.md
  source_sha256: <sha256 of the exact imported file version>
  record_id: batch-08
  line_start: 176
  line_end: 185
  source_span_sha256: <sha256 of the exact bounded line span>
  subject_refs:
    - kind: alpha_id
      id: <external platform identity>
evidence_refs:
  - source_record_key: <same record_key>
    artifact_role: historical_experiment_record

The historical-record compiler must reject absolute paths, parent traversal, missing or mismatched hashes, an end line before the start line, a record ID that is absent from the bounded span, and external subject IDs that are absent from that span. It derives record_key from the normalized app-relative source reference, file hash, record ID, line interval, span hash, and sorted subject references. Display prose and array order do not participate in identity.

Historical imports use the same inactive candidate queue, duplicate/family gates, review flags, and no-route boundary as runtime Prompt C candidates. They are not newly persisted by the current fail2pivot episode and are therefore never eligible for the same-episode one-shot Diagnosis Trial. They may affect runtime diagnosis only after human review, promotion into an approved Golden asset, and index registration.

Historical material must pass through a factual compilation boundary before an LLM can summarize it. The app may declare contracts.historical_learning_import with runtime_binding: review_only, bounded record/table/text budgets, and one or more app-relative source records. The substrate implementation is source-neutral: it knows Markdown headings, tables, fenced blocks, labeled numeric facts, hashes, and line spans, but it does not know Alpha metrics, Batch semantics, or app lesson names.

For a selected heading, the compiler closes the record at the next heading of the same or higher level. It may retain only the heading, declared table cells, enabled fenced blocks, and numeric tokens from app-declared labels. It must not copy ordinary prose or author-written hypotheses, decisions, lessons, attributions, or next-step recommendations. A record with no retained factual block fails closed instead of sending narrative text to the LLM.

The compiled unit contains source_record, a deterministic fact_unit_id, a hash of the canonical factual payload, and the bounded factual payload itself. The LLM may later infer a transferable pattern by comparing units, but it cannot change source identity, line bounds, source hashes, subject references, or raw facts. Factual compilation does not write a Candidate and does not invoke Diagnosis Trial.

An app may separately declare a review-only historical Candidate plan. The plan binds each proposal to explicit fact-unit selectors, a primary source_record, canonical source_scope, catalog reason codes, allowed future asset types, and a stable factual trigger. These are compiler inputs, not Prompt C output. The app may also deny selected record-heading prefixes when an incident belongs to deterministic Product Validation rather than Golden learning.

The plan may include a review question that focuses Prompt C on a comparison. It is an instruction, not evidence: it cannot override the compiled records, and insufficient facts still require an empty result.

Historical Prompt C reuses the normal semantic draft schema and its only three outcomes: [], enrich_existing, or propose_new. It runs once per declared proposal over bounded fact units and the normal approved/open comparison set. Unlike an unverified runtime episode, a historical review may describe a bounded practice suggested by recorded comparisons. This does not relax the ban on diagnosis reasons, Campaign routes, restart targets, active promotion, or claims of universal/unique causality. The compiler owns candidate family, fingerprint, ID, scope, provenance, evidence refs and filename; persistence uses the existing inactive queue and duplicate/family gates. Historical Candidates never receive source_episode, never enter same-episode Trial, and never change Diagnosis or Campaign output.

Prompt C output containing compiler-owned identity, path, source scope, episode identity, diagnosis reason, route, activation flags, wave authorization, or absolute evidence paths must fail the draft contract. The compiler must not silently accept those values.

The candidate path is derived mechanically from proposed_asset_type, the app-declared canonical source_scope, and the compiler-generated candidate ID:

golden/candidates/
  positivecases/
    <subagent>/
      <module-or-layer>/
        <subagent>-<module-or-layer>-<case-slug>.md
  counterexamples/
    <subagent>/
      <module-or-layer>/
        <subagent>-<module-or-layer>-<case-slug>.md
  patterns/
    <subagent>/
      <module-or-layer>/
        <subagent>-<module-or-layer>-<case-slug>.md

proposed_asset_type: positive_case maps to the positivecases/ candidate bucket. counterexample maps to counterexamples/; pattern maps to patterns/. The file stem must include the same <subagent> and <module-or-layer> values used in the directory path.

Consumer apps own the allowed scope set. For example, an app may declare that Evaluate candidates are limited to evaluate-alphas/metrics and evaluate-alphas/settings. The compiler resolves that scope from the app's current-step, failed-phase, and selected Prompt B reason-family mapping. Prompt C cannot emit or override it. If no mapping matches, compilation fails closed; the substrate must not invent a platform, fail2pivot, or catch-all scope.

Candidate compilation and persistence remain separate deterministic stages. Compilation owns episode identity, family/fingerprint, candidate ID, filename, structured evidence references, approved-card coverage, open-family and exact duplicate gates. Persistence revalidates all compiled identities, writes only inactive golden/candidates/ artifacts with exclusive create, and never updates the active Golden index. Replaying the same episode and semantic boundary must produce a duplicate/open-family skip and zero new files; it must not overwrite the existing candidate or create a new trial identity.

Candidate family is computed from canonical JSON containing future asset type, canonical subagent/module scope, and sorted related reason codes. Candidate fingerprint adds normalized trigger, anti, and guard signals to that family. Neither identity may include title, summary, free-form generalization prose, source episode, filename, path, phase, or array order.

enrich_existing never updates a candidate file automatically. It is an audit suggestion for the review workflow. An exact fingerprint duplicate is skipped regardless of the Prompt C title or proposed filename.

Prompt C failure must be reported as a learning-side failure. It must not invalidate, rewrite, or downgrade the baseline diagnosis. If candidate trial is enabled but Prompt C, compilation, persistence, or the trial diagnosis fails, fail2pivot must publish the baseline diagnosis and its Campaign route.

8.5.5 One-shot inactive candidate trial

An inactive learning candidate may participate in one real repair attempt without becoming active Golden truth. This is an explicit diagnosis replay, not automatic promotion and not a second routing engine.

The execution order is:

baseline Prompt A/B diagnosis
  -> provisional Campaign outcome (Prompt C context only; do not publish)
  -> same-episode Step6 receipt lookup
  -> app-declared learning-research eligibility gate
  -> optional Forum Learning declared by the app contract
  -> Prompt C semantic draft
  -> candidate compile and inactive persistence
  -> one-shot trial eligibility gate
  -> fresh Prompt A/B diagnosis with candidate_trial_context
  -> final Campaign outcome from the selected diagnosis result

Forum Learning, Prompt C persistence, and Trial share the canonical episode identity trace_id + cycle_id + source_phase. Their bounded completion receipt is stored in the existing cycle step6.json; no process-local cache or parallel learning state file is allowed. A replay of the same episode must load and validate that receipt before eligibility compilation, search, read, Prompt C, persistence, or Trial. A valid receipt suppresses all six operations, so replay cannot repeat the learning gate, external research, candidate write, or one-shot Trial.

The receipt may persist grounded learning units together with their app-declared evidence_role, declared llm_profile, source hashes, candidate persistence refs, Trial key, and baseline/final result codes. It must not persist raw forum text, raw prompts, candidate prose, credentials, or active Golden content. A receipt without an exact episode key or explicit replay_complete: true is not reusable.

When a prior Trial was applied, replay may reuse its final diagnosis verdict only if the current app catalog still registers that result code for the same step and the current required/contradiction evidence gate still passes. Otherwise replay keeps the fresh baseline diagnosis. It must never call the candidate again to repair a stale receipt.

Only a candidate newly written by the current persistence call is eligible. learning_candidates: [], enrich_existing, approved-coverage skips, open-family skips, duplicate skips, and persistence failures do not start a trial. The trial gate also requires:

  • exact trace_id + cycle_id + source_phase provenance;
  • one candidate only;
  • a valid canonical source scope;
  • no candidate-authored reason code, target step, route, or activation flag;
  • an app contract that explicitly enables candidate trial;
  • no prior trial for the same trial identity.

The explicit app permission is contracts.learning_candidate_trial_enabled: true in the consumer diagnosis catalog. learning_candidate_persistence_enabled grants only inactive storage; it must not implicitly grant Trial. Runtime payloads may not enable Trial when the consumer catalog does not. An app that omits the Trial flag therefore still persists eligible candidates, but fail2pivot publishes the baseline diagnosis without replaying Prompt A/B.

Trial identity is program-owned:

candidate_trial_key = hash(
  candidate_family_key
  + subject_id
  + product_revision_id
)

product_revision_id is the failed product revision that the repair will supersede, such as a skeleton revision or another app-declared stable revision. The key is attempt identity, not candidate identity and not Golden identity. Title, summary, path, array position, trace ID, and cycle ID do not participate.

The second diagnosis receives two explicit bounded inputs:

candidate_trial_context:
  candidate_id: <compiler-owned ID>
  candidate_family_key: <compiler-owned family>
  summary: <bounded candidate diagnosis distinction>
  why_worth_reviewing: <bounded learning value>
  trigger_signals: []
  anti_signals: []
  generalization_boundary: ""
  anti_overgeneralization: ""
  source_episode: {}
  trial_only: true

upstream_contract_snapshot:
  producer_contract: {}
  current_product_revision: {}
  downstream_failure_facts: {}

context.py prepares and bounds these materials. It does not decide a root cause, result code, or target. Prompt A/B may select only result codes already declared by the consumer diagnosis catalog, and the normal evidence gate must pass. The candidate may sharpen a distinction, but it cannot supply the answer or bypass contradiction evidence.

The trial must preserve the candidate's bounded semantic distinction, not only its trigger labels. summary, why_worth_reviewing, and anti_overgeneralization are candidate-authored hypotheses and remain untrusted; they cannot carry routes or become evidence. Prompt B compares that hypothesis against all three snapshot sections: producer contract, current product revision, and downstream failure facts. The raw leaf reason is an observed symptom during Trial, not a preselected root cause. Prompt B must re-evaluate which contract layer owns the failure and then choose only an evidence-eligible app-catalog reason.

During this explicit Trial, the upstream snapshot is current contract evidence, not optional historical context. Prompt A's selected active Golden may explain only the leaf symptom. Prompt B may reject that asset for root-cause ownership, leave selected_asset_refs empty, and choose another eligible catalog reason when the candidate hypothesis plus snapshot explains the downstream failure more completely.

For Trial only, catalog_constraints must include bounded semantic contracts for every evidence-eligible reason: code, family, description, rendering hints, and prefer/defer hints. A bare list of reason-code strings is insufficient for cross-layer rejudgment because the model cannot recover app-owned responsibility boundaries from names alone. These contracts contain no Campaign target or route and do not relax the existing evidence or contradiction gates.

fail2pivot owns the composition order and failure policy:

  • baseline diagnosis and provisional Campaign are computed first;
  • the same-episode receipt is checked before learning eligibility;
  • not_eligible skips Forum Learning but may continue Prompt C with the existing approved/open materials;
  • an invalid eligibility contract stops the learning side path and preserves the baseline diagnosis;
  • Forum Learning failure stops the learning side path for this episode and preserves the baseline diagnosis;
  • Prompt C and candidate compilation remain learning-side operations;
  • the trial diagnosis is attempted at most once;
  • a valid trial diagnosis becomes the final diagnosis;
  • any trial-side failure publishes the baseline diagnosis;
  • a same-episode replay reuses the Step6 receipt and does not rerun Forum Learning, Prompt C, persistence, or Trial;
  • an existing unreadable, incomplete, or identity-conflicting receipt fails the StepSix handoff; it is never treated as a missing receipt or a first run;
  • Campaign is generated from the final diagnosis exactly once for external handoff.

Joint mock acceptance must keep the learning side path independent from the baseline diagnosis result:

CaseRequired result
result code is outside the app allowlistnot_eligible; no Forum call
one or more required observed signals are absentnot_eligible; no Forum call
one approved Golden card covers every required signalapproved_golden_covered; no Forum call; Prompt C may still use approved/open materials
eligibility is valid and approved Golden does not cover the signal setForum Learning may run within the declared budgets
Forum planning, search, read, or synthesis failsstop the learning side path and publish the baseline diagnosis/Campaign result
same-episode receipt is validskip eligibility, Forum, Prompt C, persistence, and Trial
same-episode receipt exists but is invalidfail closed; do not rerun learning or persistence

The focused acceptance suite must also scan active Diagnosis and Fail2pivot sources for app-owned reason-code literals. App result codes belong only to app catalogs and test fixtures; the substrate may compare declared values but must not branch on a built-in app reason.

Trial can choose only an existing, evidence-eligible diagnosis-catalog reason. It cannot mutate Campaign assets or retry policy and cannot emit route, target, repair-count, or retry authority. Any additional attempt must be authorized by app-owned diagnosis, Campaign, and execution-policy contracts; candidate prose, persistence, or Trial success cannot grant that authority.

The final Step6 envelope may report bounded audit metadata such as candidate ID, trial key, baseline result code, final result code, and whether the trial was applied or skipped. It must not inline candidate prose, raw prompts, or active Golden files. A successful real repair is evidence for later human promotion; it does not auto-promote the candidate.

8.5.6 Golden boundaries

Golden must never:

  • replace evidence.yml as evidence truth;
  • replace diagnosis.yml as result ontology;
  • replace campaign campaign.yml.routes as route truth;
  • replace campaign assets as halt / restart / escalation execution truth;
  • become an app-local Python detector engine;
  • auto-promote runtime failure stories into active prompt assets.

Golden may:

  • ground diagnosis in reviewed prior episodes;
  • prevent tempting but unsupported overdiagnosis;
  • supply abstraction patterns and counterexamples to Prompt B;
  • propose learning candidates for future asset evolution.
  • auto-write inactive Prompt C candidate files when candidate persistence is enabled, without activating them.
  • supply one newly persisted inactive candidate to the explicit one-shot trial channel when the consumer app enables it, without adding that candidate to normal Prompt A/B retrieval.

In short:

cases/counterexamples provide groundedness;
patterns provide abstraction;
index cards provide retrieval;
learning candidates provide controlled evolution.

8.5.7 Contract sample layout

src/nexrur/engines/contracts/diagnosis/golden/ should mirror the canonical shape as a developer-facing contract sample:

src/nexrur/engines/contracts/diagnosis/golden/
  README.md
  index.example.yml
  positivecases/
    <subagent>/
      <module-or-layer>/
        example.md
  counterexamples/
    <subagent>/
      <module-or-layer>/
        example.md
  patterns/
    <subagent>/
      <module-or-layer>/
        example.md
  candidates/
    positivecases/
      <subagent>/
        <module-or-layer>/
          example.md
    counterexamples/
      <subagent>/
        <module-or-layer>/
          example.md
    patterns/
      <subagent>/
        <module-or-layer>/
          example.md

This contracts tree is documentation and fixture material only. It is not a production diagnosis asset pack and must not be loaded as app truth. Production truth comes from the app-owned diagnosis asset root registered by payload / overlay, such as .gemini/skills/_shared/engines/diagnosis/golden/.


8.6 Asset Pack 是 Schema-Validated Contract

§8.0–§8.5 描述的 asset 是 substrate-validated executable contract / classified advisory asset,不是散文配置。它们由 diagnosis contract / app schema pack 登记,由 substrate loader / builder 在加载阶段做 per-file schema 与 cross-file validation。

Golden obligations apply when an app registers golden assets in diagnosis contract / app schema pack. Apps without registered golden assets remain valid, but cannot enable the selector / Prompt B / Prompt C golden chain. In other words:

  • feature absent: no golden loader hard fail; diagnosis can still run with evidence.yml, diagnosis.yml, and classified advisory assets;
  • feature present but invalid: registered golden assets fail schema / cross-file validation at load time;
  • feature present but no approved assets: the pre-LLM selector receives no active golden index cards and must report that no approved golden knowledge was available.

详细 schema governance 规则见 docs/DESIGN_SCHEMA.md §11。本节只声明 diagnosis pack 必须遵守的硬约束。

8.6.1 Per-File Schema Obligations (diagnosis pack)

AssetRequired structural obligations
evidence.ymlfive-bucket 来源声明完备;path / kind / required 字段齐全;bucket 落在 substrate 已知 bucket 枚举
diagnosis.ymlresult_code 必须有 family / severity / 描述 / evidence gates;无重复;命名落在 enum 规范;不得含 disposition / route / Product status
_archived/targets.ymlhistory-only migration reference;不得作为 active route truth;不得覆盖 campaign routing
_archived/legacy_classified_markdown/retired root-level patterns/examples/counterexamples;history-only;不得进入 active selector / Prompt B / Prompt C 或 production diagnosis prompt
golden/index.ymlindex card 必须有 id / type / summary / trigger_signals / anti_signals / related_result_codes / asset_ref / review_status;不得含 route verdict;asset_ref 相对 golden/
golden/positivecases/<subagent>/<module-or-layer>/*.mdapproved 正例 full assets;必须有 applies_when / does_not_apply_when / evidence boundary / provenance / review_status;不得含 route verdict
golden/counterexamples/<subagent>/<module-or-layer>/*.mdapproved 反例 / guard full assets;必须有 applies_when / does_not_apply_when / required_evidence / contradiction_evidence / provenance / review_status;不得含 route verdict
golden/patterns/<subagent>/<module-or-layer>/*.mdapproved 抽象 pattern full assets;必须有适用边界 / 反适用边界 / evidence signature / provenance / review_status;不得含 route verdict
golden/candidates/{positivecases,counterexamples,patterns}/<subagent>/<module-or-layer>/*.mdPrompt C 自动候选落点;必须 review_status: proposedactive_runtime_allowed: false;不进入 active selector / Prompt B,除非人工 review/promote 后迁入三类正式 folder 并同步 index

8.6.2 Cross-File Validation Obligations

Cross-checkRule
evidence ↔ five-bucketbucket / kind 必须在 substrate 已知枚举
catalog ↔ campaign route boundary每个可输出 result_code 必须在 campaign.yml 有明确 handling;route、continue_with_repair、halt 或 diagnostic-only 都是 Campaign truth
campaign lifecycle无 executable route 的 result_code 必须在 campaign.yml 显式标记 no_action / halt_only / diagnostic_only
campaign escalation/halt ↔ catalogescalation / halt 引用的 result_code 必须在 catalog 存在
campaign routing ↔ step enumtarget_step / target_subagent 必须在 substrate legal step / subagent 词表
classified knowledge ↔ catalog/evidencepattern/example/counterexample 的分类必须可映射到 known step / failure family / evidence signature
golden index ↔ full assetsindex asset_ref 必须存在;full asset id / type 必须与 index 一致
golden ↔ catalogrelated result_code 必须在 catalog 存在;golden 不得引入裸 result_code

8.6.3 Naked Result Code 禁令

Naked result_code = diagnosis.yml 声明了可输出 result_code, 但 campaign.yml 既没有 executable route,也没有显式 no_action / halt_only / diagnostic_only handling。

Naked result_code 必须在 substrate loader / builder 阶段 hard fail,不允许 拖到 longrun 阶段才被 campaign 拒绝。app 一旦在 diagnosis.yml 引入新 result_code,必须同步在 campaign.yml 登记 route 或显式的 no_action / halt_only / diagnostic_only handling。

底座责任: loader 检测到 naked result_code 立即拒绝加载,不允许 fallback "unknown result"。 app 责任: 修补 diagnosis catalog 或 campaign asset YAML,不允许在 owner / schema wrapper / Prompt B 中本地补 result_code → target_step 表(详见 §7.3 Sovereignty 与 DESIGN_SCHEMA.md §11.8)。

8.6.4 失败语义

时机行为
Load 阶段 schema 违反substrate loader hard fail
Load 阶段 cross-file 不一致substrate builder hard fail
Runtime 期 diagnosis 输出未登记 result_codesubstrate diagnosis hard fail,不 fallback unknown
Runtime 期 naked result_code (未被 §8.6.2 在 load 阶段拦截)视为 substrate contract 漏洞,提工单修 loader,不在 app 端兜底

9. Diagnosis 与 ToolLoop / Campaign / Orchestrator 的关系

9.1 ToolLoop

ToolLoop 是局部探索器。Diagnosis 是全证据解释器。

  • ToolLoop 负责:

    • 工具选择
    • 局部探索
    • 局部汇总
  • Diagnosis 负责:

    • 解释全链路失败
    • 融合五桶 evidence
    • 产出 diagnosis_result

所以 ToolLoop 不是 Diagnosis 的替代,而是 Diagnosis 的局部感官之一。


9.2 Campaign

Campaign 是总控器。Diagnosis 是总控器的解释器。

  • Campaign 负责:

    • budget
    • loop
    • route
    • halt
    • final decision
  • Diagnosis 负责:

    • 原因分析
    • result_code 诊断分类
    • evidence-based explanation
    • 为 Campaign 提供 triage 输入

所以:

Campaign 可以调用 Diagnosis,但不能把总控权交给 Diagnosis。


9.3 Orchestrator

Orchestrator 是执行壳,不是病理学家。

  • Orchestrator 负责执行拓扑
  • Diagnosis 负责解释为什么某条路径失效

二者关系是:

  • Orchestrator 提供运行事实
  • Diagnosis 解释运行事实

Orchestrator 还是 Diagnosis 执行坐标的唯一生产者:

  • current_step:当前 leaf 所属的 app-level step;
  • phase_path:从 app step 到 nested graph 的声明路径;
  • phase / failed_phase:实际执行或失败的 local leaf;
  • phase_failure_facts:leaf 明确输出后由 Orchestrator 有界转运的运行事实。
  • phase_failure_facts.diagnosis_facts:leaf 生产、app contract 解释的 opaque 业务事实容器;Orchestrator 只做 bounded copy。

其中 phase_failure_facts.reason_code 必须作为原始 leaf candidate 进入 DiagnosisInput 和 Prompt A 作用域;context.py 只能复制、去重和限界,不能 翻译该值。这样 nested leaf 的失败不会因为 Step6 packet 顶层 reason_code 为空而退化成全局 Golden 卡片扫描。

Diagnosis 不得根据 phase_patterns、reason code、错误文本或 artifact 路径重新 解析这组坐标。坐标错误属于 Orchestrator/input contract failure,不属于 Diagnosis 的根因推理任务。

9.4 boundary.py / context.py / diagnosis.py Implementation Boundary

src/nexrur/engines/diagnosis/boundary.py 只定义声明合同并读取底座 Schema。材料读取、 Prompt 渲染、evidence fingerprint 与结果生成均不得放入该文件。

src/nexrur/engines/diagnosis/context.py 只负责准备材料。

输入:

  • Step6 的 bounded facts 与 Orchestrator 执行坐标;
  • consumer diagnosis.yml / evidence assets;
  • approved Golden index/full assets;
  • Prompt 资产与历史 feedback refs。

输出:

  • 经过选择、正规化、去重和体积控制的 DiagnosisInput
  • Prompt A/B/C 所需的 bounded context、eligible catalog facts、episode/scope、 approved/inactive comparison 和验证约束;
  • 已校验的 inactive candidate records;读取失败必须作为显式 contract error 返回。

context.py 不得:

  • 决定 primary diagnosis candidate;
  • 输出最终 diagnosis_result.result_code
  • 输出或改写任何 Product reason_code
  • 把 raw leaf reason 翻译成另一个 app reason;
  • 修补或重解释 current_step / phase_path
  • 生成 target_steptarget_subagent、restart、halt 或 route。
  • 调用 Prompt A/B/C、解释 LLM 输出、编译/持久化新 candidate 或执行 Trial。

context.py 必须保留 DiagnosisInput.evidence.diagnosis_facts 的 bounded shape, 供 app diagnosis.yml 与 Prompt 资产消费;它不得把容器内 role 提升为底座字段, 也不得在 Python 中内置任何 app role、path、threshold 或 signal 名称。

Diagnosis runtime assets 必须由调用方显式传入 DiagnosisAssets 或精确的 diagnosis_assets_root。底座不得读取 CWD、父目录、环境变量或进程级缓存来猜当前 App,也不得从 knowledge_root、evidence payload 或其他相邻目录补出 Diagnosis 路径。 缺少或无法加载显式资产时,Diagnosis input contract 必须 fail closed。

Campaign CLI 也属于调用方。App CLI contract 必须用 contracts.diagnosis: <exact-assets-root> 显式绑定;命令行可用 --diagnosis-assets 做本次覆盖。nexrur 不再用固定 .gemini/.../diagnosis 目录作为默认值。

候选故障只允许来自两个 active envelope:显式 reason_candidates[],或单一 phase_failure_facts.reason_code。两者都只做原样、bounded 的机械正规化。底座不得 递归扫描 validation_artifactsschema_artifactssimulation_artifactsruntime_artifactslocal_artifacts 等旧容器找 reason_code,不得从顶层 reason_code / first_problem 猜候选,也不得按 brain- 等 App 命名约定修剪 scope。

Flash / Pro 使用的 ToolLoop profile 由 App 的 diagnosis.yml 显式声明:

contracts:
  diagnosis_llm_profiles:
    flash: <registered-profile>
    pro: <registered-profile>

两个 profile 都必须是非空精确值;缺失、未知字段或空值均 fail closed。底座只把该 值原样交给 ToolLoop,不按 model 名、provider 名、flash / pro 字样或 use_flash 推断 Gemini、DeepSeek 或任何 provider。

diagnosis_suggestion 只公开 result_code、confidence、evidence、解释、bounded repair constraints 与 metadata;不得公开 target_stepsuggested_escalation_targetdiagnosis_actions。这些字段即使为空也不是合法的 Diagnosis Product。Campaign 必须仅凭 App route contract 和已验证的 Diagnosis result_code 形成执行目标。

App 可以在 diagnosis.ymlcontracts.observed_signal_rules 声明可审计规则:

contracts:
  observed_signal_rules:
    - id: <app-owned-stable-signal-id>
      fact_role: <exact-key-under-diagnosis_facts>
      path: <dotted-path-inside-that-role>
      operator: eq
      value: <app-owned-value>

底座只提供通用规则执行器:按 fact_role 选择 opaque facts,按 path 读取值, 执行白名单 operator,并在匹配时输出规则自身的 id。首批通用 operator 为 eqneexistsnot_existsgtgteltltecontainsin。规则 ID、role、path 和比较值的业务含义全部归 App;底座不得根据 scope、 字段名、错误文本或数值正负自行合成 observed signal。缺失 path、非法 operator、 无效比较值或不兼容类型必须 fail closed:该规则不匹配,且不得退回文本猜测。

Prompt A/B/C 只能消费 observed_signals 与原始 bounded evidence。旧的 diagnosis_focus 属于 WQ Evaluate/Simulator 专属摘要,必须退出 active Diagnosis; 底座不得再组织 simulation、qualified、slot、pyramid、L2 或 alpha quality 摘要。

src/nexrur/engines/diagnosis/diagnosis.py 才负责执行 Prompt A/B/C、校验模型 输出、在 app catalog 允许范围内分类并形成唯一 diagnosis_result.result_code。它必须同时保持输入中的 Product status/reason/reason_code 不变,不得把诊断分类写回 Product。 Prompt A/B 没有运行、没有合法候选或执行失败时,Diagnosis 只能在自身 execution_status / errors 中报告失败;不得制造一个 Diagnosis 分类来代替 Product reason,也不得把 diagnosis_unavailableprompt_a_failed 等底座执行码 写进 Product reason_code。 它仍不得执行 route。campaign.py 只消费这个 Diagnosis result, 并依据 app-owned campaign.yml 决定后续 cycle 的 continue / restart / reroute / halt;这个决定不得改写当前 cycle Product。

diagnosis.py 只能通过 context.py 的显式公开 material-preparation API 消费准备结果, 不得导入 context 私有 helper。旧的 rag 参数和执行期临时 memory 检索接口退场; memory/cognition/cross-domain 必须在 DiagnosisInput 形成前显式准备并随输入传入。

9.5 2026-07-20 Rejected Implementation

本次错误实施的现象是:Step6 收到的非空 current_step 实际为 local leaf dataset_l2_fail2pivot,而不是 app-level step。错误修法是在 context.py 中读取 phase_patternssource_phasephasefailed_phase,再把该 leaf 猜回一个 app step。

该修法被否决,原因是:

  1. 它掩盖了 Orchestrator 写错执行坐标的上游 contract defect;
  2. 它让 Diagnosis 长出第二套 nested graph resolver;
  3. 它让 diagnosis catalog 反向决定执行身份,破坏 contracts ownership;
  4. 同名、模糊或未来新增 leaf 会产生静默重解释,可能把错误送入错误 catalog;
  5. context.py 从材料准备层越权成为 reason scope 与 graph identity 决策层。

正确修复是:Orchestrator 从真实递归 graph stack 写入唯一 app-level current_step,同时原样保留 local phase / failed_phase / phase_pathcontext.py 对缺失或冲突坐标 fail closed;diagnosis.py 只基于合法 DiagnosisInput 产生 Diagnosis result;Campaign 再执行路由。不得保留旧推断作为 compatibility fallback。


10. 与五桶 evidence 的关系

Diagnosis 不是一个封闭 engines 模块,而是系统级消费者。


10.1 与 core

Diagnosis 必须吃:

  • 失败步骤证据
  • Validation (schema-driven) report
  • outcome
  • audit/evidence ledger
  • schema/policy/runtime contract refs

如果 Diagnosis 不吃 core evidence,它就是盲诊。


10.2 与 engines

Diagnosis 必须吃 bounded engines facts:

  • orchestrator checkpoint index
  • campaign control state
  • toolloop event index
  • LLM/tool usage refs
  • phase failure / timeout / provider error short facts

否则 Diagnosis 无法区分业务失败、执行失败和状态连续性失败。完整 checkpoint、 events、tool output、prompt、provider response 只能作为 refs,不能进入 diagnosis prompt。


10.3 与 aiskills

Diagnosis 必须吃:

  • app business artifacts
  • production verdict / bounded summary
  • schema validation projection
  • diagnosis / Step6 active projection
  • upstream/downstream business refs

否则 Diagnosis 无法解释 app 业务语义是否漂移。


10.4 与 memory

Diagnosis 必须吃:

  • contentstore / vectorstore bounded retrieved units
  • app-declared historical raw material refs
  • previous product / derived artifact recall
  • transferable lessons or cross-domain lessons after store retrieval

否则 Diagnosis 只能看“发生了什么”,不能看“过去哪里失败过、哪些跨域经验可迁移”。 Memory 不能替代当前事实,也不能直接触发 route / halt。


10.5 与 golden

Diagnosis 必须吃 approved golden grounding:

  • positive cases
  • counterexamples
  • patterns
  • index cards selected by pre-LLM selector

否则 Diagnosis 只能自由发挥,无法受历史正反例约束。Golden 不含 route truth; 它只约束 Prompt B/C 的解释边界。


11. 标准数据流

Five-bucket evidence bundle
  + core / engines / aiskills / memory / golden refs
  + consumer diagnosis assets
        │
        ▼
  nexrur.engines.diagnosis
        │
        ├─ load app diagnosis asset pack
        ├─ normalize Step6 evidence envelope
        ├─ match catalog + selected approved golden cognition
        └─ produce diagnosis_result
        │
        ▼
diagnosis_result
        │
        ▼
campaign consumes diagnosis_result
        │
        ▼
campaign_control decides continue / continue_with_repair / reroute / halt

continue_with_repair 是 Campaign 对后续行动的控制结果,不是 Diagnosis 对当前 Product 的二次状态判定。当前 Product 能否继续 由 producer 已经返回的 status 决定;Campaign 只登记后续 repair / rerun target。Production、Diagnosis 和 Campaign 的原始结果必须分层进入 Step6、checkpoint、active 和 Admin 事实面,不得互相覆盖。


12. 文件归属与目录设计

12.1 nexrur active 目录

src/nexrur/engines/diagnosis/
  __init__.py
  boundary.py
  context.py
  diagnosis.py
  schemas/
    _schema_index.yml
    nexrur_diagnosis_flash_assessment.yml
    nexrur_diagnosis_pro_assessment.yml
    nexrur_diagnosis_golden_asset_selection.yml
    nexrur_diagnosis_golden_diagnosis_verdict.yml
    nexrur_diagnosis_golden_candidate_draft.yml
    nexrur_diagnosis_golden_candidate.yml
    nexrur_diagnosis_candidate_trial_handoff.yml
    nexrur_diagnosis_upstream_contract_snapshot.yml
    nexrur_diagnosis_suggestion.yml

src/nexrur/prompts/
  diagnosis.md

schemas/_schema_index.yml 是 Diagnosis logical role 到 schema file 的唯一 active mapping truth;其余 schema files 是结构合同。目录命名沿用 Evidence 与 Projection 的 稳定格式:

nexrur_<engine>_<stable-role-or-artifact>.yml

因此文件名描述长期稳定的角色或产物,不描述当前实现顺序。禁止使用 prompt_a.ymlprompt_b.ymlprompt_c.ymlstep_1.yml 之类流程字母或步骤号 命名;Prompt 顺序可以演进,但 golden_asset_selectiongolden_diagnosis_verdictgolden_candidate_draft 等合同角色必须保持稳定。

12.2 Schema 职责清单

Schema结构职责当前 Python 迁移来源
nexrur_diagnosis_flash_assessment.ymlFlash 初判输出 shapeboundary.py 声明 role 并通过 core Schema 读取
nexrur_diagnosis_pro_assessment.ymlPro 复核输出 shapeboundary.py 声明 role 并通过 core Schema 读取
nexrur_diagnosis_golden_asset_selection.ymlGolden 资产选择结果;对应当前 Prompt A 角色boundary.py 声明 role;context.py 准备输入,diagnosis.py 校验输出
nexrur_diagnosis_golden_diagnosis_verdict.ymlGolden-grounded Diagnosis verdict;对应当前 Prompt B 角色boundary.py 声明 role;context.py 准备输入,diagnosis.py 校验输出
nexrur_diagnosis_golden_candidate_draft.ymlPrompt C 只可生成的语义草稿与 [] / enrich_existing / propose_new 决策diagnosis.py 的 Prompt C 输出校验;context.py 只准备输入材料
nexrur_diagnosis_golden_candidate.ymlCandidate compiler 编译后的 inactive persisted candidatediagnosis.py 的 compiler/persistence;context.py 只负责 fail-closed queue read
nexrur_diagnosis_candidate_trial_handoff.yml本 episode 新候选进入一次性 Diagnosis Trial 的 bounded handoffdiagnosis.py 的 Trial handoff compiler;context.py 只准备显式 episode identity
nexrur_diagnosis_upstream_contract_snapshot.ymlTrial 使用的 bounded upstream contract snapshotdiagnosis.py 的 snapshot section/shape 检查
nexrur_diagnosis_suggestion.ymlDiagnosis 对 Campaign 公开的结构化 Product;不含 route/controldiagnosis.py 的最终 suggestion/result shape

必须明确区分:

  • golden_candidate_draft 是 LLM 的无身份语义草稿;
  • golden_candidate 是程序分配 identity、scope、fingerprint、evidence refs 后的 inactive candidate;
  • candidate_trial_handoff 是一次性试用通道,不是 approved Golden,也不进入普通 Golden retrieval;
  • diagnosis_suggestion 是 Diagnosis Product,不得携带 target_steptarget_subagent、restart、halt 或 Campaign route。

12.3 加载与消费规则

Diagnosis schema 使用与 Evidence/Projection 相同的 JSON-Schema-like YAML 形状: typerequiredpropertiesitemsenum 等。实现对齐时遵守:

  1. schemas/_schema_index.yml 只登记稳定 logical role 到 schema file 的映射;
  2. nexrur.core.schema 是唯一 YAML loader、schema definition checker 和递归 validator;
  3. boundary.py 可以缓存通过 core schema 加载的 schema,并提供 enum/required/ properties introspection,但不得读取 YAML、保存 role-to-filename 字典或实现私有 validator;
  4. context.py 只消费已加载合同来准备、裁剪和验证材料,不复制 required/allowed 字段常量;
  5. diagnosis.py 只消费已验证结构执行 Diagnosis,并形成最终 Product,不维护第二份 schema dict;
  6. schema index/mapping/file 缺失、YAML 无法解析、根节点不是 mapping、合同自身不完整时, Diagnosis 执行失败,不得退回内联 Python schema;
  7. schema logical role 由底座固定,不允许 app payload 覆盖 index 或任意文件路径;
  8. 不新增 Diagnosis-local schema helper 模块;公共能力继续收敛在 core/schema.py

12.4 Schema 与 Policy 边界

应迁入 YAML 的只有可机械验证的结构事实:

  • required / optional 字段;
  • object / array / string / number / boolean 类型;
  • 稳定枚举;
  • nested object shape;
  • LLM 草稿、编译产物、Trial handoff、最终 Product 的字段边界。

不得迁入 Diagnosis schema:

  • app result_code 的业务含义与 catalog evidence gate;
  • reason 选择、置信度解释和 Golden 语义判断;
  • candidate fingerprint、episode limit、近似检索和去重算法;
  • candidate scope 到物理目录的映射;
  • cross-wave applicability、改善/退化的业务解释;
  • Campaign route、repair budget、restart、halt、replacement trace;
  • 任何 WQ-YI、AUDIT 或其他 app-specific reason/phase/target 值。

底座 schema 可以要求 result_code 是非空字符串,但合法值仍必须在 consumer diagnosis.yml 中声明并由 catalog gate 校验;不能把 app 枚举复制进底座 schema。 同理,schema 可以禁止 route 字段,却不能决定 route。

12.5 去重与迁移完成条件

YAML 生效后,Python 中对应的内联结构定义必须删除,禁止“YAML 校验一次、Python 常量再校验一次”的双真相。语义算法可以保留,但只能读取 schema 校验后的结构。

迁移完成必须满足:

  • 五个 boundary.py 内联 LLM output schema 已删除;
  • context.py 中只表达结构的 draft/candidate/trial 字段集合已删除或由 schema 派生;
  • diagnosis.py 中只表达结构的 Trial/snapshot/output 字段集合已删除或由 schema 派生;
  • 缺失、损坏、不完整 index/mapping/schema 的 focused tests 均 fail closed;
  • Flash、Pro、Prompt A/B/C、candidate compile、Trial 和最终 suggestion 的既有行为测试 继续通过;
  • context.py 仍不决定 reason,diagnosis.py 仍不执行 Campaign route。

迁移完成后,active Diagnosis Python 不再直接调用 yaml.safe_load 读取自己的 schemas, 也不再出现 DIAGNOSIS_SCHEMA_FILES 或第二套 _validate_json_schema_properties 实现。只创建 YAML/index 而未删除私有 loader/validator 不算完成。

12.6 consumer(WQ-YI / AGV / AUDIT)

_shared/engines/diagnosis/
  evidence.yml
  diagnosis.yml
  golden/
    index.yml
    positivecases/
      <subagent>/<module-or-layer>/
    counterexamples/
      <subagent>/<module-or-layer>/
    patterns/
      <subagent>/<module-or-layer>/
    candidates/
      positivecases/<subagent>/<module-or-layer>/
      counterexamples/<subagent>/<module-or-layer>/
      patterns/<subagent>/<module-or-layer>/
  _archived/
    legacy_classified_markdown/

12.7 兼容期遗留

_shared/engines/modules/diagnosis/

仅可作为:

  • legacy import compatibility subtree

不得再作为:

  • diagnosis 主实现目录
  • prompt 真身目录
  • knowledge 真身目录

13. 为什么不能让 app 继续长 diagnosis engine

如果 app 继续拥有自己的:

  • toolloop_diagnosis.py
  • skill_diagnosis.py
  • ai_diagnosis.py
  • 各种 detector Python 主逻辑

那么结果一定是:

  1. 底座失去统一智能主脑
  2. 每个 app 各长一套 diagnosis
  3. cross_domain / cognition / evidence / memory 永远接不成统一闭环
  4. nexrur 再次沦为半吊子 runtime substrate

所以 app 的边界必须像 Claude Code 的 skill 体系一样窄:

只允许交标准化资产,不允许再长 agent 主脑。


14. 与 Cross-Domain / Cognition 的统一关系

Diagnosis 不只是 consumer asset pack 的消费者,它是五桶 evidence 的统一解释层:

  • core
  • engines
  • aiskills
  • memory
  • golden
  • consumer diagnosis assets

其中 cognition、调用方显式准备的 memory lessons、crossdomain lessons 都归入 memory bucket,而不是独立决策层。Diagnosis 不持有 RAG 执行接口。

14.1 Cross-Domain 是 memory bucket 的经验迁移输入

Cross-domain knowledge 不是独立 feature,也不直接触发 reroute。它必须先成为 memory bucket evidence,再由 Diagnosis 解释。

14.2 Cognition 是 memory bucket 的认知输入

Cognition 不是 AUDIT 独有 feature,它是 Diagnosis 的:

  • 上下游认知契约输入
  • trace-local semantic evidence

14.3 统一结论

Cross-Domain 与 Cognition 都应被视为 memory bucket 中的 evidence,而不是并列的小 feature,更不能绕过 Diagnosis/Campaign 直接改 lifecycle 或 route。


15. Diagnosis Input Ownership

Diagnosis 输入不是单一 ownership。它至少分成 app-owned evidence、substrate-owned mechanism、asset-pack truth 三个 ownership 面:

输入层ownership内容作用跨 app 语义
raw evidence payloadapp-ownedstep outcome、gate report、simulation summary、skill output、domain metrics解释当前 app / 当前 trace / 当前资产发生了什么顶层 evidence envelope 可通用,payload 解释不保证跨 app 成立
local cognitionapp-ownedbrief、validation、trace-local reasoning、current pipeline-local lessons解释当前 app / trace / asset 的上下文和认知偏差不保证跨 app 成立
crossdomain lessonssubstrate-owned bridge mechanics + app-owned physical storagepromoted transferable lessons、reusable patterns、cross-app guidance给多个 app 的 diagnosis 提供可迁移 grounding应尽量跨 app 成立

硬规则:

原始 evidence payload 的解释权归 app。原始 cognition 一律 app-owned;可迁移的 crossdomain lessons 由 substrate bridge mechanics 生成,但物理落盘在当前 app 的 runtime support root。底座可以拥有提升/检索机制,但不自动拥有内容语义。

15.1 Local cognition

Local cognition 指:

  • brief
  • validation
  • trace-local reasoning
  • current pipeline-local lessons
  • 当前 app 对某个资产 / trace / run 的上下文解释

它回答的是:

  • 当前 app 认为自己在做什么?
  • 当前 trace 上下文里,哪些判断已经被上游或下游确认?
  • 当前资产为什么进入这个 repair / route / halt 分支?

它的 ownership 是 app-owned,原因是:

  • 它通常包含 app step vocabulary。
  • 它通常依赖 app asset schema。
  • 它通常依赖 app diagnosis / campaign contract 的业务解释。
  • 它不保证离开当前 app 后仍可正确解释。

因此,local cognition 可以被底座 diagnosis 消费,但不能被底座当成生产语义真值。

15.2 Crossdomain lessons

Crossdomain lessons 指被明确提升为 transferable 的经验:

  • reusable failure pattern
  • transferable repair lesson
  • cross-app guidance
  • 经过归一化的结构相似性结论

它的 bridge mechanics 是 substrate-owned,物理存储是 app-owned,原因是:

  • 它已经从 app-local payload 中抽象出来,需要底座提供通用提升和检索机制。
  • 它的目标是服务多个 app。
  • 它不能继续依赖某个 app 私有字段才能解释。
  • 它仍是由当前 app 运行触发产生的运行产物,不应串写进另一个 app 或 nexrur 仓的 docs/ai-runs

进入 crossdomain layer 的前提是 promotion,而不是简单复制:

app local cognition / evidence
        │
        │ normalize + abstract + promote
        ▼
substrate crossdomain lesson

没有 promotion 的原始 cognition 仍然归 app。


16. Diagnosis And Multi-App Execution

跨 app subagent 调用不改变 local cognition ownership。

核心规则:

subagent 来源 app 不等于 local cognition ownership。ownership 取决于它服务哪个 trace,以及内容是 trace-local 认知还是 transferable shared lesson。

16.1 触发 trace 的 app 拥有 local cognition

如果某个 trace 由 AGV 触发,即使它调用了 AUDIT 或 WQ-YI 的 subagent:

  • AGV 拥有该 trace 的 local cognition。
  • AUDIT / WQ-YI subagent 只是在该 trace 内提供执行能力或 app-specific skill 输出。
  • 这些输出进入 AGV trace 的 local evidence / cognition 时,不自动变成 AUDIT / WQ-YI owned cognition。

16.2 底座拥有 cross-app shared lesson layer

只有当 trace-local 内容被归一化并提升为 transferable lesson 时,才进入 substrate crossdomain layer。

例如:

  • AGV agv-asset-oracle 调 AUDIT 审计 subagent。
  • AUDIT subagent 产生的原始审计解释服务 AGV trace,因此 local cognition 归 AGV。
  • 如果其中某个 failure pattern 被抽象成可迁移 lesson,才进入 substrate crossdomain layer。

再例如:

  • AGV agv-mm-arv 调 WQ-YI curate / dataset subagent。
  • WQ-YI subagent 产出的 raw skeleton / dataset binding 解释服务 AGV trace,因此原始 local cognition 仍归 AGV。
  • 只有跨 app 可复用的“curate failure pattern”或“dataset binding failure pattern”经过 promotion 后,才归 substrate crossdomain。

16.3 不允许的误判

禁止:

  • 因 subagent 来自 WQ-YI,就把 AGV trace 的 local cognition 归 WQ-YI。
  • 因文件写在 nexrur/docs/ai-runs,就把 app evidence payload 解释权归底座。
  • 因 lesson 被底座存储,就把未归一化 app-local 语义当成 substrate truth。

17. ai-runs Ownership Model

ai-runs 不是单一语义 root。它同时承载:

  • substrate runtime state
  • substrate runtime support stores
  • app-owned business run artifacts
  • mixed / transitional runtime containers

runroot.py 已退场;路径 ownership 必须由各 writer/engine owner 显式解析,不能再恢复成一个全局 resolve_runs_root()

17.1 Ownership table

目录族物理位置ownership原因
.engines/.orchestrator/nexrur/docs/ai-runssubstrate-owned纯 runtime checkpoint / trace state;step_order 等值来自 app contract,但 checkpoint 外壳归底座
.memory/vectorstore/current app docs/ai-runsapp-owned runtime support with substrate mechanics可由 Diagnosis 上游准备 memory lessons;Diagnosis 自身不打开或查询该索引
.memory/contentstore/current app docs/ai-runsapp-owned runtime support with substrate mechanicsContentStore index/cache 在 app 内共享,不承接其他 app 的业务内容
.core/.audit/<trace_id>/<cycle_id>/audit.jsonlapp local audit root under app docs/ai-runsapp-owned observability stream with substrate envelopeaudit envelope 可通用;WQ 等 app 的业务 audit 不写入 nexrur 仓,trace/cycle 是主寻址维度
.migration-*nexrur/docs/ai-runssubstrate-owned audit/support迁移审计与冲突记录,不是 app 生产资产
.llm/.usage/<profile>/<run_id>.jsonlcurrent app docs/ai-runsprovider-neutral usage ledger with substrate envelopeusage accounting 主通道;summary / hotspots / diagnostics 只消费 provider-neutral usage helpers
.gemini-usage/ / gemini_usage.jsonldeprecated compatibility onlylegacy Gemini-only explicit audit仅当显式配置 AI_AUDIT_JSONL 时用于历史 Gemini 诊断;新代码不得默认写入或扫描
evidence-papers/<run-id>/app business runs root,当前可能暂在 nexrur/docs/ai-runsapp-owned run artifactWQ evidence 业务语义强绑定;manifest/outcome 外壳可通用,内容解释归 app
curate-knowledge/<run-id>/app business runs root,当前可能暂在 nexrur/docs/ai-runsapp-owned run artifactWQ skeleton / idea packet / curate semantics 强绑定
dataset-explorer/<run-id>/app business runs root,当前可能暂在 nexrur/docs/ai-runsapp-owned run artifactWQ field binding / pyramid / slot semantics 强绑定
evaluate-alphas/<run-id>/app business runs root,当前可能暂在 nexrur/docs/ai-runsapp-owned run artifactWQ simulation / gate / alpha metrics semantics 强绑定
datafield-updater/<run-id>/app business runs root,当前可能暂在 nexrur/docs/ai-runsapp-owned run artifactWQ dataset knowledge/category snapshot 强绑定
.golden/.cognition/app golden cognition rootapp-ownedbrief / validation / trace-local reasoning 不保证跨 app 成立
.memory/local/app local memory rootapp-ownedapp-local lessons / trace-local lessons 归 app
.golden/.crossdomain/current app docs/ai-runsapp-owned storage with substrate bridge mechanicspromoted transferable lessons 由底座机制提升,物理记录留在当前 app
.engines/.campaign/nexrur/docs/ai-runssubstrate runtime承载 campaign runtime state;不承载 app semantic summary

17.2 Substrate-owned

以下目录归底座:

nexrur/docs/ai-runs/.engines/.orchestrator/
nexrur/docs/ai-runs/.migration-*

它们的共同点:

  • 保存 runtime state 或 runtime support data。
  • 外壳可以跨 app 复用。
  • app label 可以出现在 payload 中,但不改变设施 ownership。

17.3 App-owned

以下目录归 app:

WQ-YI/docs/ai-skills/**
WQ-YI/docs/ai-runs/evidence-papers/<run-id>/
WQ-YI/docs/ai-runs/curate-knowledge/<run-id>/
WQ-YI/docs/ai-runs/dataset-explorer/<run-id>/
WQ-YI/docs/ai-runs/evaluate-alphas/<run-id>/
WQ-YI/docs/ai-runs/datafield-updater/<run-id>/
WQ-YI/docs/ai-runs/.core/.audit/**
WQ-YI/docs/ai-runs/.golden/.cognition/**
WQ-YI/docs/ai-runs/.memory/vectorstore/**
WQ-YI/docs/ai-runs/.memory/contentstore/**
WQ-YI/docs/ai-runs/.memory/local/**
WQ-YI/docs/ai-runs/.golden/.crossdomain/**

硬规则:

step run artifacts 的语义 ownership 属于 app,即使当前物理位置暂在 substrate root。

底座可以定义 manifest.json / outcome.json 的通用外壳,但不能拥有:

  • WQ reason_code 的业务解释。
  • WQ metrics 的业务含义。
  • WQ artifact_id / skeleton_id / alpha_id 的领域含义。
  • WQ gate / simulation / field binding / curate semantics。

17.4 Shared / Transitional

.engines/.campaign/ 是 active campaign runtime root。

允许短期保留在:

nexrur/docs/ai-runs/.engines/.campaign/

但它的目标状态是:

  • 只保留 campaign runtime state。
  • 不再承载 app semantic summary 真值。
  • app summary / matrix / budget interpretation 应通过 app contract 或 app-owned business runs 表达。

.golden/.crossdomain/ 的 bridge mechanics 归 substrate,但物理落盘归当前 app golden support layer。

它只能接收经过 promotion 的 transferable lessons,不能直接吞 app-local cognition。

17.5 诊断读取规则

Diagnosis 读取这些目录时必须遵循:

  • 读取 .engines/.orchestrator/:获得 trace/checkpoint runtime facts。
  • 读取 .engines/.campaign/:获得 campaign runtime state;app semantic summary 不在这里持久化。
  • 读取 app step run dirs:获得 app business run artifacts;通用 manifest/outcome 外壳可由底座解释,业务字段由 app 解释。
  • 读取 .memory/local/:获得 app-local lessons。
  • 读取 .golden/.crossdomain/:获得当前 app 通过 substrate bridge mechanics 提升的 transferable lessons。

18. Retired runroot Constraints

resolve_runs_root() / runroot.py 已退场,不应作为 V2 active 语义入口恢复。

未来如确需重新引入部署级 root override,只能设计 owner-specific contract,不能恢复全局 root router。最低限度应区分:

resolve_business_assets_root()
resolve_business_runs_root()
resolve_runtime_state_root()
resolve_runtime_support_root()

进一步拆分时,应提供:

resolve_runtime_audit_root()
resolve_runtime_cache_root()
resolve_runtime_checkpoint_root()
resolve_local_evidence_root()
resolve_local_cognition_root()
resolve_local_memory_root()
resolve_crossdomain_root()

硬规则:

  • resolve_business_runs_root() 指向 app-owned business run artifacts。
  • resolve_runtime_state_root() 指向 substrate-owned runtime state,例如 .engines/.orchestrator/.engines/.campaign/
  • resolve_runtime_support_root() 对业务 app 指向 app-owned .memory/vectorstore/.memory/contentstore/ 等 runtime support 设施;LLM usage 由 nexrur.llm.usage 写入 .llm/.usage/
  • resolve_runtime_audit_root() 对业务 app 指向 app-owned .core/.audit/<trace_id>/<cycle_id>/audit.jsonl 根,不承接 WQ 业务 audit 到 nexrur 仓。
  • resolve_local_evidence_root()resolve_local_cognition_root() 指向 app-owned diagnosis input。
  • resolve_crossdomain_root() 指向 app-owned .golden/.crossdomain/ 物理存储;bridge mechanics 仍归 substrate。

后续重构不允许:

  • 用单一 runs_root 同时表达 app business output、runtime checkpoint、audit cache、local cognition、crossdomain lesson。
  • 因目录当前物理位置在 nexrur/docs/ai-runs 就改变内容 ownership。
  • 把 app evidence/cognition payload 升格为底座 truth。

19. 迁移路线

Phase 1

  • diagnosis.py 成为 substrate diagnosis shell
  • consumer diagnosis asset pack 标准化

Phase 2

  • Step 6 输入统一为五桶 evidence envelope
  • app owner 不再自行维护 result-to-target Python mapping

Phase 3

  • campaign.py 消费 diagnosis_result 并返回 campaign_control
  • reroute 一律从目标 subagent phase 1 重启

Phase 4

  • 清退 _shared/engines/modules/diagnosis/ 与 app-local diagnosis engine 真身
  • legacy compatibility shim 只保留在明确退场条件下

20. 完成定义

Diagnosis Substrate 完成时,必须满足:

  1. diagnosis.py 是唯一 diagnosis engine shell
  2. app 只提供标准化 diagnosis asset pack
  3. Diagnosis 统一消费五桶 evidence + consumer diagnosis assets
  4. Campaign / Orchestrator / ToolLoop 不再各自长隐性 diagnosis 真脑或 route mapping
  5. _shared/engines/modules/diagnosis/ 被清退或只剩极薄兼容壳
  6. no Step 7 repair;所有 reroute 都由 campaign 控制并从 target subagent phase 1 重启
  7. Product status/reason/reason_code 在 Diagnosis 前后完全一致
  8. Diagnosis 只输出 diagnosis_result.result_code,不存在 diagnosis_result.reason_code 兼容别名
  9. Diagnosis / Step6 / Campaign 不得把 valid Product partial 就地升级为 stop

21. 反模式与禁止事项

禁止

  1. app 自己再新增 ai_diagnosis.py
  2. app 在 diagnosis 边界下继续长 Python 主逻辑
  3. 让 cross_domain 直接触发 reroute,而不进入五桶 evidence
  4. 让 cognition 只停留在上游 artifact,而不进入 diagnosis 输入
  5. 让 campaign/toolloop 各自偷偷长 diagnosis intelligence
  6. 把底座 diagnosis 再次塞满 consumer 专属业务语义
  7. 在 diagnosis 后新增 Step 7 repair 或 middle-phase hot repair
  8. 在 app evidence.py / Step 1/2/3 中加工 diagnosis semantic summary
  9. 在 app Step 4 production / Step 5 schema wrapper / simulator loop 中判断 root cause 或 campaign target
  10. 在 app owner Python 中硬编码 reason -> target routing truth
  11. 用 app-local detector engine 代替 diagnosis engine + consumer diagnosis asset pack
  12. Diagnosis 通过忽略 Production partial 实现假放行
  13. Step6 / Orchestrator Python 按 app reason code 硬编码 non-blocking
  14. continue_with_repair 输出成 no-action / success,丢失修复事实
  15. context.py 根据 leaf 名、phase_patterns 或错误文本修补/重解释 current_step
  16. context.py 选择 primary diagnosis、输出最终 result_code 或生成 route
  17. Diagnosis 输出 reason_code,或用任何别名兼容双写 Product reason
  18. Diagnosis 输出 governance_class / recommended_disposition 重建 Product 的 pass / partial / stop 状态机
  19. Step6 将 diagnosis_result.result_code 提升为自身、child graph 或 parent graph 的 Product reason_code
  20. 用 artifact 存在性验证 Product partial 是否“合法”或是否可继续

22. 一句话总结

Diagnosis 是 nexrur program-first 智能闭环的统一解释层:它消费五桶 evidence 与 consumer diagnosis assets,输出独立的 diagnosis_result.result_code;Production 对当前 Product 的 status/reason/reason_code 保持唯一所有权,Campaign 只决定后续 cycle 动作,任何诊断或控制结果都不得回写当前 Product。


23. Diagnosis 调用图与父级 deadline

Diagnosis 必须向 fail2pivot 声明足以防止父级误杀 child 的 bounded call topology,而不是 把单次 LLM provider watchdog 当作整个父级时限。一次 child floor 包含底座最大 admission wait、provider 无进展 watchdog 和有界返回 tail;串行/并发信息只用于形成保守安全下限, 不用于预测完成时间或中断仍有进展的调用。

nexrur_fail2pivot 的 ToolLoop watchdog floor 不得短于已接纳的 Diagnosis child 加 Campaign 与投影收尾;Orchestrator graph floor 只能延长 Worker operator watchdog。 不得保留短于单个 Diagnosis child 的通用 120 秒父级,也不得用 ToolLoop batch-local max_total_latency_ms 冒充精确的 Step5/6 完成时限。

若 Diagnosis child 超时、排队耗尽或输出不可用,Diagnosis 返回自己的 execution incident; 它不修改输入 Product。父级超时同样不能把 Product reason 改成 Diagnosis result、 diagnosis_unavailable 或 batch error。测试必须验证父级不会缩短 child watchdog、健康长 调用可继续完成,以及 Product code 原样透传。


24. Active Source App Boundary Freeze

Diagnosis substrate 只能解释 app 通过 catalog、schema、observed signals 和 evidence 合同声明的业务事实,不能在 active Python 中拥有 WQ-YI 的 Evaluate、Dataset、 Pyramid 或 Alpha 质量词汇。以下词属于 app contract,不属于底座 ontology:

quality_wave_learning_facts
evaluate_diagnosis_context
qualified_count
alpha_quality
dataset_l1
dataset_l2
skeleton_preflight_facts
all_relevant_pyramids_*

2026-08-01 的 Diagnosis 现存债务冻结如下;这是迁移清单,不是允许继续扩展的 设计:

active filefrozen occurrences迁移方向
engines/diagnosis/context.py0app predicate、quality 解释和 dataset scope 已迁入 app diagnosis assets;context.py 只执行通用 path + operator + value 规则

quality_wave_learning_facts、cross-wave candidate 特判、retry 正则、Evaluate scope、simulation/qualified/slot/pyramid/L2 predicates、alpha-quality 文本猜测和 diagnosis_focus 已于 2026-08-01 从 Diagnosis active code/schema 移除,边界基线 为 0。通用 Diagnosis schema 外置、候选编译、持久化和 trial 边界保持不变。

边界冻结规则:

  • active src/nexrur/**/*.py|yml|yaml 按大小写不敏感扫描,不得增加上述词的 新文件或新次数;
  • _archived 不参与 active 边界扫描;
  • 删除现存命中允许直接通过,不要求维持旧计数;
  • 已归零的词继续保持 0;其余命中后续以 app contract 替代并逐项降低基线;
  • 边界测试只检查源码归属,不判断运行结果,也不得成为新的业务 gate。