Skip to content

Commit a518920

Browse files
author
Tehan
committed
fix(pi): render profile slice in external m[1] delta
1 parent 2a8cd71 commit a518920

1 file changed

Lines changed: 50 additions & 0 deletions

File tree

packages/pi-plugin/src/inject-compartments-pi.test.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1578,3 +1578,53 @@ describe("Pi external m[1] delta pressure-refold exclusion (cache parity)", () =
15781578
}
15791579
});
15801580
});
1581+
1582+
describe("Pi external m[1] delta includes profile slice (Finding #2)", () => {
1583+
// Regression: Pi's m[1] delta previously called renderExternalMemoryBlock
1584+
// (project+global only), dropping profile-slice items. The fix uses
1585+
// renderExternalMemoryDelta (project+global+profile), matching OpenCode.
1586+
1587+
it("profile-slice item from recall snapshot appears in Pi m[1] external delta", () => {
1588+
const db = createTestDb();
1589+
const cwd = mkdtempSync(join(tmpdir(), "pi-ext-profile-delta-"));
1590+
try {
1591+
const state = piState("ses-pi-ext-profile", cwd);
1592+
1593+
// Materialize m[0] first (no external recall yet).
1594+
const firstPass = [userMessage("hello", 10)];
1595+
const r0 = injectM0M1Pi(state, db, firstPass as never, [], true);
1596+
expect(r0.m0Materialized).toBe(true);
1597+
1598+
// Seed an external recall snapshot with a profile-slice item AFTER
1599+
// m[0] was materialized. The snapshot hash differs from the m[0]
1600+
// baseline hash (which is ""), so the delta will be rendered into m[1].
1601+
const profileItem = "user prefers concise answers";
1602+
db.prepare(
1603+
"UPDATE session_meta SET external_recall_state = ?, external_recall_json = ?, external_recall_at = ? WHERE session_id = ?",
1604+
).run(
1605+
"done",
1606+
JSON.stringify({
1607+
project: [],
1608+
profile: [{ content: profileItem }],
1609+
global: [],
1610+
}),
1611+
Date.now(),
1612+
state.sessionId,
1613+
);
1614+
1615+
// Cache-busting pass: the external delta must include the profile item.
1616+
const secondPass = [userMessage("hello", 11)];
1617+
injectM0M1Pi(state, db, secondPass as never, [], true);
1618+
1619+
// m[1] must contain the profile-slice item.
1620+
const m1Text = textOf(secondPass[1] as never);
1621+
expect(m1Text).toContain(profileItem);
1622+
// m[0] must NOT contain it (profile merges into <user-profile> at next
1623+
// HARD fold, not into the external block at m[0]).
1624+
expect(textOf(secondPass[0] as never)).not.toContain(profileItem);
1625+
} finally {
1626+
rmSync(cwd, { recursive: true, force: true });
1627+
closeQuietly(db);
1628+
}
1629+
});
1630+
});

0 commit comments

Comments
 (0)