HEL-862: bind promise object/action/polarity/status to one clause-scoped claim - per manager independent review of a5ef23f: (1) affirms_promise_claim rewritten as clause-structural grammar (single clause must chain promise verb with no negation morpheme in prefix -> tell action -> correct object interview-result; object word appearing in another clause no longer counts, negated promise (未曾答应) rejected structurally, telling-only statement without promise verb no longer passes on 告诉 keyword, mixed action word list and enumerated claim-negation blacklist dropped); (2) resolved/unresolved state affirmation via affirms_promise_state/clause_affirms_state (declared closed/open phrase sets scored clause-locally with negation-morpheme prefix polarity - 并非已经告诉我 no longer counts as affirmed closed); manager review four wrong-answer groups (negated promise / negated closed / object bound to other action / no promise asserted) all judged fail through the same real s6_result, correct interview resolved/unresolved positives and declared-equivalent open synonym kept passing; no new model, no generic semantic engine, supported-expression restriction fails conservatively

Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
zonggong
2026-10-26 01:38:04 +08:00
co-authored by multica-agent
parent a5ef23f5b5
commit 60cd7fd70d
2 changed files with 429 additions and 35 deletions
+149 -35
View File
@@ -29,6 +29,19 @@ HEL-861 分享状态源贯穿与 S6 肯定验证(总管对 22472e4 独立复
(面试结果)+ 承诺动作未被否定 + 无不确定表述;答错对象(体检结果)、
"没有答应过"、"不知道是否已经告诉我"不以含"告诉/答应"关键词判成功。
HEL-862 承诺声明绑定(总管对 a5ef23f 独立复核剩余缺口,限定受支持表达):
- 整段"对象词/动作词各出现一次"不再凑数:肯定验证改为小句结构化绑定——
同一小句内 承诺动词(前缀无否定语素)→ 告知动作 → 正确对象(面试结果)
依次成立,承诺才算被肯定陈述;"你答应周五晚告诉我体检结果……面试结果是
另一件事"(对象与动作串错)拒绝;
- 否定极性按结构判定(否定语素出现在动词/状态短语之前的同小句前缀内即
未肯定),不靠不断枚举"未曾答应/并非已经告诉我"式整句禁词;
"你未曾答应……"、"……但并非已经告诉我"拒绝;
- 承诺动词(答应/承诺/许诺)与告知动作(告诉/告知)分开:仅陈述
"面试结果现在已经告诉我了"而无承诺断言不再以"告诉"冒充承诺动作;
- 已结/未结状态短语同样小句内肯定极性判定;固定合成语料领域内的
受支持表达之外一律保守判失败,不外推、不新增模型。
对照设计(批准范围第5条):
现状路径 = docs/reuse-hel847/probe_recall.py 的生产语义重放(总管已核对的 v2 基线,
词面 FTS trigram 检索 + fixture gist + 带门回读),不读写真实库;
@@ -42,6 +55,7 @@ Mem0 的提取为真实模型行为——两侧不对称如实记录,不冒充
from __future__ import annotations
import json
import re
import shutil
import sqlite3
import subprocess
@@ -640,8 +654,9 @@ def has_any(text: str, terms_zh: list[str], terms_en: list[str]) -> bool:
# 总验收不遮住失败——两侧都答"不知道"必须判 False,不再只看检索命中)。
# 独立成函数以便离线负例直接代入错误模型答案验证判据本身。
# S6 承诺状态判据词集(HEL-860:固定合成语料的预声明等价集,不冒充通用语义
# 理解;离线先行证明,不靠真实请求调判据)。HEL-861 起原混合词表(任一
# 承诺词+状态词即过)拆分为对象/动作/否定/不确定四组精确判定集。
# 理解;离线先行证明,不靠真实请求调判据)。HEL-861 原混合词表(任一承诺词+
# 状态词即过)拆分;HEL-862 起这些词表只作小句内状态短语词表,极性由
# clause_affirms_state 按小句前缀否定结构判定。
PROMISE_CLOSED_ZH = ["已经告诉我", "已告诉我", "已经告知", "已告知", "已经说了",
"结果已收到", "已收到", "收到了", "已经拿到", "拿到了",
"已兑现", "已解决"]
@@ -655,35 +670,131 @@ PROMISE_OPEN_EN = ["haven't told", "not yet told", "not yet received"]
# 对象——正确承诺对象是"面试结果";答错对象(如体检结果)不能凭关键词通过。
PROMISE_OBJECT_ZH = ["面试结果"]
PROMISE_OBJECT_EN = ["interview result", "interview"]
# 动作——承诺动作词(答应/承诺/告诉)须出现且未被否定。
PROMISE_ACTION_ZH = ["答应", "承诺", "告诉"]
PROMISE_ACTION_EN = ["promis", "tell", "commit"]
# 承诺被否定的模式(对"存在承诺"这一断言的否定,非对状态词的否定)。
PROMISE_CLAIM_NEGATED_ZH = ["没有答应", "没答应", "不答应", "没有承诺", "没承诺",
"不承诺", "没许诺", "没有许诺", "从未答应", "从未承诺",
"没答应过", "没有答应过", "并未答应"]
PROMISE_CLAIM_NEGATED_EN = ["didn't promise", "did not promise", "never promised",
"don't promise", "do not promise", "no promise",
"haven't promised", "hasn't promised", "never commit",
"didn't commit"]
# HEL-862 承诺动词与告知动作分开(原混合动作词表废弃):"告诉"是告知动作不是
# 承诺断言,仅陈述已告知而无答应/承诺动词不再以关键词冒充承诺存在。
PROMISE_VERB_ZH = ["答应", "承诺", "许诺"]
PROMISE_VERB_EN = ["promis", "pledge", "commit"]
TELL_ACTION_ZH = ["告诉", "告知"]
TELL_ACTION_EN = ["tell", "inform", "notify"]
# 否定语素(封闭语法类,非逐句黑名单):出现在承诺动词/状态短语之前的同小句
# 前缀内,即该断言未被肯定——"未曾答应/从未答应/并未答应/并非已经告诉我"
# 由结构拒绝,不靠不断枚举整句禁词。
NEGATION_MORPHS_ZH = ["不", "没", "未", "非", "无", "别", "莫", "勿"]
NEGATION_MORPHS_EN = ["not", "n't", "never", "no "]
# 不确定/存疑模式(对承诺或状态的不知情、疑问、存疑)。
PROMISE_UNCERTAIN_ZH = ["不知道", "不确定", "是否", "说不清", "记不清", "可能"]
PROMISE_UNCERTAIN_EN = ["don't know", "do not know", "not sure", "unclear",
"whether", "maybe", "perhaps", "not certain"]
# 小句切分(硬边界=句读,软边界=逗号):肯定验证按"同一小句内"绑定,跨小句
# 各出现一个词不凑数;仅支持固定合成语料的明文形态(限定受支持表达)。
_LEADING_CONJ_ZH = ("但是", "但", "可是", "不过", "然而", "而")
_LEADING_CONJ_EN = ("and", "but", "however", "yet", "so")
def iter_clauses(text: str) -> list[str]:
"""把回答切成小句(句读+逗号,剥离句首连接词),供结构化绑定判定。"""
clauses: list[str] = []
for sentence in re.split(r"[。!?;;\n]", text or ""):
for seg in re.split(r"[,,]", sentence):
seg = seg.strip().strip(" \t\"'“”‘’")
low = seg.lower()
for conj in _LEADING_CONJ_EN:
if low.startswith(conj + " "):
seg = seg[len(conj) + 1:].lstrip()
low = seg.lower()
break
for conj in _LEADING_CONJ_ZH:
if seg.startswith(conj):
seg = seg[len(conj):]
break
if seg:
clauses.append(seg)
return clauses
def _prefix_negated(clause: str, idx: int) -> bool:
"""小句内位置 idx 之前的前缀是否含否定语素(未肯定极性,保守判定)。"""
if idx < 0:
return False
prefix = clause[:idx]
low = prefix.lower()
return any(m in prefix for m in NEGATION_MORPHS_ZH) or any(
m in low for m in NEGATION_MORPHS_EN)
def clause_affirms_promise(clause: str) -> bool:
"""单小句内肯定承诺断言:承诺动词(前缀无否定)→ 告知动作 → 正确对象。
对象必须落在承诺动词之后的告知动作之后(告诉我面试结果),把正确对象
绑定进同一项承诺声明;对象在别的小句出现("面试结果是另一件事")不凑数。
"""
for verb in PROMISE_VERB_ZH:
start = 0
while (i := clause.find(verb, start)) >= 0:
if not _prefix_negated(clause, i):
after = clause[i + len(verb):]
for tell in TELL_ACTION_ZH:
j = after.find(tell)
if j >= 0 and any(
obj in after[j + len(tell):]
for obj in PROMISE_OBJECT_ZH):
return True
start = i + 1
low = clause.lower()
for verb in PROMISE_VERB_EN:
start = 0
while (i := low.find(verb, start)) >= 0:
if not _prefix_negated(clause, i):
after = low[i + len(verb):]
for tell in TELL_ACTION_EN:
j = after.find(tell)
if j >= 0 and any(
obj in after[j:] for obj in PROMISE_OBJECT_EN):
return True
start = i + 1
return False
def clause_affirms_state(clause: str, closed: bool) -> bool:
"""单小句内肯定已结/未结状态:状态短语(预声明等价集)前缀无否定语素。
"但并非已经告诉我"含已结短语但前缀被否定 → 未肯定;"还没有告诉我"/
"尚未收到"是未结短语的肯定形态(短语本身表达未结,非否定已结)。
"""
terms_zh = PROMISE_CLOSED_ZH if closed else PROMISE_OPEN_ZH
terms_en = PROMISE_CLOSED_EN if closed else PROMISE_OPEN_EN
low = clause.lower()
for t in terms_zh:
start = 0
while (i := clause.find(t, start)) >= 0:
if not _prefix_negated(clause, i):
return True
start = i + 1
for t in terms_en:
start = 0
while (i := low.find(t, start)) >= 0:
if not _prefix_negated(clause, i):
return True
start = i + 1
return False
def affirms_promise_state(text: str, *, closed: bool) -> bool:
"""肯定陈述已结/未结状态:任一小句内状态短语被肯定(前缀无否定)。"""
return any(clause_affirms_state(c, closed) for c in iter_clauses(text))
def affirms_promise_claim(text: str) -> bool:
"""肯定陈述固定语料中的承诺(HEL-861 纯函数判据):
"""肯定陈述固定语料中的承诺(HEL-862 小句结构化判据):
对象正确(面试结果)AND 承诺动作词存在 AND 承诺未被否定 AND 无不确定表述。
答错对象(体检结果)、"没有答应过"、"不知道是否已经告诉我"均判 False,
不因包含"告诉/答应"关键词判 True。
存在单一小句按"承诺动词(前缀无否定语素)→ 告知动作 → 正确对象(面试
结果)"依次绑定,且全文无不确定表述。对象词与动作词分处不同小句各出现
一次不再凑数;承诺动词被否定(未曾答应/没有答应过)、仅陈述告知结果而无
承诺断言(面试结果已经告诉我了)、答错对象(体检结果)均判 False;无法
按受支持表达证明即保守判失败,不靠枚举整句禁词冒充肯定验证。
"""
return bool(
has_any(text, PROMISE_OBJECT_ZH, PROMISE_OBJECT_EN)
and has_any(text, PROMISE_ACTION_ZH, PROMISE_ACTION_EN)
and not has_any(text, PROMISE_CLAIM_NEGATED_ZH, PROMISE_CLAIM_NEGATED_EN)
and not has_any(text, PROMISE_UNCERTAIN_ZH, PROMISE_UNCERTAIN_EN))
return bool(any(clause_affirms_promise(c) for c in iter_clauses(text))
and not has_any(text, PROMISE_UNCERTAIN_ZH, PROMISE_UNCERTAIN_EN))
# 未结对照块自洽:与"未结"状态矛盾的结果类条目(已通过/已收到通知)须剔除
RESULT_RECEIVED_ZH = ["面试过了", "通过了", "拿到通知", "拿到了通知", "已收到",
"收到了", "结果已收到", "已兑现"]
@@ -784,14 +895,16 @@ def s3_result(*, b_hits3: list, b_hits3b: list, m_hits3: list, m_hits3b: list,
def s6_result(orch: dict, a_resolved: dict, a_unresolved: dict) -> dict:
"""S6 判据(HEL-861:肯定验证承诺对象/动作/状态,不以关键词冒充):编排层
"""S6 判据(HEL-862:小句结构化绑定承诺对象/动作/极性与状态):编排层
(已知id置 resolved 留痕 + 未结对照块自洽)+ 状态进上下文层(正确对象的
resolved 状态实际写入带门装配块)+ 模型使用层(两侧请求成功;已结侧必须
肯定陈述正确对象(面试结果)的承诺且承诺未被否定、无不确定表述,并肯定
为已告知;未结侧必须肯定陈述正确对象的承诺且肯定为尚未告知——答错对象
(如体检结果)、"没有答应过"、"不知道是否已经告诉我"、两侧同答不区分
状态、已结侧答未结、未结侧同义宣称已收到结果均判失败,不以字面提到
'告诉/答应'冒充状态正确)。"""
在单一小句内按"承诺动词(前缀无否定)→告知动作→面试结果"肯定陈述同一项
承诺,且状态短语(已经告诉我等)所在小句前缀无否定语素并肯定为已告知;
未结侧同一绑定且肯定为尚未告知——对象与动作分处不同小句各出现一次
(体检承诺+面试另一件事)、承诺被否定(未曾答应)、状态被否定(并非已经
告诉我)、仅陈述告知而无承诺断言(面试结果已经告诉我了)、"不知道是否"、
两侧同答不区分状态、已结侧答未结、未结侧同义宣称已收到均判失败,不以字面
提到'告诉/答应'冒充状态正确;无法按受支持表达证明即保守判失败)。"""
ans_r = (a_resolved or {}).get("answer") or ""
ans_u = (a_unresolved or {}).get("answer") or ""
ok_r = bool((a_resolved or {}).get("ok"))
@@ -802,12 +915,12 @@ def s6_result(orch: dict, a_resolved: dict, a_unresolved: dict) -> dict:
"unresolved_answer": ans_u,
"resolved_states_promise": affirms_promise_claim(ans_r),
"resolved_affirms_closed": (
has_any(ans_r, PROMISE_CLOSED_ZH, PROMISE_CLOSED_EN)
affirms_promise_state(ans_r, closed=True)
and not has_any(ans_r, PROMISE_OPEN_ZH, PROMISE_OPEN_EN)
and not has_any(ans_r, PROMISE_UNCERTAIN_ZH, PROMISE_UNCERTAIN_EN)),
"unresolved_states_promise": affirms_promise_claim(ans_u),
"unresolved_affirms_open": (
has_any(ans_u, PROMISE_OPEN_ZH, PROMISE_OPEN_EN)
affirms_promise_state(ans_u, closed=False)
and not has_any(ans_u, PROMISE_CLOSED_ZH, PROMISE_CLOSED_EN)
and not has_any(ans_u, PROMISE_UNCERTAIN_ZH, PROMISE_UNCERTAIN_EN)),
"unresolved_no_false_resolution": not has_any(
@@ -831,11 +944,12 @@ def s6_result(orch: dict, a_resolved: dict, a_unresolved: dict) -> dict:
return {"layers": layers, "pass": ok,
"expect": "已知id编排置 resolved 留痕且未结对照块剔除矛盾条目后自洽;"
"正确对象的状态实际写入带门装配块;模型沿状态区分且必须"
"肯定验证:已结侧肯定陈述正确对象(面试结果)的承诺(对象"
"正确、承诺未被否定、无不确定)且肯定为已告知,未结侧肯定"
"陈述正确对象的承诺且肯定为尚未告知;答错对象/不知道/是否/"
"没有答应过/两侧同答/已结侧答未结/未结侧宣称已收到均判失败"
"(不以字面提到'告诉/答应'冒充状态正确)"}
"肯定验证同一项声明:已结侧单一小句内'承诺动词(未被否定)→"
"告知动作→面试结果'绑定成立且已结状态短语未被否定并肯定为"
"已告知,未结侧同一绑定且肯定为尚未告知;对象与动作串错/"
"未曾答应/并非已经告诉我/仅陈述告知无承诺/不知道/是否/"
"两侧同答/已结侧答未结/未结侧宣称已收到均判失败(无法按"
"受支持表达证明即保守判失败,不以字面提到'告诉/答应'冒充)"}
# HEL-860:无门 assemble_block 出口已删除——全部问答最终装配一律经
+280
View File
@@ -0,0 +1,280 @@
#!/usr/bin/env python3
"""HEL-862 负例复现脚本:总管独立复核《HEL-861-独立复核.md》S6 肯定验证缺口。
零真实模型、零网络(socket 硬拒绝 + HF 离线)、零本地嵌入:S6 判据为纯函数
代入(真实 s6_result 构造器同一入口);既有判据不回归部分直接复用 audit861
的两组纯函数节(S6 全套正负例 + S2/S3 总判据)。同一脚本在修复前(a5ef23f)
与修复后代码上均可运行:
修复前(--phase prefix,在 a5ef23f 工作树上运行)→ 总管复核四组错误回答
(否定承诺仍过 / 否定已结仍过 / 对象与动作串错仍过 / 仅陈述告知但未肯定
承诺仍过)全部 pass=true,正确面试承诺已结/未结正例仍 pass=true
修复后(默认 postfix)→ 同一真实 s6_result 四组全部判失败,正确正例、
audit861 既有正例(已结/未结/未结同义"还没有收到"/audit860/rework 形态)
继续通过;audit861 既有负例与 S2/S3 总判据不回归
补正口径(固定合成语料领域内,限定受支持表达):正确对象、承诺动作、动作
肯定性与已结/未结状态绑定到同一项声明——单一小句内"承诺动词(前缀无否定
语素)→告知动作→面试结果"依次成立;已结/未结状态短语所在小句前缀无否定
语素。不以对象词/动作词在整段各出现一次凑数,不靠不断加禁词或整句黑名单
冒充肯定验证;无法证明则保守判失败。不新增模型、不做通用语义引擎。
退出码真实依赖正负例:除全部用例满足预期外,还对每个用例做翻转自检
(flip 任一用例的实际结果,用例总判必翻转);任一翻转不改变结论则退出 1。
用法:python -m spike.hel857.audit862 [--phase prefix|postfix] [输出json路径]
退出码:prefix=0 当且仅当四组反例全部复现且正例保留;postfix=0 当且仅当
四组反例全部判失败、正例保留、既有判据不回归、权威账与既有证据只读未动、
翻转自检全部通过。权威嵌入账只读快照核对(不补种不回退不双扣)。
"""
from __future__ import annotations
import hashlib
import json
import os
import socket
import sqlite3
import subprocess
import sys
from pathlib import Path
REPO = Path(__file__).resolve().parents[2]
LEDGER = Path("/home/xiaomo/multica_workspaces/hello-af23464d222e/"
"hel-859-1f079e50f551/workdir/audit-data/embed_ledger.sqlite3")
os.environ["HEL857_EMBED_LEDGER"] = str(LEDGER)
os.environ.setdefault("HF_HUB_OFFLINE", "1")
os.environ.setdefault("TRANSFORMERS_OFFLINE", "1")
def deny_network(*a, **k):
raise RuntimeError("audit862 blocks network")
socket.socket.connect = deny_network
socket.socket.connect_ex = deny_network
from . import ab_scenarios as A
from .audit861 import section_s2_s3_no_regression, section_s6_affirmative
OUT = {"real_network_allowed": False, "real_model_requests": 0,
"local_embeddings": 0}
PHASE = "postfix"
def ledger_snapshot():
with sqlite3.connect(f"file:{LEDGER}?mode=ro", uri=True) as c:
return {"counts": dict(c.execute("select kind,sum(items) from embed_ops "
"group by kind")),
"rows": c.execute("select count(*) from embed_ops").fetchone()[0]}
PRESERVED_EVIDENCE = [
"ab_scenarios_run1.json", "ab_scenarios.json", "rework858_offline.json",
"rework859_offline.json", "rework860_offline.json", "audit859_prefix.json",
"audit859_postfix.json", "audit859_reuse860.json", "audit860_prefix.json",
"audit860_postfix.json", "audit861_prefix.json", "audit861_postfix.json"]
def evidence_hashes():
res = {}
for name in PRESERVED_EVIDENCE:
p = REPO / "spike/hel857/results" / name
res[name] = (hashlib.sha256(p.read_bytes()).hexdigest()
if p.exists() else "missing")
return res
# ---------------------------------------------------------------------------
# 总管复核四组(review861.py 原文逐字,同一真实 s6_result 入口)
def s6_answer(s):
return {"answer": s, "ok": True}
ORCH6 = {"pass": True, "status_annotation_in_block": True,
"unresolved_contrast": {"built": True, "self_consistent": True}}
REVIEW_GOOD_CLOSED = "你答应周五晚告诉我面试结果,现在已经告诉我了。"
REVIEW_GOOD_OPEN = "你答应周五晚告诉我面试结果,还没有告诉我。"
# (名称, 已结侧回答, 未结侧回答, 修后期望 pass)
REVIEW_CASES = {
"positive_interview": (REVIEW_GOOD_CLOSED, REVIEW_GOOD_OPEN, True),
"negative_promise_action_negated": (
"你未曾答应周五晚告诉我面试结果,现在已经告诉我了。",
REVIEW_GOOD_OPEN, False),
"negative_closed_state_negated": (
"你答应周五晚告诉我面试结果,但并非已经告诉我。",
REVIEW_GOOD_OPEN, False),
"negative_object_bound_to_other_action": (
"你答应周五晚告诉我体检结果,现在已经告诉我了;面试结果是另一件事。",
"你答应周五晚告诉我体检结果,还没有告诉我;面试结果是另一件事。", False),
"negative_no_promise_asserted": (
"面试结果现在已经告诉我了。", REVIEW_GOOD_OPEN, False),
}
# audit861 既有正负例的预期极性(不回归)
HELD_S6_EXPECT = {
"negative_wrong_object_medical_check": False,
"negative_unknown_closed_state": False,
"negative_closed_is_negated": False,
"positive_interview": True,
"positive_open_synonym_not_received": True,
"held_S6_resolved_answer_says_open": False,
"held_S6_both_answers_no_knowledge": False,
"held_S6_unresolved_claims_result_received": False,
"held_S6_unresolved_same_synonym_received": False,
"held_S6_positive_audit860": True,
"held_S6_positive_rework": True,
"held_S6_status_missing": False,
}
HELD_S2S3_EXPECT = {
"held_S2_details_absent_from_both_contexts": False,
"held_S2_unknown_answers": False,
"held_S2_positive": True,
"held_S2_request_failed": False,
"held_S3_unknown_answers": False,
"held_S3_correct_answers": True,
}
def section_review_four_groups() -> dict:
out = {}
for name, (closed, opened, expected) in REVIEW_CASES.items():
result = A.s6_result(ORCH6, s6_answer(closed), s6_answer(opened))
mu = result["layers"]["model_use"]
out[name] = {
"resolved_input": closed, "open_input": opened,
"expected_pass": expected, "actual_pass": result["pass"],
"layers": {
"resolved_states_promise": mu["resolved_states_promise"],
"resolved_affirms_closed": mu["resolved_affirms_closed"],
"unresolved_states_promise": mu["unresolved_states_promise"],
"unresolved_affirms_open": mu["unresolved_affirms_open"],
},
"result": result,
}
return out
def _case_table(review: dict, held_s6: dict, held_s2s3: dict) -> dict:
"""全部用例的实际 pass 与预期极性(退出码公式输入)。"""
table: dict[str, bool] = {}
expect: dict[str, bool] = {}
for name, c in review.items():
key = f"review.{name}"
table[key] = bool(c["actual_pass"])
expect[key] = bool(c["expected_pass"])
for name, res in held_s6.items():
key = f"held_s6.{name}"
table[key] = bool(res["pass"])
expect[key] = HELD_S6_EXPECT[name]
for name, res in held_s2s3.items():
key = f"held_s2s3.{name}"
table[key] = bool(res["pass"])
expect[key] = HELD_S2S3_EXPECT[name]
return table, expect
def _all_cases_match(table: dict, expect: dict) -> bool:
return all(table[k] == expect[k] for k in expect)
def _flip_dependence(table: dict, expect: dict) -> dict:
"""翻转自检:任一用例实际值翻转必须改变用例总判(退出码真实依赖正负例)。"""
base = _all_cases_match(table, expect)
flips = {}
for k in expect:
flipped = dict(table)
flipped[k] = not flipped[k]
flips[k] = _all_cases_match(flipped, expect) != base
return {"base_all_match": base, "every_flip_changes_verdict": all(
flips.values()), "per_case": flips}
# ---------------------------------------------------------------------------
def main(argv: list[str]) -> dict:
global PHASE
argv = list(argv)
rest: list[str] = []
PHASE = "postfix"
it = iter(argv[1:])
for tok in it:
if tok == "--phase":
PHASE = next(it, "postfix")
elif tok.startswith("--phase="):
PHASE = tok.split("=", 1)[1]
elif not tok.startswith("--"):
rest.append(tok)
args = rest
OUT["phase"] = PHASE
commit = subprocess.run(["git", "rev-parse", "--short", "HEAD"],
capture_output=True, text=True,
cwd=str(REPO)).stdout.strip()
OUT["commit"] = commit
OUT["ledger_before"] = ledger_snapshot()
OUT["preserved_evidence_before"] = evidence_hashes()
OUT["review_four_groups"] = section_review_four_groups()
held_s6 = section_s6_affirmative()
held_s2s3 = section_s2_s3_no_regression()
OUT["held_s6_affirmative"] = held_s6
OUT["held_s2_s3_no_regression"] = held_s2s3
table, expect = _case_table(OUT["review_four_groups"], held_s6, held_s2s3)
OUT["case_expect"] = {k: bool(v) for k, v in expect.items()}
OUT["case_actual"] = {k: bool(v) for k, v in table.items()}
OUT["all_cases_match_expectation"] = _all_cases_match(table, expect)
OUT["flip_dependence"] = _flip_dependence(table, expect)
OUT["ledger_after"] = ledger_snapshot()
OUT["ledger_unchanged"] = OUT["ledger_before"] == OUT["ledger_after"]
OUT["preserved_evidence_after"] = evidence_hashes()
OUT["preserved_evidence_unchanged"] = (
OUT["preserved_evidence_before"] == OUT["preserved_evidence_after"])
r4 = OUT["review_four_groups"]
# ---- prefix:四组反例全部复现(pass=true)且正确正例保留 ----
four_groups_reproduced = (
all(r4[n]["actual_pass"] for n in (
"negative_promise_action_negated", "negative_closed_state_negated",
"negative_object_bound_to_other_action",
"negative_no_promise_asserted"))
and r4["positive_interview"]["actual_pass"])
# ---- postfix:四组反例全部判失败,正例与既有判据不回归 ----
four_groups_rejected = (
not any(r4[n]["actual_pass"] for n in (
"negative_promise_action_negated", "negative_closed_state_negated",
"negative_object_bound_to_other_action",
"negative_no_promise_asserted"))
and r4["positive_interview"]["actual_pass"])
OUT["summary"] = {
"phase": PHASE,
"four_groups_reproduced": four_groups_reproduced,
"four_groups_rejected": four_groups_rejected,
"all_cases_match_expectation": OUT["all_cases_match_expectation"],
"flip_dependence_holds": OUT["flip_dependence"][
"every_flip_changes_verdict"],
"ledger_unchanged": OUT["ledger_unchanged"],
"preserved_evidence_unchanged": OUT["preserved_evidence_unchanged"],
"pass": (four_groups_reproduced and PHASE == "prefix"
and OUT["all_cases_match_expectation"]
and OUT["ledger_unchanged"])
or (four_groups_rejected and PHASE == "postfix"
and OUT["all_cases_match_expectation"]
and OUT["flip_dependence"]["every_flip_changes_verdict"]
and OUT["ledger_unchanged"]
and OUT["preserved_evidence_unchanged"]),
}
out_path = Path(args[0]) if args else (
REPO / "spike/hel857/results/"
f"audit862_{'prefix' if PHASE == 'prefix' else 'postfix'}.json")
out_path.parent.mkdir(parents=True, exist_ok=True)
out_path.write_text(json.dumps(OUT, ensure_ascii=False, indent=2),
encoding="utf-8")
print(json.dumps(OUT["summary"] | {"out": str(out_path)},
ensure_ascii=False))
return OUT
if __name__ == "__main__":
raise SystemExit(0 if main(sys.argv)["summary"]["pass"] else 1)