@@ -1408,6 +1408,16 @@ function renderExternalItem(item: ExternalRecallSliceItem): string {
14081408 : `- ${ escapeXmlContent ( item . content ) } ` ;
14091409}
14101410
1411+ /** Body of the <external-memory> block. INTENTIONALLY merges only the
1412+ * `project` and `global` slices — the `profile` slice is omitted here by
1413+ * design and is rendered separately into the <user-profile> block (see
1414+ * `renderUserProfileBlock(..., externalRecall?.profile ?? [])` in `renderM0`).
1415+ * Duplicating profile lines into <external-memory> would be redundant
1416+ * (the model would see the same recall content twice) and would defeat
1417+ * the user-profile budget trim that lives on that block. Note that the
1418+ * sibling `renderExternalDeltaLines` (m[1] delta path) DOES include the
1419+ * profile slice — there profile lines reconcile into <user-profile> at
1420+ * the next HARD fold, per its own comment. */
14111421function renderExternalLines ( snapshot : ExternalRecallSnapshot ) : string [ ] {
14121422 const items : ExternalRecallSliceItem [ ] = [ ...snapshot . project , ...snapshot . global ] ;
14131423 const lines : string [ ] = [ ] ;
@@ -1504,6 +1514,11 @@ export function renderM0(args: {
15041514} ) : string {
15051515 const sections : string [ ] = [ ] ;
15061516 if ( args . projectDocs . length > 0 ) sections . push ( args . projectDocs ) ;
1517+ // The external-recall PROFILE slice is merged HERE (into <user-profile>),
1518+ // not into <external-memory>. `renderExternalLines` deliberately emits
1519+ // only project + global — see its JSDoc for the rationale. Splitting the
1520+ // merge this way lets the user-profile budget trim govern recall-derived
1521+ // profile lines without inflating the sibling <external-memory> block.
15071522 const userProfile = renderUserProfileBlock (
15081523 trimUserMemoriesToBudget (
15091524 args . userProfileBaseline ,
0 commit comments