Skip to content

Commit 969037f

Browse files
committed
fix(session): drop dead State repair and tighten token scoring
1 parent 6584a45 commit 969037f

2 files changed

Lines changed: 40 additions & 13 deletions

File tree

‎src/session/compaction-verify.test.ts‎

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,12 +146,13 @@ describe("verifyCompactionSummary", () => {
146146
expect(kinds).toContain("exactName");
147147
});
148148

149-
test("auth as a goal token does not match authored, author, or preauth", () => {
149+
test("auth as a goal token does not match authored, author, preauth, or pre-auth", () => {
150150
const facts = extractContinuationFacts([textTurn("user", "Fix auth now")]);
151151
for (const summary of [
152152
"The authored notes: next step module plan is set.",
153153
"The author notes: next step module plan is set.",
154154
"The preauth notes: next step module plan is set.",
155+
"The pre-auth notes: next step module plan is set.",
155156
]) {
156157
const report = verifyCompactionSummary(summary, facts);
157158
expect(report.supported).toBe(false);
@@ -168,6 +169,15 @@ describe("verifyCompactionSummary", () => {
168169
expect(report.misses.some((m) => m.kind === "contradiction")).toBe(true);
169170
});
170171

172+
test("a half-overlap paraphrase does not cover the standing goal", () => {
173+
const facts = extractContinuationFacts(droppedTurns());
174+
const report = verifyCompactionSummary(
175+
"The module tokens migrate elsewhere on schedule.",
176+
facts,
177+
);
178+
expect(report.misses.some((m) => m.kind === "goal")).toBe(true);
179+
});
180+
171181
test("oauth.ts does not cover src/auth.ts", () => {
172182
const facts = extractContinuationFacts([
173183
textTurn("user", "Fix auth now"),
@@ -379,6 +389,7 @@ describe("verifyOrRepair", () => {
379389
expect(repair).not.toContain("src/auth.ts");
380390
expect(repair).not.toContain("Goal:");
381391
expect(repair).not.toContain("Next:");
392+
expect(repair).not.toMatch(/^State:/m);
382393
});
383394

384395
test("repair lines are goal, next, exact names, then the rest", () => {
@@ -397,6 +408,26 @@ describe("verifyOrRepair", () => {
397408
expect(ranAt).toBeGreaterThan(blockersAt);
398409
});
399410

411+
test("repair does not emit a State line even when state is independent", () => {
412+
const facts = {
413+
goal: "Migrate the auth module to opaque tokens",
414+
constraints: [] as string[],
415+
nextAction: "Fix the token refresh assertion next.",
416+
state: "The cache is still cold after warmup.",
417+
verification: [] as string[],
418+
blockers: ["token refresh assertion failed"],
419+
exactNames: [] as string[],
420+
};
421+
const summary = "Work continues.";
422+
const misses = verifyCompactionSummary(summary, facts).misses;
423+
expect(misses.some((m) => m.kind === "blocker")).toBe(true);
424+
expect(misses.some((m) => m.kind === "nextAction")).toBe(true);
425+
const repaired = repairSummary(summary, facts, misses);
426+
const repair = repaired.slice(repaired.indexOf(VERIFY_REPAIR_HEADING));
427+
expect(repair).not.toMatch(/^State:/m);
428+
expect(repair).not.toContain("cache is still cold");
429+
});
430+
400431
test("a tight cap keeps goal, next, and names before aborting on the tail", () => {
401432
const facts = extractContinuationFacts(droppedTurns());
402433
const misses = verifyCompactionSummary("Work continues.", facts).misses;

‎src/session/compaction-verify.ts‎

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -125,14 +125,18 @@ function significantTokens(text: string, cap = 24): string[] {
125125
return out;
126126
}
127127

128-
// Half (rounded up) of the fact's content words must appear in the summary.
128+
// A strict majority of the fact's content words must appear in the summary.
129129
// Short facts need all of their words: one shared word proves nothing.
130-
// Match on token boundaries so "auth" does not score against "authored".
130+
// Match on token boundaries so "auth" does not score against "authored" or
131+
// hyphenated "pre-auth".
131132
function isTokenChar(ch: string | undefined): boolean {
132133
if (ch === undefined) return false;
133134
const code = ch.charCodeAt(0);
134135
return (
135-
(code >= 48 && code <= 57) || (code >= 97 && code <= 122) || code === 95
136+
(code >= 48 && code <= 57) ||
137+
(code >= 97 && code <= 122) ||
138+
code === 95 ||
139+
code === 45
136140
);
137141
}
138142

@@ -156,7 +160,7 @@ function tokensSupported(fact: string, summary: string): boolean {
156160
const lowered = summary.toLowerCase();
157161
const hits = tokens.filter((t) => tokenAppears(t, lowered)).length;
158162
const needed =
159-
tokens.length <= 2 ? tokens.length : Math.ceil(tokens.length / 2);
163+
tokens.length <= 2 ? tokens.length : Math.floor(tokens.length / 2) + 1;
160164
return hits >= needed;
161165
}
162166

@@ -397,14 +401,6 @@ export function repairSummary(
397401
.map((m) => m.detail);
398402
lines.push(`Exact references: ${missing.join(", ")}`);
399403
}
400-
// The state line carries where the work stood when it is neither the next
401-
// action nor an already-listed blocker.
402-
const stateCovered =
403-
facts.state.trim().length === 0 ||
404-
facts.state === facts.nextAction ||
405-
facts.blockers.includes(facts.state);
406-
if ((kinds.has("blocker") || kinds.has("nextAction")) && !stateCovered)
407-
lines.push(`State: ${facts.state}`);
408404
if (kinds.has("constraint")) {
409405
const missing = misses
410406
.filter((m) => m.kind === "constraint")

0 commit comments

Comments
 (0)