M2 时间线认得报告引用了遮罩列的那一行:decode.ts 把日志 report_masked_cell 说成「报告引用了 N 处取自遮罩列的格子,已标注」,副标题点名引用(不写值),下一步说出具已降档、去改写作指令;证据面板的违规清单给 masked_cell 一个自己的叫法「引用了遮罩列」,不再落成「文档核对未通过」

文案放在 terms.ts 新块 MASKED_CELL_TEXT;check-decode.mjs 加一节守住后端字段(count、refs、columns)、标题、副标题、缺字段时的说法。
This commit is contained in:
ThearchyHelios
2026-10-07 00:24:19 +08:00
parent fa50456e0f
commit 3e0aacac18
4 changed files with 57 additions and 2 deletions
+11
View File
@@ -247,6 +247,17 @@ export const ABSENCE_CLAIM_TEXT = {
+ '或换用上下文窗口更大的写作模型后重新运行',
}
/**
* 报告直接引用了取自遮罩列的格子(报告自查的 masked_cell;c.phone AS tel 这种改了名字的也算),重写后仍在、
* 「违规处置」为标注时照常产出:时间线上那一行(日志 report_masked_cell)和证据面板违规清单里的叫法
*/
export const MASKED_CELL_TEXT = {
label: '引用了遮罩列',
title: (n?: number) => `报告引用了${n ? ` ${formatNumber(n)} 处` : ''}取自遮罩列的格子,已标注`,
next: '数据源设置了遮罩的列不应写进报告,这几处的值会随报告出具,出具已按缺口降档。'
+ '请在报告撰写节点的指令中去掉对这些列的引用后重新运行',
}
/** 证据面板和证据条的文案 */
export const EVIDENCE_TEXT = {
allCited: (n: number) => `${formatNumber(n)} 个数字都有出处`,
+2 -1
View File
@@ -19,7 +19,7 @@ import {
import { humanizeError } from '../lib/errors'
import { formatDateTime, formatNumber, NONE, shortId } from '../lib/format'
import {
ABSENCE_CLAIM_TEXT, CHALLENGE_TEXT, DUAL_CHECK_TEXT, EVIDENCE_TEXT, JUDGE_TEXT, MERGE_TEXT, NODE_TYPE_LABEL, RUN_SQL_CHECK_TEXT,
ABSENCE_CLAIM_TEXT, CHALLENGE_TEXT, DUAL_CHECK_TEXT, EVIDENCE_TEXT, JUDGE_TEXT, MASKED_CELL_TEXT, MERGE_TEXT, NODE_TYPE_LABEL, RUN_SQL_CHECK_TEXT,
SQL_CHECK_TEXT, nodeTypeLabel,
} from '../lib/terms'
import { useCatalog } from '../store/catalog'
@@ -1835,6 +1835,7 @@ const CODE_LABEL: Record<string, string> = {
unknown_entity: '疑似不存在的名称',
unverified_entity: '无法核实的名称',
absence_claim: ABSENCE_CLAIM_TEXT.label,
masked_cell: MASKED_CELL_TEXT.label,
}
/** 违规清单:报告撰写节点核对出来的全部问题,画得出线的能定位,画不出的说清在哪 */
+12 -1
View File
@@ -3,7 +3,7 @@ import type { NodeState, RunPhase } from './trace'
import { formatDuration, formatNumber } from '../lib/format'
import {
ABSENCE_CLAIM_TEXT, CATALOG_DRIFT_TEXT, CATALOG_PATCH_TEXT, COPILOT_CONTEXT_TEXT, JUDGE_TEXT, MERGE_TEXT, RUN_SQL_CHECK_TEXT, SCHEMA_PARTIAL_TEXT, SQL_CHECK_TEXT, TYPE_LABEL,
CATALOG_TABLE_FIELD_LABEL, CHALLENGE_TEXT, DUAL_CHECK_TEXT, INQUIRY_TEXT, JUDGE_TRUNCATED_TEXT, NODE_TYPE_LABEL,
CATALOG_TABLE_FIELD_LABEL, CHALLENGE_TEXT, DUAL_CHECK_TEXT, INQUIRY_TEXT, JUDGE_TRUNCATED_TEXT, MASKED_CELL_TEXT, NODE_TYPE_LABEL,
VERIFY_TRUNCATED_TEXT,
claimTally,
evidenceTally, issuanceLabel, nodeTypeLabel,
@@ -873,6 +873,17 @@ function explainLog(code: string | undefined, message: string, d: Record<string,
next: ABSENCE_CLAIM_TEXT.next,
}
}
case 'report_masked_cell': {
// 报告引用了取自遮罩列的格子,重写后仍在、照常产出(report.py):读结构化字段 count、refs,副标题只点名引用,
// 不写那几格的值(后端也没给)
const n = typeof d.count === 'number' && d.count > 0 ? d.count : undefined
const refs = strs(d.refs)
return {
title: MASKED_CELL_TEXT.title(n),
sub: refs.length ? refs.map((r) => `[[${r}]]`).join('、') : undefined,
next: MASKED_CELL_TEXT.next,
}
}
case 'report_catalog_trimmed': {
// 写作目录超出篇幅(report.py _trimmed_message)。读结构化字段(queries、omitted、nodes),不从原话里认
const total = typeof d.queries === 'number' ? d.queries : undefined
+32
View File
@@ -1377,6 +1377,38 @@ await section('报告核对 report.checked、口径卡的台账(可点击证
&& !!rcAbsent?.detail?.includes('缺失断言') && !!rcAbsent?.detail?.includes('依据不足'), `${rcAbsent?.status} ${rcAbsent?.detail}`)
})
await section('报告引用了取自遮罩列的格子(report_masked_cell):标题说几处、已标注,副标题点名引用,不写那几格的值', async () => {
// 契约:data = {level: warn, code: report_masked_cell, message, count, refs, columns},重写后仍在、「违规处置」为标注时才发
const E = (seq, type, node_id, data = {}) => ({ seq, type, node_id, ts: 1790000000 + seq, data })
const reportPy = readFileSync(`${root}backend/app/engine/nodes/report.py`, 'utf8')
check('后端发引用了遮罩列的警告,带着 count、refs、columns', reportPy.includes('code="report_masked_cell"')
&& reportPy.includes('count=len(hits), refs=refs') && reportPy.includes('columns=list(dict.fromkeys('),
'改了 report.py 的字段就同步改 decode.ts 的 explainLog 和这里的夹具')
const MASKED = '报告引用了 2 处取自遮罩列的格子(「v:Q2.r0.tel」、「v:Q2.r1.tel」),已要求模型重写 1 次仍未改掉,这些值会随报告出具。'
+ '报告照常产出,这几处已标注:数据源设置了遮罩的列不应写进报告,请在报告撰写节点的指令中去掉对这些列的引用'
const steps = flatten(mod.decodeRun([E(1, 'node.started', 'w', { node_type: 'report', label: '写报告' }),
E(2, 'log', 'w', { level: 'warn', code: 'report_masked_cell', message: MASKED, count: 2,
refs: ['v:Q2.r0.tel', 'v:Q2.r1.tel'], columns: ['tel'] }),
E(3, 'report.checked', 'w', { doc_artifact: 'abc', repairs: 1, ok: false, on_violation: 'flag', failed: false,
stats: { numbers: 1, numbers_cited: 1, uncited_numbers: 0, unresolved: 0 },
violations: [{ code: 'masked_cell', ref: 'v:Q2.r0.tel', column: 'tel',
message: '引用了取自遮罩列的格子 [[v:Q2.r0.tel]]:列「tel」取自数据源中设置了遮罩的列,值不应写进报告' }] }),
]))
const mc = steps.find((s) => s.code === 'report_masked_cell')
check('标题说几处引用了遮罩列、已标注', mc?.title === '报告引用了 2 处取自遮罩列的格子,已标注', mc?.title)
check('……副标题点名那几处引用(不写值)', mc?.sub === '[[v:Q2.r0.tel]]、[[v:Q2.r1.tel]]', mc?.sub)
check('……下一步说遮罩列不应写进报告、出具已降档、去改指令;是提醒(warn),原话留在展开区',
!!mc?.next?.includes('不应写进报告') && !!mc?.next?.includes('降档') && !!mc?.next?.includes('指令')
&& mc?.level === 'warn' && mc?.detail === MASKED, mc?.next)
const rc = steps.find((s) => s.code === 'report_checked')
check('……核对那一行照常完成(标注,不判失败),违规清单里写着这一条的说明', rc?.status === 'done'
&& !!rc?.detail?.includes('取自数据源中设置了遮罩的列'), `${rc?.status} ${rc?.detail}`)
const bare = flatten(mod.decodeRun([E(1, 'log', 'w', { level: 'warn', code: 'report_masked_cell', message: '报告引用了遮罩列' })]))
.find((s) => s.code === 'report_masked_cell')
check('……缺字段时标题照样说人话,不出 undefined', bare?.title === '报告引用了取自遮罩列的格子,已标注'
&& bare?.sub === undefined, `${bare?.title} / ${bare?.sub}`)
})
await section('工具门控 tool.gated(工具信任三档)', async () => {
// 契约:data = {tool, verdict: allow|escalate, reason, model, duration_ms, call_id?, agent?},node_id 是所在节点
const E = (seq, type, node_id, data = {}) => ({ seq, type, node_id, ts: 1790000000 + seq, data })