Skip to content

Commit eba05c2

Browse files
sync(insertion-normalization): match cnighswonger#272 tip — join-hash + tail guard
Brings proxy/extensions/insertion-normalization.mjs and its real-pair test to the cnighswonger#272 slice tip (fork e0f8fcb): the merged-standalone join-hash set and the tail-position suppression guard. The extension rides here so this slice's tools replay the same behaviour cnighswonger#272 ships. Co-Authored-By: Claude opus-5 <noreply@anthropic.com>
1 parent 3d2095b commit eba05c2

2 files changed

Lines changed: 105 additions & 12 deletions

File tree

proxy/extensions/insertion-normalization.mjs

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -656,22 +656,54 @@ function pinnedBlockHashes(priorCanonical) {
656656
return hashes;
657657
}
658658

659-
// Is `msg` a suppressible duplicate of a currently-pinned block? Narrow by
660-
// definition (BACKLOG #76606 part (c)): STANDALONE only (single block after
661-
// the same string->one-block fold canonicalMessageShape already applies
662-
// elsewhere in this file), and its wrapper-stripped bytes must exactly
663-
// equal a hash in `pinnedHashes` — never a positional or role heuristic.
664-
// Returns the matched hash (for telemetry) or null (genuine content: no
665-
// suppression, existing rules apply unchanged).
666-
export function findSuppressibleDuplicate(msg, pinnedHashes) {
659+
// The merged-standalone shape (measured 2026-07-30, capture s-633915a8,
660+
// msg864, the 587k window): CC sometimes migrates ALL of a message's
661+
// volatile blocks out TOGETHER, joined into one standalone message,
662+
// rather than one standalone per block. pinnedBlockHashes above can never
663+
// match that — it hashes one block at a time, and a merged message is one
664+
// block whose text spans two reminders. A second set covers exactly the
665+
// observed join: for each pinned entry with >=2 volatile blocks, hash the
666+
// concatenation of ALL its volatile blocks' wrapper-stripped texts, in
667+
// WIRE order, joined with "\n\n" — the exact separator measured on the
668+
// real merged standalone (both hook reminders, 627 chars). No
669+
// subset-merges: partial joins were never observed and would only invite
670+
// false suppression on coincidental partial matches. "\n\n" is hardcoded
671+
// to the one observed instance, not a general N-ary merge grammar — other
672+
// separators are unobserved, and the census keeps watching for them.
673+
function pinnedJoinHashes(priorCanonical) {
674+
const hashes = new Set();
675+
if (!Array.isArray(priorCanonical)) return hashes;
676+
for (const entry of priorCanonical) {
677+
if (entry.d || !entry.m || !Array.isArray(entry.m.content)) continue;
678+
const volatileTexts = entry.m.content.filter(isVolatileBlock).map((b) => unwrapVolatileText(b).text);
679+
if (volatileTexts.length < 2) continue;
680+
const h = hashMessageContent({ content: [{ type: "text", text: volatileTexts.join("\n\n") }] });
681+
if (h !== null) hashes.add(h);
682+
}
683+
return hashes;
684+
}
685+
686+
// Is `msg` a suppressible duplicate of a currently-pinned block (or, since
687+
// 2026-07-30, a currently-pinned entry's FULL joined volatile-block set)?
688+
// Narrow by definition (BACKLOG #76606 part (c)): STANDALONE only (single
689+
// block after the same string->one-block fold canonicalMessageShape
690+
// already applies elsewhere in this file), and its wrapper-stripped bytes
691+
// must exactly equal a hash in `pinnedHashes` or `joinHashes` — never a
692+
// positional or role heuristic. `joinHashes` is optional (existing callers
693+
// checking single-block duplicates only are unaffected). Returns the
694+
// matched hash (for telemetry) or null (genuine content: no suppression,
695+
// existing rules apply unchanged).
696+
export function findSuppressibleDuplicate(msg, pinnedHashes, joinHashes) {
667697
const shaped = canonicalMessageShape(msg);
668698
if (!Array.isArray(shaped.content) || shaped.content.length !== 1) return null;
669699
const h = hashMessageContent({ content: [unwrapVolatileText(shaped.content[0])] });
670-
if (h === null || !pinnedHashes.has(h)) return null;
671-
return h;
700+
if (h === null) return null;
701+
if (pinnedHashes.has(h)) return h;
702+
if (joinHashes && joinHashes.has(h)) return h;
703+
return null;
672704
}
673705

674-
export { pinnedBlockHashes };
706+
export { pinnedBlockHashes, pinnedJoinHashes };
675707

676708
// Pin-mode classification. Differences from classifyInsertion:
677709
// - identities exclude volatile blocks (flip absorption);
@@ -822,11 +854,25 @@ export function classifyPinned(messages, priorCanonical) {
822854
// findSuppressibleDuplicate returns null, the entry is untouched here,
823855
// and whatever the existing rules above already decided (append/splice/
824856
// edit-shaped reset) stands — no new reset path is introduced.
857+
// TAIL GUARD (BACKLOG.md, "suppression can strip a request's FINAL
858+
// message", 2026-07-30). Three real 400s ("must end with a user
859+
// message"): report-enforcer injects identical instruction bytes at
860+
// every SubagentStop; the first occurrence gets pinned, and when the
861+
// SAME bytes arrive again as the resume request's ONLY/new final
862+
// message, suppressing it left the forwarded array ending on the prior
863+
// assistant turn. A tail-position duplicate is never a stray migration
864+
// copy of already-pinned content — CC just sent it as the live,
865+
// load-bearing final entry of THIS request, and the model needs to see
866+
// it. Applies uniformly to both single-block and join-hash matches: the
867+
// guard is positional, not about which hash set matched.
868+
const lastIdx = messages.length - 1;
825869
const pinnedHashes = pinnedBlockHashes(priorCanonical);
870+
const pinnedJoin = pinnedJoinHashes(priorCanonical);
826871
const suppressions = [];
827872
for (const e of newEntries) {
828873
if (e.r === "assistant") continue;
829-
const h = findSuppressibleDuplicate(messages[e.index], pinnedHashes);
874+
if (e.index === lastIdx) continue;
875+
const h = findSuppressibleDuplicate(messages[e.index], pinnedHashes, pinnedJoin);
830876
if (h !== null) suppressions.push({ index: e.index, hash: h });
831877
}
832878
const suppressedIdx = new Set(suppressions.map((s) => s.index));

test/insertion-suppression.test.mjs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,53 @@ test("classifyPinned: a standalone duplicate of a pinned block is suppressed; th
155155
assert.deepEqual(result.messages[result.messages.length - 1], userMsg("continue"));
156156
});
157157

158+
// =====================================================================
159+
// TAIL GUARD (BACKLOG.md, "suppression can strip a request's FINAL
160+
// message", 2026-07-30). Three real 400s ("must end with a user
161+
// message"): report-enforcer injects identical instruction bytes at
162+
// every SubagentStop; the first occurrence is pinned, and when the SAME
163+
// bytes arrive again as a resume request's ONLY/new final message,
164+
// suppressing it left the forwarded array ending on the prior assistant
165+
// turn. A tail-position duplicate is CC's live payload for THIS request,
166+
// not a migration copy of already-pinned content, regardless of role or
167+
// which hash set (single-block or join) matched it.
168+
// =====================================================================
169+
170+
test("TAIL GUARD: a standalone duplicate at the FINAL index is never suppressed — it is live payload, not a migration", () => {
171+
const orig = [withReminderMsg("tool result"), assistantMsg("a1")];
172+
const canon = pinCanon(orig);
173+
174+
const strippedTail = { role: "user", content: [{ type: "text", text: "tool result" }] };
175+
const standaloneDuplicate = { role: "system", content: [{ type: "text", text: REMINDER_INNER }] };
176+
// No trailing entry after the duplicate — it IS the array's final
177+
// message, mirroring the real resume-request shape.
178+
const next = [strippedTail, assistantMsg("a1"), standaloneDuplicate];
179+
180+
const result = classifyPinned(next, canon);
181+
assert.equal(result.suppressed, 0, "a final-position duplicate must never be suppressed");
182+
assert.equal(result.suppressions.length, 0);
183+
assert.deepEqual(
184+
result.messages[result.messages.length - 1],
185+
standaloneDuplicate,
186+
"the final message must be forwarded intact — this is exactly what would otherwise strip a resume's last turn",
187+
);
188+
});
189+
190+
test("REGRESSION: the same standalone duplicate, mid-history (not final), is still suppressed", () => {
191+
const orig = [withReminderMsg("tool result"), assistantMsg("a1")];
192+
const canon = pinCanon(orig);
193+
194+
const strippedTail = { role: "user", content: [{ type: "text", text: "tool result" }] };
195+
const standaloneDuplicate = { role: "system", content: [{ type: "text", text: REMINDER_INNER }] };
196+
// Same duplicate, same position (index 2) as the tail-guard test above,
197+
// but with a trailing turn after it — no longer the final index.
198+
const next = [strippedTail, assistantMsg("a1"), standaloneDuplicate, userMsg("continue")];
199+
200+
const result = classifyPinned(next, canon);
201+
assert.equal(result.suppressed, 1, "mid-history duplicates are suppressed exactly as before the tail guard");
202+
assert.equal(result.suppressions[0].index, 2);
203+
});
204+
158205
test("classifyPinned: suppression is stable across a THIRD request — CC keeps resending the duplicate, it keeps getting suppressed, with no persisted marker needed", () => {
159206
const orig = [withReminderMsg("tool result"), assistantMsg("a1")];
160207
let canon = pinCanon(orig);

0 commit comments

Comments
 (0)