feat: 场景引擎与测试底层方法统一(ADR-0014,ADR-0013 系列 PR-C) - #13
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
PR Summary by Qodo统一声明式场景引擎与控制测试门禁
AI Description
Diagram
High-Level Assessment
Files changed (5)
|
Code Review by Qodo
1. Structured assertions match substrings
|
| narrative: 意图→组队→planner 产卡→test_author 冻结测试树→card_gate→build→verify | ||
| (verifier 判卷+review)→integrator 合并→release_bot behind flag→handoff→销毁 | ||
| hook: scenario_happy_path | ||
| ct_refs: [CT-BLD-002, CT-PLN-001, CT-PLN-002, CT-TA-001, CT-RLB-001] |
There was a problem hiding this comment.
1. Cross-registry links skip approval status 📘 Rule violation ≡ Correctness
The new scenario and ct_refs links reference registry entries that have no status, while validation only confirms that targets exist. Consequently, references to unapproved or deprecated entries cannot be rejected.
Agent Prompt
## Issue description
The scenario and control-test registries now reference each other, but referenced entries do not declare `status: approved` and the validator does not enforce approval status.
## Issue Context
PR Compliance ID 2771006 requires every referenced registry entry to exist and have an exactly approved status. Add a required status field to both registry schemas and fail validation when a referenced scenario or control test is not approved.
## Fix Focus Areas
- standards/control-tests.yaml[9-255]
- standards/scenarios.yaml[22-156]
- scripts/validate.py[450-464]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| s = val if isinstance(val, str) else str(val) | ||
| if op == "eq": | ||
| return None if s == str(want) else f"{a['path']}={s!r} != {want!r}" | ||
| if op == "contains": | ||
| return None if str(want) in s else f"{a['path']} 不含 {want!r}(实={s[:80]!r})" | ||
| if op == "not_contains": | ||
| return None if str(want) not in s else f"{a['path']} 不应含 {want!r}" | ||
| if op == "contains_all": | ||
| missing = [w for w in want if str(w) not in s] |
There was a problem hiding this comment.
2. Structured assertions match substrings 🐞 Bug ≡ Correctness
contains, not_contains, and contains_all stringify lists and mappings before searching, so they test substrings rather than exact members. For example, S16's required paused state would still pass if the lifecycle contained only unpaused, allowing a broken declaration to remain green.
Agent Prompt
## Issue description
The declarative assertion evaluator converts structured YAML values to strings before applying containment operations. This allows partial matches in unrelated keys or values and can make scenario assertions pass when required list members are absent.
## Issue Context
String values may continue using substring semantics, but lists should use exact element membership and mappings should use explicit key/value semantics. `contains_all` should require every expected item to be an exact member of a collection.
## Fix Focus Areas
- scripts/simulate-wave.py[167-185]
- standards/scenarios.yaml[132-143]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| for cid, ct in CT_TESTS.items(): | ||
| if not isinstance(ct, dict): | ||
| continue |
There was a problem hiding this comment.
3. Malformed ct bypasses validation 🐞 Bug ≡ Correctness
The CT loop silently skips every non-mapping test value, while existing coverage checks only require the CT ID to be present. Replacing a referenced CT definition with a scalar therefore bypasses all new scenario, runtime, and runtime_note requirements without failing validation.
Agent Prompt
## Issue description
Non-mapping control-test entries are silently skipped, allowing an existing CT ID to retain coverage membership while bypassing the new runtime and scenario metadata checks.
## Issue Context
Every CT entry must first be validated as a mapping. Invalid entries should call `fail()` and then be skipped only to avoid secondary exceptions; they must never be accepted silently. Add regression coverage for scalar, list, and null CT definitions.
## Fix Focus Areas
- scripts/validate.py[152-178]
- scripts/validate.py[443-460]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| hook: scenario_trust_chain | ||
| ct_refs: [CT-ADV-003] |
There was a problem hiding this comment.
4. S11 links wrong control 🐞 Bug ≡ Correctness
S11 lists CT-ADV-003, whose own scenario is null and whose claim concerns CT coverage, while the S11 hook explicitly verifies the CT-RES-002 source requirement. This makes the scenario registry omit its actual linked control test and advertise an unrelated one.
Agent Prompt
## Issue description
S11's `ct_refs` points to CT-ADV-003 even though its hook explicitly enforces CT-RES-002 and CT-RES-002 declares S11 as its scenario prerequisite.
## Issue Context
Replace the unrelated reference and strengthen validation so a CT naming a scenario must be represented consistently in that scenario's references, unless asymmetric links are explicitly modeled and documented.
## Fix Focus Areas
- standards/scenarios.yaml[81-86]
- standards/control-tests.yaml[170-194]
- scripts/simulate-wave.py[570-603]
- scripts/validate.py[443-464]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| for sid, spec in SCEN.items(): | ||
| for ref in (spec.get("ct_refs") or []): | ||
| if ref not in CT_TESTS: | ||
| fail(f"scenario {sid} ct_refs 引用不存在的 {ref}(悬空 CT 引用)") |
There was a problem hiding this comment.
5. Malformed scenarios crash validation 🐞 Bug ☼ Reliability
The new reverse-link loop calls spec.get() without verifying that each scenario is a mapping, so valid YAML such as S18: null or S18: [] terminates validation with an uncaught AttributeError. The scenario engine has the same unchecked assumption and also crashes instead of reporting a registry failure.
Agent Prompt
## Issue description
Structurally malformed scenario entries cause uncaught exceptions in both validation and simulation instead of producing controlled diagnostics.
## Issue Context
Validate that the scenarios root is a mapping, each scenario is a mapping, `asserts` and `ct_refs` are lists, and each assertion has the required mapping fields before dereferencing them. Add malformed-root and malformed-entry regression tests.
## Fix Focus Areas
- scripts/validate.py[443-464]
- scripts/simulate-wave.py[167-185]
- scripts/simulate-wave.py[631-656]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
回答"我下达意图到最后完成,流程是什么":
- standards/intent-routing.yaml:八分类路由表(deliver/fix/respond/investigate/
maintain/govern/spawn/ask),每类声明 {载体, 验收来源, owner 同步成本, flow_ref};
三立场:不设多套流程(R1)/owner 从不启动任何东西(R2,分类=interface-gateway
机制判定,歧义按更重一侧路由+问一次)/注意力只花在新对错(R3)
- 验收三分法落地 flows.yaml#intent_ratification.shortcuts:new_ratable(新批)/
self_evident(自明——fix 意图原文即验收)/pre_approved(预批准——复绿即验收,
不可迁移到新验收面)/predetermined/evidence_based
- change-classes +trivial(fix 载体:自明验收+verifier 判卷不豁免+promote_if 四条
路径规则防"小修"定义膨胀)+spike(investigate 载体:无合并面产 ADR/finding,
evidence_based——此前无载体类,真实缺口)
- flows.yaml#maintain_loop:issue 五态生命周期(open→triage→consumed→closed/deferred),
不变式"issue 不可能躺在列表里"(消费/驳回/带条件延期三选一);maintenance_wave
自救通道(security 级 OR aging>30d 触发——周扫问题无人手动启动 agent 的结构答案)
- team-collaboration backlog 接口 +maintenance_trigger(引用 flows 单一真源)
- validate.py fail-closed:路由引用的 change_class/团队原型必须存在;trivial/spike
不可成孤类(负向测试:删 fix 路由→FAIL exit=1)
验证:validate OK + simulate 12 场景全通。系列:PR-B(owner 控制+可观测)/
PR-C(场景声明化+测试引擎统一)。
可观测与控制一体两面:同一事件流的读端(TUI/agent 查询)与写端(控制动词), 不新建设施,不出现"看得到控不了、控了看不到"。 - standards/observability.yaml:原则(read_only/attention_first/provenance)+ TUI 六视图(attention 默认页=等决策队列+SLA 倒计时/now/wave/budget/backlog/trace)+ log 三级受众投影(owner/机制/审计——同一事件流三个读端投影,非三套日志)+ ask 检索契约(researcher as_tool,回答必附引用,与 TUI 同源同投影) - flows.yaml#owner_control:pause=停表停预算(wall_clock 不计暂停,usd 已花照记); abort=不可逆+reason 必填,reason_routing 三路善后(need_gone 作废/spec_wrong 退 backlog 接 escape 回路/superseded 关联新卡);不变式:控制动词=事件不是凭据 (TUI 无数据层写凭据);注意力账本零新增(账本管系统等 owner,owner 主动出手不入账) - team-collaboration:卡生命周期 +paused/aborted 状态(owner_control_ref 单一真源 引用);event_producers +card.paused/resumed/aborted(owner 经平台通道); services +tui 机制(视图物化+控制入站——fail-closed 注册);interface_gateway duty 扩展 ask 路由与控制动词入站 验证:validate OK + simulate 12 场景全通 + 语义链核对脚本通过(六视图/三事件有主/ tui 注册/paused+aborted 状态)。基于 PR-A 分支(#11 合并后自然 rebase)。
统一方法论:一切测试 = 事件进 → 事件出 → 断言不变式(L1 原语 A1-A7 不变 / L2 场景剧本 YAML 声明化 / L3 门禁 PR 回归+CT 先决)。 - standards/scenarios.yaml:场景注册表(17 场景)。S1-S12 存量(hook 保留, 元数据+ct_refs 入表);S13-S17 新场景纯声明式(零 Python):S13 trivial 直通 / S14 maintain loop(issue 五态无第四态)/ S15 maintenance wave 触发 / S16 owner pause-abort / S17 未批意图拒绝(control 类=CT-PLN-003 声明层先决) - simulate-wave.py:引擎化——声明式断言求值器(path+op 统一求值,支持数字键); run() 注册表驱动(hook 双向一致性=漂移检测);输出 class 统计 - control-tests.yaml:29 条 CT 全部链接 scenario(声明层先决)+ runtime (adversary-executed×10 / validate-executed×3 / manual_only×16 各带 runtime_note 理由——理由清单即待自动化攻击面清单) - validate.py:CT↔scenario 双向校验(悬空引用/非法 runtime/manual_only 无理由=FAIL) 验证:validate OK + simulate 17 场景全通(30 声明式断言+12 hook);负向测试 3 连 (CT 悬空场景/声明式断言失败/manual_only 无理由均 FAIL 拦截)。
1b88752 to
383f1c3
Compare
7bd0c82 to
3c60105
Compare
383f1c3 to
812af11
Compare
解决什么
"流程本身也需要是声明式的;做出来要考虑如何模拟、未来流程怎么测试;测试的底层方法要代码化要统一。"(ADR-0014)
核心命题
流程、角色、治理声明完备后,组织的一切行为都是状态机转移——可枚举即可测试。统一底层方法:
一切测试 = 事件进 → 事件出 → 断言不变式(三层):
变更
1. scenarios.yaml:17 场景注册表
{path, op, value},op ∈ {exists, eq, contains, not_contains, contains_all}2. simulate-wave.py 引擎化
声明式断言求值器(路径解析+op 求值);run() 注册表驱动;hook 双向一致性检查(声明 hook 不存在/实现未登记=漂移=FAIL)。
3. CT 双层链接(29 条全部完成)
"假防线"从无法发现变为机器可判(ADR-0012 发现 adr-required 悬空是人工摸底,现在制度化了):
scenario:声明层先决(模拟器绿=CT 前提成立;null 须显式)runtime:adversary-executed×10 / validate-executed×3 / manual_only×16(每条带 runtime_note 理由——理由清单即待自动化的攻击面清单)4. validate 双向校验
CT 引用场景必须存在;scenario.ct_refs 引用 CT 必须存在;manual_only 无理由=CI 拒绝。
验证
validate OK + simulate 17 场景全通(30 声明式断言+12 hook);负向测试 3 连(悬空场景引用/声明式断言失败/manual_only 无理由)均 FAIL 拦截。
诚实边界(写进 scenarios.yaml 头部)
模拟测"声明的世界";实现的世界归 gate/verifier;防线真实有效归 escape_review/CT——三层各管一段,不互相冒充。S1-S12 hook 迁移纯声明式=后续增量(不假装一次完成)。