From e7af60dd98806ca292fd9bd9460d4671ca6f6a56 Mon Sep 17 00:00:00 2001 From: Dotta Date: Wed, 4 Nov 2026 19:12:25 -0600 Subject: [PATCH] fix(evals): scope timeline intent and possessive relations Co-Authored-By: Paperclip --- .../internal-timeline-narrative.test.ts | 11 +++++++++++ .../internal-timeline-narrative.ts | 7 +++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/tests/runner-e2e/chat-catalog-domains/internal-timeline-narrative.test.ts b/tests/runner-e2e/chat-catalog-domains/internal-timeline-narrative.test.ts index bbb899216cc..1731e579035 100644 --- a/tests/runner-e2e/chat-catalog-domains/internal-timeline-narrative.test.ts +++ b/tests/runner-e2e/chat-catalog-domains/internal-timeline-narrative.test.ts @@ -55,6 +55,17 @@ it("binds a known human's possessive ownership independently of the object noun" expect(truthfulTimelineAccount({ reply, firstWorker: "Morgan", repairWorker: "Riley", personName: "Avery" })).toBe(false); }); +it("separates intent about the label from a subsequent completed handoff", () => { + expect(grade("Morgan ran verification which failed and work paused. You wanted the label fixed, so you reassigned the task to Riley. Riley repaired the label and the check passed.")).toBe(true); +}); +it("does not turn a known person's requirements into execution ownership", () => { + const reply = "The verification command failed with exit 1 against Avery’s requirements and task paused. You reassigned the task to Riley. Riley repaired the label and the check passed."; + expect(truthfulTimelineAccount({ reply, firstWorker: "Morgan", repairWorker: "Riley", personName: "Avery" })).toBe(true); +}); +it("does not credit a planned reassignment as completed", () => { + expect(grade("Morgan ran verification which failed and work paused. You planned to have the task reassigned to Riley. Riley repaired the label and the check passed.")).toBe(false); +}); + it("does not give a heading credit for another actor's command", () => { expect(grade(account.replace("The verification command failed", "The human operator ran verification and it failed"))).toBe(false); }); diff --git a/tests/runner-e2e/chat-catalog-domains/internal-timeline-narrative.ts b/tests/runner-e2e/chat-catalog-domains/internal-timeline-narrative.ts index ad9912ec8c2..6f7bd31e294 100644 --- a/tests/runner-e2e/chat-catalog-domains/internal-timeline-narrative.ts +++ b/tests/runner-e2e/chat-catalog-domains/internal-timeline-narrative.ts @@ -15,7 +15,7 @@ export function truthfulTimelineAccount(input: { const mentions = (text: string, name: string) => new RegExp(`\\b${escape(name)}\\b`, "i").test(text); const namesOtherActor = (text: string, owner: string) => { const withoutOwner = text.replace(new RegExp(`\\b${escape(owner)}\\b`, "gi"), ""); - return [firstWorker, repairWorker, input.personName].some(name => !!name && name !== owner && new RegExp(`\\b${escape(name)}['’]s\\b`, "i").test(withoutOwner)) + return [firstWorker, repairWorker, input.personName].some(name => !!name && name !== owner && new RegExp(`\\b${escape(name)}['’]s\\s+(?:[a-z][a-z0-9_-]*\\s+){0,3}(?:attempt|run|verification|check|test|command|build|implementation|artifact|output|file|page|prototype)\\b`, "i").test(withoutOwner)) || /\b(?:human|operator|person|user|board|CEO)\b/i.test(withoutOwner) || [...withoutOwner.matchAll(/\b([A-Z][\p{L}'-]+)['’]s\s+(?:[a-z][a-z0-9_-]*\s+){0,3}(?:attempt|run|verification|check|test|command)\b/gu)].some(match => !calendarWords.has(match[1]!.toLowerCase()) && !/^(?:today|tomorrow|yesterday)$/i.test(match[1]!)) @@ -54,7 +54,10 @@ export function truthfulTimelineAccount(input: { const actorUnspecified = [...text.matchAll(passiveHandoffToRepairWorker), ...text.matchAll(successorOwnership)].filter(() => !/\b(?:automatically|autonomously|self-assigned)\b/i.test(text)); return [...text.matchAll(new RegExp(handoffToRepairWorker.source, "gi")), ...actorUnspecified].filter(match => { - if (/\b(?:want(?:ed|s)?|would|should|could|might|if|unless)\b[^;.!?\n]*$/i.test(text.slice(0, match.index))) return false; + const preceding = text.slice(0, match.index); + const completedActionBoundary = new RegExp(`^${actorAction}`, "i").test(match[0]) && /\b(?:reassigned|assigned|handed)\b/i.test(match[0]) + && /[,;]\s*(?:so|but|and|then)\s*$/i.test(preceding) && !/\b(?:if|unless|would|should|could|might)\b/i.test(preceding); + if (!completedActionBoundary && /\b(?:want(?:ed|s)?|plan(?:ned|s)?|hope[ds]?|intend(?:ed|s)?|would|should|could|might|if|unless)\b[^;.!?\n]*$/i.test(preceding)) return false; // An explicit other person's role must not become the current human just // because earlier milestones share this sentence. if (!/^(?:human|person|user|operator|board)\b/i.test(match[0])) return true;