mirror of
https://github.com/ThearchyHelios/AgentLab.git
synced 2026-11-15 00:01:58 +00:00
分析结论的「在验证什么」照实说谁写的:分析卡上那一条是模板作者写的,标「分析卡上写的『在验证什么』」;Agent 现场做的照旧「Agent 写的假设」(台账条目带 item 的是分析卡、带 call_id 的是 Agent)。服务端按 origin 给 hypothesis_label、hypothesis_note 两句,证据面板、导出页、可验证报告都照原样显示,不自己拼。测试:证据接口两种都测,分析卡的链、导出页、核对页各加一条断言
This commit is contained in:
@@ -1015,8 +1015,12 @@ async def _chain(seg: dict[str, Any], doc: dict[str, Any], sealed: _Sealed,
|
||||
# 分析结论的出处链
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
#: Agent 写的假设(hypothesis)旁边那句:它不是结论,只在证据面板显示(细案 01 §7.3)
|
||||
HYPOTHESIS_NOTE = "Agent 写的假设:说明这次在验证什么,不是分析结论,也不进报告正文"
|
||||
#: 「在验证什么」(hypothesis)旁边那句:它不是结论,只在证据面板显示(细案 01 §7.3)。谁写的照实说:Agent 现场做的
|
||||
#: (台账条目带 call_id)写「Agent 写的假设」,分析卡做的(带 item)是模板作者写的,写「分析卡上写的『在验证什么』」
|
||||
HYPOTHESIS_LABEL = "Agent 写的假设"
|
||||
HYPOTHESIS_NOTE = f"{HYPOTHESIS_LABEL}:说明这次在验证什么,不是分析结论,也不进报告正文"
|
||||
CARD_HYPOTHESIS_LABEL = "分析卡上写的『在验证什么』"
|
||||
CARD_HYPOTHESIS_NOTE = f"{CARD_HYPOTHESIS_LABEL}:模板作者写的那一句,不是分析结论,也不进报告正文"
|
||||
UNSEALED_ANALYSIS = "这份分析结论不属于封存范围内的任何事件(封存前的台账里没有它),不能作为证据展示"
|
||||
TAMPERED_ANALYSIS = "分析结论与哈希不一致,疑似被修改,不展示其中的判定和数"
|
||||
MISSING_ANALYSIS = "无法读取分析结论"
|
||||
@@ -1104,7 +1108,8 @@ async def _analysis_chain(seg: dict[str, Any], cite: dict[str, Any], entry: dict
|
||||
"""分析结论的出处链(00-总方案 §3.3):判定 → 方法 → 计算 → 输入 → 复算 → 封存。
|
||||
|
||||
- 判定(analysis):判定语、判定标准、判定码和点名的段、附带说明、算不了的原因,这一处引用的是哪一项(判定语、具名标量、
|
||||
结果表的一格);Agent 写的假设另列,标成「Agent 写的假设」(HYPOTHESIS_NOTE)
|
||||
结果表的一格);「在验证什么」另列,谁写的照实标:Agent 现场做的写「Agent 写的假设」
|
||||
(HYPOTHESIS_NOTE),分析卡做的写「分析卡上写的『在验证什么』」(CARD_HYPOTHESIS_NOTE,模板作者写的)
|
||||
- 方法(analysis_method):方法与版本、规范化后的参数、实际用的阈值(只列这个算子用到的)、现查的表范围(probes)
|
||||
- 计算(analysis_calc):结果表(前 table_top_k 段,加上被引用的那一行附近)、具名的数、关键数的代入式
|
||||
(evidence.analysis_formulas)
|
||||
@@ -1154,7 +1159,11 @@ async def _analysis_chain(seg: dict[str, Any], cite: dict[str, Any], entry: dict
|
||||
phrase=result.get("phrase"), criterion=result.get("criterion"), verdict=verdict,
|
||||
caveats=[{k: c.get(k) for k in ("code", "text")} for c in result.get("caveats") or [] if isinstance(c, dict)])
|
||||
if isinstance(result.get("hypothesis"), str) and result["hypothesis"].strip():
|
||||
judged.update(hypothesis=result["hypothesis"], hypothesis_note=HYPOTHESIS_NOTE)
|
||||
# 谁写的照实说:分析卡(台账条目带 item)是模板作者写的,Agent 工具(带 call_id)是现场写的
|
||||
card = judged["origin"] == "card"
|
||||
judged.update(hypothesis=result["hypothesis"],
|
||||
hypothesis_label=CARD_HYPOTHESIS_LABEL if card else HYPOTHESIS_LABEL,
|
||||
hypothesis_note=CARD_HYPOTHESIS_NOTE if card else HYPOTHESIS_NOTE)
|
||||
settings = result.get("settings") if isinstance(result.get("settings"), dict) else {}
|
||||
method = {
|
||||
"step": "analysis_method", "alias": alias, "method": result.get("method"),
|
||||
|
||||
@@ -259,7 +259,7 @@
|
||||
dCell: '快照里的值', dShown: '正文显示', dShownSame: '与按显示规则渲染的结果一致', dExpected: '按显示规则应为',
|
||||
dArtifact: '所在工件', dReport: '所在报告',
|
||||
dPhrase: '判定语', dCriterion: '判定标准', dMethod: '方法与版本', dAnalysis: '分析结论里的值', dRecheck: '复算',
|
||||
dAnalysisInputs: '输入', dHypothesis: 'Agent 写的假设', dCaveats: '附带说明',
|
||||
dAnalysisInputs: '输入', dHypothesis: 'Agent 写的假设', dCardHypothesis: '分析卡上写的『在验证什么』', dCaveats: '附带说明',
|
||||
recheckBy: '导出时服务端按封存的输入复算的结论;本页只核哈希,不在浏览器里重算统计',
|
||||
recheckNone: '导出时没有复算(结论未随文件附带)',
|
||||
analysisInput: (role, alias) => `${role}${alias ? ` · ${alias}` : ''}`,
|
||||
@@ -1212,7 +1212,7 @@
|
||||
async function verify(data, digest, shownSeal) {
|
||||
const out = {
|
||||
events: [], manifest: [], artifacts: [], chain: [], numbers: [], docs: [], meta: [], checked: new Map(), order: [],
|
||||
arts: new Map(), queryAliases: new Map(),
|
||||
arts: new Map(), queryAliases: new Map(), analysisEntries: new Map(),
|
||||
}
|
||||
const events = Array.isArray(data.events) ? data.events.filter(isObj) : []
|
||||
const meta = data.meta
|
||||
@@ -1373,6 +1373,15 @@
|
||||
for (const [id, refs] of byDoc) {
|
||||
if (refs.length && !out.queryAliases.has(id)) out.queryAliases.set(id, refs[0].alias)
|
||||
}
|
||||
// 工件 → 报告目录里这条分析结论的条目(item、call_id):谁做的那一行、「在验证什么」的说法照它认
|
||||
out.analysisEntries = new Map()
|
||||
for (const [id, refs] of byDoc) {
|
||||
for (const ref of refs) {
|
||||
const doc = trusted.get(ref.report)
|
||||
const entry = own(isObj(doc) ? doc.catalog : null, ref.alias)
|
||||
if (isObj(entry) && entry.kind === 'analysis' && !out.analysisEntries.has(id)) out.analysisEntries.set(id, entry)
|
||||
}
|
||||
}
|
||||
out.arts = arts
|
||||
out.chained = chained
|
||||
// 已核对的口径卡记着的输入 → 输入指向的查询快照。卡本身核过哈希(③ 通过),它记的引用和文档的证据目录
|
||||
@@ -2032,12 +2041,17 @@
|
||||
return parts
|
||||
}
|
||||
|
||||
/** 数字详情里分析结论一节:判定语、判定标准、方法与版本、附带说明、Agent 写的假设、输入(各自的核对状态)、导出时服务端
|
||||
* 的复算结论。结论没随文件附带(遮罩、文件不在)时只写复算一句 */
|
||||
/** 数字详情里分析结论一节:判定语、判定标准、方法与版本、附带说明、「在验证什么」(谁写的照实标:Agent 写的假设 /
|
||||
* 分析卡上写的『在验证什么』,照报告目录里这条结论的条目认)、输入(各自的核对状态)、导出时服务端的复算结论。
|
||||
* 结论没随文件附带(遮罩、文件不在)时只写复算一句 */
|
||||
function analysisBlock(number) {
|
||||
const result = isObj(number.analysis) ? number.analysis : null
|
||||
const art = view.out.artifacts.find((a) => a.a.id === number.artifact)
|
||||
const recheck = art && isObj(art.a.recheck) ? art.a.recheck : null
|
||||
// 谁做的:报告目录里这条结论的条目(带 item 的是分析卡做的,带 call_id 的是 Agent 现场做的)。「在验证什么」的说法照它认,
|
||||
// 不把模板作者写的那一句标成 Agent 写的假设
|
||||
const entry = view.out.analysisEntries.get(number.artifact)
|
||||
const card = isObj(entry) ? !!entry.item && !entry.call_id : false
|
||||
const parts = []
|
||||
if (result) {
|
||||
parts.push(kv([
|
||||
@@ -2048,7 +2062,7 @@
|
||||
const caveats = (Array.isArray(result.caveats) ? result.caveats : []).filter(isObj).map((c) => String(c.text || ''))
|
||||
if (caveats.length) parts.push(h('p', { class: 'sub' }, T.dCaveats), h('ul', { class: 'items' }, caveats.map((c) => h('li', {}, c))))
|
||||
if (typeof result.hypothesis === 'string' && result.hypothesis.trim()) {
|
||||
parts.push(h('p', { class: 'sub' }, T.dHypothesis), h('p', {}, result.hypothesis))
|
||||
parts.push(h('p', { class: 'sub' }, card ? T.dCardHypothesis : T.dHypothesis), h('p', {}, result.hypothesis))
|
||||
}
|
||||
const inputs = (Array.isArray(result.inputs) ? result.inputs : []).filter((i) => isObj(i) && typeof i.artifact === 'string')
|
||||
if (inputs.length) {
|
||||
|
||||
@@ -461,7 +461,8 @@
|
||||
}, v == null ? NONE : textOf(v))))))))
|
||||
}
|
||||
|
||||
/** 分析结论 · 判定:判定语、判定标准、判定码和点名的段、附带说明、算不了的原因、这一处引用的是哪一项、谁做的、Agent 写的假设 */
|
||||
/** 分析结论 · 判定:判定语、判定标准、判定码和点名的段、附带说明、算不了的原因、这一处引用的是哪一项、谁做的、
|
||||
* 「在验证什么」(谁写的照实标:Agent 写的假设 / 分析卡上写的『在验证什么』) */
|
||||
function analysisPart(step) {
|
||||
const body = []
|
||||
const verdict = isObj(step.verdict) ? step.verdict : null
|
||||
@@ -484,7 +485,9 @@
|
||||
h('ul', { style: 'margin:4px 0 0;padding-left:1.2em;font-size:13px' }, step.caveats.map((c) => h('li', {}, String(c.text || '')))))
|
||||
}
|
||||
if (step.hypothesis) {
|
||||
body.push(h('p', { class: 'sub' }, T.dHypothesis), h('p', { style: 'margin:4px 0 0;font-size:13px' }, String(step.hypothesis)))
|
||||
// 「在验证什么」:谁写的服务端照实给(Agent 写的假设 / 分析卡上写的『在验证什么』),这里照原样显示
|
||||
body.push(h('p', { class: 'sub' }, String(step.hypothesis_label || T.dHypothesis)),
|
||||
h('p', { style: 'margin:4px 0 0;font-size:13px' }, String(step.hypothesis)))
|
||||
if (step.hypothesis_note) body.push(muted(step.hypothesis_note))
|
||||
}
|
||||
if (step.note) body.push(waiting(step.note))
|
||||
|
||||
@@ -100,6 +100,7 @@ def verdicts(bundle: dict[str, Any]) -> dict[str, Any]:
|
||||
|
||||
|
||||
def test_the_analysis_and_its_input_travel_with_the_file_and_verify():
|
||||
"""Agent 现场做的结论(台账条目带 call_id):那一句「在验证什么」标成「Agent 写的假设」。"""
|
||||
bundle, files, a = bundle_of()
|
||||
analysis_item = item(bundle, a)
|
||||
assert analysis_item["kind"] == ARTIFACT_KIND and "b64" in analysis_item and analysis_item["node_id"] == "an"
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
真的 recompute:按 sha256 取回封存的输入快照、下钻的上一层结论,逐字段比。只有要它出错、升版的几处用 monkeypatch。
|
||||
|
||||
- 证据图:A1 条目带算子、判定;「派生自」的边 A1 → Q1
|
||||
- 片段接口:判定 → 方法 → 计算 → 输入(接查询步骤)→ 复算 → 封存;Agent 写的假设标出来;复算不了照实写,不让接口出错
|
||||
- 片段接口:判定 → 方法 → 计算 → 输入(接查询步骤)→ 复算 → 封存;「在验证什么」谁写的照实标(Agent 写的假设 / 分析卡上
|
||||
写的『在验证什么』);复算不了照实写,不让接口出错
|
||||
- 审计:分析判定、分析结论的叫法;分析说法核对的违规单列一行
|
||||
- 报告导出:数据块里有分析结论那几步;文档带「分析范围」的,正文后面渲染、编号点得开
|
||||
- 指标步骤带可比性:口径卡指标上的可比性结论(不进台账)照卡上记的 sha256 取回,点得开(判定 → … → 复算 → 封存)
|
||||
@@ -135,7 +136,9 @@ async def test_the_phrase_opens_judgment_method_calculation_inputs_recompute_and
|
||||
assert judged["verdict"] == {"code": "driver", "subjects": [["华东"]], "direction": "down"}
|
||||
assert judged["cited"] == {"what": "phrase"} and judged["render_ok"] is True and judged["eid_ok"] is True
|
||||
assert judged["origin"] == "card" and judged["item"] == "drop" and judged["label"] == "分析"
|
||||
assert judged["hypothesis"] == "华东拖累" and judged["hypothesis_note"].startswith("Agent 写的假设")
|
||||
# 分析卡做的:模板作者写的「在验证什么」,不标成 Agent 写的假设
|
||||
assert judged["hypothesis"] == "华东拖累" and judged["hypothesis_label"] == "分析卡上写的『在验证什么』"
|
||||
assert judged["hypothesis_note"].startswith("分析卡上写的『在验证什么』")
|
||||
assert {c["code"] for c in judged["caveats"]} == {"measure_unlabeled", "headline_basis", "comparability"}
|
||||
assert method["method"] == "decompose.additive@1" and method["method_label"] == "变化拆解(可加)"
|
||||
assert {s["key"]: s["label"] for s in method["settings"]}["main_share"] == "「主要来源」的占比"
|
||||
@@ -307,9 +310,12 @@ def test_suspicious_name_hints_do_not_read_the_analysis_results(monkeypatch):
|
||||
|
||||
|
||||
async def test_agent_analyses_are_marked_as_such(client):
|
||||
"""Agent 现场做的:谁做的写 Agent,「在验证什么」照旧标「Agent 写的假设」(分析卡上那一句是模板作者写的,另说)"""
|
||||
made = await sealed_run(TEXT, item=None, call_id="call-9")
|
||||
body = (await client.get(f"/api/runs/{made['run']}/evidence/segments/{seg_id(made['doc'], 'a:A1')}")).json()
|
||||
assert body["chain"][0]["origin"] == "agent" and body["chain"][0]["call_id"] == "call-9"
|
||||
judged = body["chain"][0]
|
||||
assert judged["origin"] == "agent" and judged["call_id"] == "call-9"
|
||||
assert judged["hypothesis_label"] == "Agent 写的假设" and judged["hypothesis_note"].startswith("Agent 写的假设")
|
||||
|
||||
|
||||
async def test_headline_inputs_show_the_closure(client):
|
||||
|
||||
@@ -147,7 +147,8 @@ async def test_the_export_page_opens_the_analysis_steps_and_the_scope_numbers():
|
||||
"analysis_recompute", "analysis_seal"]
|
||||
assert opened["title"].startswith("判定「销售额下降")
|
||||
body = opened["body"]
|
||||
for text in ("判定标准一段占总变化的一半以上算主要来源", "Agent 写的假设华东拖累", "实际用的阈值", "「主要来源」的占比",
|
||||
# 分析卡做的结论(台账条目带 item):那一句是模板作者写的,照实写「分析卡上写的『在验证什么』」,不标成 Agent 写的假设
|
||||
for text in ("判定标准一段占总变化的一半以上算主要来源", "分析卡上写的『在验证什么』华东拖累", "实际用的阈值", "「主要来源」的占比",
|
||||
"华东的占比 = 华东的变化 ÷ 总变化 = -120 ÷ (-194) = 61.9%", "结果表(列出 4 行,共 4 行)",
|
||||
"复算一致:按封存的输入重新计算,结论逐项相同", "封存范围内的台账记过这份分析结论",
|
||||
"按运行当天现算的界 date('now', '-7 days') = 2026-10-14(现查 · 2026-10-21T09:00:00)",
|
||||
@@ -186,6 +187,8 @@ async def test_the_bundle_page_shows_the_analysis_detail_and_the_scope():
|
||||
# 方法写服务端带来的叫法和 id(和导出页同一个写法),不只写 id
|
||||
assert "判定语销售额下降 194(-8.7%)" in phrase and "方法与版本变化拆解(可加) · decompose.additive@1" in phrase
|
||||
assert "输入数据 · Q1" in phrase # 输入的角色写叫法,不写 data
|
||||
# 这份结论是分析卡做的(台账条目带 item):那一句「在验证什么」写「分析卡上写的『在验证什么』」,不标成 Agent 写的假设
|
||||
assert "分析卡上写的『在验证什么』" in phrase and "Agent 写的假设" not in phrase
|
||||
assert "复算一致:按封存的输入重新计算,结论逐项相同(导出时服务端按封存的输入复算的结论;本页只核哈希" in phrase
|
||||
value = next(text for text in out["opened"].values() if "具名的数「top_share」" in text)
|
||||
assert "引用的值0.618556701031" in value and "正文显示61.9%(与按显示规则渲染的结果一致)" in value
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
* 的数、说法违规的原话都是服务端写好的,界面照原样显示,不按判定码、原因码自己拼。规矩同 terms.ts 开头的术语表。
|
||||
*
|
||||
* 术语:一次分析的结果叫「分析结论」,编号 A1、A2……;系统写的那一句叫「判定语」;判定的依据叫「判定标准」;做不成的叫「没有做成」
|
||||
* (服务端判定语的写法),原因叫「算不了的原因」;写错的调用叫「调用有误」,不记成结论;Agent 写的那句叫「Agent 写的假设」。
|
||||
* (服务端判定语的写法),原因叫「算不了的原因」;写错的调用叫「调用有误」,不记成结论;「这次在验证什么」那一句谁写的照实说:
|
||||
* Agent 现场做的那句叫「Agent 写的假设」,分析卡上那条是模板作者写的,叫「分析卡上写的『在验证什么』」。
|
||||
*/
|
||||
import { formatNumber } from './format'
|
||||
|
||||
@@ -261,6 +262,7 @@ export const ANALYSIS_TEXT = {
|
||||
citedCell: (row: number, column: string) => `结果表第 ${formatNumber(row + 1)} 行「${column}」`,
|
||||
who: '谁做的',
|
||||
origin: { card: '分析卡(模板定好的分析)', agent: 'Agent 现场做的分析', metric: '口径卡执行时自动做的可比性检查' } as Record<string, string>,
|
||||
/** 「在验证什么」那一行:服务端按谁写的给说法(Agent 写的是假设,分析卡上那一条是模板作者写的),照原样显示 */
|
||||
hypothesis: 'Agent 写的假设',
|
||||
refused: '这次分析没有做成',
|
||||
renderOk: '与按结论渲染的结果一致',
|
||||
|
||||
@@ -135,7 +135,7 @@ function JudgedPart({ step, recompute, seal, overall }: {
|
||||
{step.caveats.map((c, i) => <li key={`${c.code ?? ''}-${i}`}>{c.text}</li>)}
|
||||
</ul>
|
||||
)] : null,
|
||||
step.hypothesis ? [E.hypothesis, (
|
||||
step.hypothesis ? [step.hypothesis_label || E.hypothesis, (
|
||||
<span key="h" data-ev-analysis-hypothesis="">
|
||||
{step.hypothesis}
|
||||
{step.hypothesis_note && <span className="mt-0.5 block text-2xs text-faint">{step.hypothesis_note}</span>}
|
||||
|
||||
@@ -673,7 +673,8 @@
|
||||
}
|
||||
],
|
||||
"hypothesis": "下降是不是集中在某个地区",
|
||||
"hypothesis_note": "Agent 写的假设:说明这次在验证什么,不是分析结论,也不进报告正文"
|
||||
"hypothesis_note": "Agent 写的假设:说明这次在验证什么,不是分析结论,也不进报告正文",
|
||||
"hypothesis_label": "Agent 写的假设"
|
||||
},
|
||||
{
|
||||
"step": "analysis_method",
|
||||
@@ -1326,7 +1327,8 @@
|
||||
}
|
||||
],
|
||||
"hypothesis": "下降是不是集中在某个地区",
|
||||
"hypothesis_note": "Agent 写的假设:说明这次在验证什么,不是分析结论,也不进报告正文"
|
||||
"hypothesis_note": "Agent 写的假设:说明这次在验证什么,不是分析结论,也不进报告正文",
|
||||
"hypothesis_label": "Agent 写的假设"
|
||||
},
|
||||
{
|
||||
"step": "analysis_method",
|
||||
@@ -1984,7 +1986,8 @@
|
||||
}
|
||||
],
|
||||
"hypothesis": "下降是不是集中在某个地区",
|
||||
"hypothesis_note": "Agent 写的假设:说明这次在验证什么,不是分析结论,也不进报告正文"
|
||||
"hypothesis_note": "Agent 写的假设:说明这次在验证什么,不是分析结论,也不进报告正文",
|
||||
"hypothesis_label": "Agent 写的假设"
|
||||
},
|
||||
{
|
||||
"step": "analysis_method",
|
||||
@@ -3280,7 +3283,8 @@
|
||||
}
|
||||
],
|
||||
"hypothesis": "下降是不是集中在某个地区",
|
||||
"hypothesis_note": "Agent 写的假设:说明这次在验证什么,不是分析结论,也不进报告正文"
|
||||
"hypothesis_note": "Agent 写的假设:说明这次在验证什么,不是分析结论,也不进报告正文",
|
||||
"hypothesis_label": "Agent 写的假设"
|
||||
},
|
||||
{
|
||||
"step": "analysis_method",
|
||||
@@ -3871,7 +3875,8 @@
|
||||
"verdict": null,
|
||||
"caveats": [],
|
||||
"hypothesis": "这周的下降算不算异常",
|
||||
"hypothesis_note": "Agent 写的假设:说明这次在验证什么,不是分析结论,也不进报告正文"
|
||||
"hypothesis_note": "Agent 写的假设:说明这次在验证什么,不是分析结论,也不进报告正文",
|
||||
"hypothesis_label": "Agent 写的假设"
|
||||
},
|
||||
{
|
||||
"step": "analysis_method",
|
||||
@@ -4075,7 +4080,8 @@
|
||||
},
|
||||
"caveats": [],
|
||||
"hypothesis": "两周能不能直接比",
|
||||
"hypothesis_note": "Agent 写的假设:说明这次在验证什么,不是分析结论,也不进报告正文"
|
||||
"hypothesis_note": "Agent 写的假设:说明这次在验证什么,不是分析结论,也不进报告正文",
|
||||
"hypothesis_label": "Agent 写的假设"
|
||||
},
|
||||
{
|
||||
"step": "analysis_method",
|
||||
@@ -5189,7 +5195,8 @@
|
||||
}
|
||||
],
|
||||
"hypothesis": "下降是不是集中在某个地区",
|
||||
"hypothesis_note": "Agent 写的假设:说明这次在验证什么,不是分析结论,也不进报告正文"
|
||||
"hypothesis_note": "分析卡上写的『在验证什么』:模板作者写的那一句,不是分析结论,也不进报告正文",
|
||||
"hypothesis_label": "分析卡上写的『在验证什么』"
|
||||
},
|
||||
{
|
||||
"step": "analysis_method",
|
||||
@@ -6082,7 +6089,8 @@
|
||||
}
|
||||
],
|
||||
"hypothesis": "下降是不是集中在某个地区",
|
||||
"hypothesis_note": "Agent 写的假设:说明这次在验证什么,不是分析结论,也不进报告正文"
|
||||
"hypothesis_note": "分析卡上写的『在验证什么』:模板作者写的那一句,不是分析结论,也不进报告正文",
|
||||
"hypothesis_label": "分析卡上写的『在验证什么』"
|
||||
},
|
||||
{
|
||||
"step": "analysis_method",
|
||||
@@ -6740,7 +6748,8 @@
|
||||
}
|
||||
],
|
||||
"hypothesis": "下降是不是集中在某个地区",
|
||||
"hypothesis_note": "Agent 写的假设:说明这次在验证什么,不是分析结论,也不进报告正文"
|
||||
"hypothesis_note": "分析卡上写的『在验证什么』:模板作者写的那一句,不是分析结论,也不进报告正文",
|
||||
"hypothesis_label": "分析卡上写的『在验证什么』"
|
||||
},
|
||||
{
|
||||
"step": "analysis_method",
|
||||
@@ -7924,7 +7933,8 @@
|
||||
}
|
||||
],
|
||||
"hypothesis": "下降是不是集中在某个地区",
|
||||
"hypothesis_note": "Agent 写的假设:说明这次在验证什么,不是分析结论,也不进报告正文"
|
||||
"hypothesis_note": "分析卡上写的『在验证什么』:模板作者写的那一句,不是分析结论,也不进报告正文",
|
||||
"hypothesis_label": "分析卡上写的『在验证什么』"
|
||||
},
|
||||
{
|
||||
"step": "analysis_method",
|
||||
@@ -9453,4 +9463,4 @@
|
||||
"declared_at": "2026-10-21T10:36:37.326911+00:00"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2448,6 +2448,8 @@ export interface EvidenceAnalysisStep {
|
||||
verdict?: AnalysisVerdict | null
|
||||
caveats?: AnalysisCaveat[]
|
||||
hypothesis?: string
|
||||
/** 「在验证什么」那一行的说法:谁写的照实说,服务端按台账条目给(Agent 写的假设 / 分析卡上写的『在验证什么』) */
|
||||
hypothesis_label?: string
|
||||
hypothesis_note?: string
|
||||
note?: string
|
||||
// ---- analysis_method:方法、参数、实际用的阈值、现查结果 ----
|
||||
|
||||
@@ -927,8 +927,9 @@ await section('样本页:各种形状', async () => {
|
||||
check('analysis:点开判定语:判定语、判定标准、方法与版本(服务端带的叫法)', detail.includes('判定语')
|
||||
&& detail.includes('一段占总变化的一半以上算主要来源') && detail.includes('变化拆解(可加) · decompose.additive@1'),
|
||||
detail.replace(/\s+/g, ' ').slice(0, 300))
|
||||
// 这三份分析都是 Agent 现场做的(台账条目带 call_id):那一句照旧标「Agent 写的假设」
|
||||
check('analysis:……附带说明、Agent 写的假设', detail.includes('附带说明') && detail.includes('Agent 写的假设')
|
||||
&& detail.includes('下降是不是集中在某个地区'), detail.replace(/\s+/g, ' ').slice(0, 400))
|
||||
&& !detail.includes('分析卡上写的『在验证什么』') && detail.includes('下降是不是集中在某个地区'), detail.replace(/\s+/g, ' ').slice(0, 400))
|
||||
check('analysis:……输入(角色、编号、各自的核对状态)', ['基期总数 · Q1', '本期总数 · Q1', '数据 · Q2'].every((t) => detail.includes(t)),
|
||||
detail.replace(/\s+/g, ' ').slice(0, 500))
|
||||
check('analysis:……复算写导出时服务端复算的结论、本页不重算统计', detail.includes('复算一致:按封存的输入重新计算,结论逐项相同')
|
||||
|
||||
@@ -645,6 +645,10 @@ await section('analysis', '分析结论:判定语、具名的数、结果表
|
||||
await p.locator('[data-ev-analysis="A2"]').waitFor({ timeout: 8000 })
|
||||
check('分析卡的结论:谁做的写「分析卡(模板定好的分析)」', (await p.locator('[data-ev-analysis-origin]').getAttribute('data-ev-analysis-origin')) === 'card'
|
||||
&& (await p.locator('[data-ev-analysis="A2"]').innerText()).includes('分析卡(模板定好的分析)'))
|
||||
// 「在验证什么」那一句是模板作者写的:照实写「分析卡上写的『在验证什么』」,不标成 Agent 写的假设
|
||||
const cardBody = await p.locator('[data-ev-analysis="A2"]').innerText()
|
||||
check('……「在验证什么」写「分析卡上写的『在验证什么』」,不说 Agent 写的假设', cardBody.includes('分析卡上写的『在验证什么』')
|
||||
&& !cardBody.includes('Agent 写的假设'), cardBody.slice(-160))
|
||||
await card.locator('[data-seg="s6"]').click()
|
||||
await p.locator('[data-ev-analysis="A1"]').waitFor({ timeout: 8000 })
|
||||
check('算不了的结论:标「这次分析没有做成」、写算不了的原因', await p.locator('[data-ev-analysis-refused]').count() === 1
|
||||
|
||||
Reference in New Issue
Block a user