fix(consult): option B for #182 - cells split on 。!?; only, no name carry (#182 needs ruling, BUG-1825)
be9b2e91 carried names across cells and past semicolons, which flagged
9 phrases in staging answers the human check rated correct (b4yoga spot
set). Option B: inside a table cell split on 。!?; only (not commas)
and never carry names. Spot set: new arm 0 mismatches, old arm keeps the
2 real ones (Amala, Saraswati). Also fixes the 5 tsc TS2339 errors.
Prototype for the owner's ruling; not merged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
This commit is contained in:
@@ -353,8 +353,8 @@ export function findAnswerFactMismatches(answer: string, card: EvidenceCard): An
|
||||
});
|
||||
}
|
||||
|
||||
/** 分句:。!?;,, 与换行;括号里的标点不断句。表格行先按 | 分格,格内再按同一套句读分句。 */
|
||||
function splitProse(line: string, base = 0): Array<{ start: number; end: number }> {
|
||||
/** 分句:正文按 。!?;,, 与换行;表格行先按 | 分格,格内只按 。!?; 与换行分句(不按逗号,也不跨句沿用名字)。括号里的标点不断句。 */
|
||||
function splitProse(line: string, base = 0, breaks = /[。!?;,,\n]/u): Array<{ start: number; end: number }> {
|
||||
const out: Array<{ start: number; end: number }> = [];
|
||||
let depth = 0;
|
||||
let start = 0;
|
||||
@@ -363,7 +363,7 @@ function splitProse(line: string, base = 0): Array<{ start: number; end: number
|
||||
const char = line[index]!;
|
||||
if (char === "(" || char === "(") depth += 1;
|
||||
else if (char === ")" || char === ")") depth = Math.max(0, depth - 1);
|
||||
else if (depth === 0 && /[。!?;,,\n]/u.test(char)) {
|
||||
else if (depth === 0 && breaks.test(char)) {
|
||||
push(index);
|
||||
start = index + 1;
|
||||
}
|
||||
@@ -377,7 +377,7 @@ function yogaSentences(line: string): Array<{ start: number; end: number }> {
|
||||
const out: Array<{ start: number; end: number }> = [];
|
||||
let base = 0;
|
||||
for (const cell of line.split("|")) {
|
||||
out.push(...splitProse(cell, base));
|
||||
out.push(...splitProse(cell, base, /[。!?;\n]/u));
|
||||
base += cell.length + 1;
|
||||
}
|
||||
return out;
|
||||
@@ -430,14 +430,10 @@ function yogaWordClass(sentence: string): { kind: "affirm" | "deny"; word: strin
|
||||
function checkYogaStatus(line: string, offset: number, view: CardView, push: Emit) {
|
||||
const entries = Object.entries(view.yogas ?? {});
|
||||
if (!entries.length) return;
|
||||
const table = line.trimStart().startsWith("|");
|
||||
// 表格一格内的状态词可以落在同格后面的子句里(「Amala、Saraswati 等为 computed,不成立」),
|
||||
// 所以同一格里记住刚提到的格局名;正文不跨句继承。
|
||||
let carried: Array<{ entry: YogaCardEntry; name: string }> = [];
|
||||
for (const sentence of yogaSentences(line)) {
|
||||
const text = line.slice(sentence.start, sentence.end);
|
||||
if (!text.trim()) continue;
|
||||
const found: Array<{ entry: YogaCardEntry & { pattern: RegExp }; name: string }> = [];
|
||||
const found: Array<{ entry: Exclude<YogaCardEntry, { ambiguous: true }>; name: string }> = [];
|
||||
for (const [, entry] of entries) {
|
||||
if ("ambiguous" in entry) continue;
|
||||
for (const hit of text.matchAll(entry.pattern)) {
|
||||
@@ -448,10 +444,8 @@ function checkYogaStatus(line: string, offset: number, view: CardView, push: Emi
|
||||
}
|
||||
}
|
||||
const wordClass = yogaWordClass(text);
|
||||
const targets = found.length ? found : (table ? carried : []);
|
||||
if (found.length) carried = found;
|
||||
if (!wordClass || !targets.length) continue;
|
||||
for (const { entry, name } of targets) {
|
||||
if (!wordClass || !found.length) continue;
|
||||
for (const { entry, name } of found) {
|
||||
const matches = (entry.key === "formed_under_source" && wordClass.kind === "affirm")
|
||||
|| (entry.key === "conditions_not_met" && wordClass.kind === "deny");
|
||||
const at = offset + sentence.start + wordClass.at;
|
||||
@@ -469,7 +463,6 @@ function checkYogaStatus(line: string, offset: number, view: CardView, push: Emi
|
||||
end: at + wordClass.word.length,
|
||||
}, matches ? "match" : "mismatch");
|
||||
}
|
||||
if (!table) carried = [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -318,3 +318,17 @@ test("a table cell splits by sentence inside the cell, so neighbours are not bla
|
||||
assert.deepEqual(found.map((item) => item.entity).sort(), ["Amala Yoga", "Saraswati Yoga"]);
|
||||
for (const item of found) assert.equal(item.claimed, "不成立");
|
||||
});
|
||||
|
||||
// 验收第 2 次(Claude 2026-11-11):be9b2e91 的「同格沿用名字」跨格、跨分号沿用,
|
||||
// 在 b4yoga 抽查的 staging 正确回答上误拦 9 条。下面三句都取自那批回答,均应 0 条不符。
|
||||
test("names never carry into the next cell or past a semicolon", () => {
|
||||
const evidence = card([
|
||||
{ name: "Sunaphaa Yoga", status: "candidate" },
|
||||
{ name: "Vosi Yoga", status: "candidate" },
|
||||
{ name: "Amala Yoga", status: "computed" },
|
||||
{ name: "Saraswati Yoga", status: "computed" },
|
||||
], ["Sunaphaa Yoga", "Vosi Yoga", "Amala Yoga", "Saraswati Yoga"]);
|
||||
assert.deepEqual(mismatches("| Yoga | Amala、Saraswati 为检测器检出、待核实;其余 computed 行同 | 都不升格为「成立」,只作观察 |", evidence), []);
|
||||
assert.deepEqual(mismatches("| Yoga | Vosi、Sunaphaa 为候选;三条规则未实现 | 不升级为格局成立,只作方向观察 |", evidence), []);
|
||||
assert.deepEqual(mismatches("| Yoga | conditional | hits 仅 Vosi、Sunaphaa,均 candidate;其余为 computed,不成立 | 只作支持层 |", evidence), []);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user