test(evals): recognize current unresolved team skill conflicts

Accept truthful exact-skill unresolved installation reports while rejecting unrelated or denied conflicts and independent current recovery claims. Keep saved state, actor, phase, links and original bounds strict.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-11-06 00:20:54 -06:00
1 parent bf311b939b
commit 88c4f35718
5 files changed
+38 -4

No files matched your search

+9
View File
@@ -489,3 +489,12 @@ Menu evidence labels the parameter as `expectedDefinitionId`; the observed UI pr
is the current-company route and visible definition key. Private entry retains the
independent exact-ID/current-owner check. Delayed flyout and own-entry visibility
are awaited within the same passed navigation deadline.
Team install v8 accepts a current, exact-skill unresolved installation or slug-conflict
report when the saved required skill is still missing. Independent current recovery
claims and all-skills-installed claims still fail. Result 5171 remains originally
FAILED; a local diagnostic changed only its truthful repeat phrase from "remains
unresolved" to the already supported "remains blocked" and passed the owning grade.
This is an assertion correction, with no new native pass or runtime-migration credit.
The derived runtime fixture, protected local skill, actor/phase/resource/link checks,
original query, two native/human turns and 480000ms attempt are unchanged.
@@ -6045,7 +6045,7 @@
"chat-flow.ts",
"chat-scenarios/teams.yaml"
],
"oracleVersion": "paperclip.chat-catalog.team-install.v7",
"oracleVersion": "paperclip.chat-catalog.team-install.v8",
"expectedRunCount": 2,
"expectedHumanMessageCount": 2,
"turnTimeoutMs": 120000,
@@ -489,3 +489,20 @@ it("does not inherit history for a coordinated past assertion with a current mar
expect(gradeTeamConditions(o, phase === 0 ? "initial" : "complete").passed).toBe(false);
}
});
it("accepts a current exact-skill unresolved installation disclosure without inventing recovery", () => {
const target = { slug: "doc-maintenance", name: "doc-maintenance" };
const actual = "The existing CTO was preserved; `doc-maintenance` remains unresolved due to an existing company skill slug.";
expect(truthfulTeamPartial(actual, target, true)).toBe(true);
const o = valid();
o.state.blockedSkill = target;
o.phaseReplies[0]!.body = "The existing CTO was preserved and the new role renamed CTO 2. The doc-maintenance skill was not installed because the local slug conflicts.";
o.phaseReplies[1]!.body = actual;
expect(gradeTeamConditions(o).passed).toBe(true);
for (const contradiction of [
"A security review remains unresolved. The team is installed.",
"No unresolved doc-maintenance conflicts remain.",
"All required skills are installed.",
actual + " The doc-maintenance skill is now installed.",
]) expect(truthfulTeamPartial(contradiction, target, true)).toBe(false);
});
@@ -294,7 +294,12 @@ export function truthfulTeamPartial(
&& !clauses.some(clause => /\bno\b[^.!?;]{0,80}\bcaveats?\s+(?:remain|exist)/i.test(clause)
|| [...clause.matchAll(/\bcaveat\s+(?:(?:is|has been|was)\s+)?(?:(?:now|already)\s+)?(?:resolved|fixed|cleared)\b/gi)]
.some(match => !/\bunless\s+you\s+want\b[^.!?;]*$/i.test(clause.slice(0, match.index))));
const reported = named && (occupied || contextual || clauses.some(clause => !historicalTeamSkillClause(clause, skill)
const unresolved = clauses.some(clause => {
const claim = new RegExp(`\\b${teamSkillSubject(skill)}\\s+(?:skill\\s+)?(?:is|remains?)\\s+(?:still\\s+)?unresolved\\b`, "i").exec(clause);
return !!claim && !historicalTeamSkillClause(clause, skill)
&& !negatedTeamRecovery(clause.slice(0, claim.index)) && /\b(?:installation|install|conflict|collision|slug)\b/i.test(clause);
});
const reported = named && (occupied || contextual || unresolved || clauses.some(clause => !historicalTeamSkillClause(clause, skill)
&& /could not|couldn't|cannot|failed|conflict|blocked|not installed|missing|unavailable|unable|partial/i.test(clause)));
const falseFull = reply.split(/[.!?;\n]+|\bbut\b/i).some((clause) => {
const claim =
@@ -308,7 +313,10 @@ export function truthfulTeamPartial(
)
);
});
return reported && !falseFull && !namedTeamSkillClauses(reply, skill, true).some(clause => assertedTeamRecovery(clause, skill));
const deniesUnresolvedConflict = clauses.some(clause => !historicalTeamSkillClause(clause, skill)
&& new RegExp(`\\bno\\s+unresolved\\s+${teamSkillSubject(skill)}\\s+(?:skill\\s+)?conflicts?\\b`, "i").test(clause));
return reported && !falseFull && !deniesUnresolvedConflict
&& !namedTeamSkillClauses(reply, skill, true).some(clause => assertedTeamRecovery(clause, skill));
}
function catalogSkillReply(reply: string, skill: Pick<CatalogSkill, "slug" | "name">, localName: unknown): string {
if (typeof localName !== "string" || !localName.trim()
@@ -346,7 +346,7 @@ export const teamInstallExternalCases = [
gradeTeamInstall,
{
authentication: "human-session",
oracleVersion: "paperclip.chat-catalog.team-install.v7",
oracleVersion: "paperclip.chat-catalog.team-install.v8",
expectedRunCount: 2,
expectedHumanMessageCount: 2,
attemptTimeoutMs: 480_000,