@@ -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