fix(chat): keep compression tip selected in sidebar - #2913
2 commits merged into
Conversation
78b34c9 to
9e74072
Compare
|
Read the diff against Code referenceThe collapse-tiebreaker change ( if(bSeg||aSeg){
if(bSeg!==aSeg) return bSeg-aSeg;
}
// Preserved pre-compression parents can share the same backend segment
// count as the continuation. Prefer the non-snapshot tip before falling
// back to timestamps, otherwise a recently-polled parent reopens the
// older transcript and makes the active continuation look lost.
const bSnapshot=!!(b&&b.pre_compression_snapshot);
const aSnapshot=!!(a&&a.pre_compression_snapshot);
if(bSnapshot!==aSnapshot) return aSnapshot-bSnapshot;
return _sessionTimestampMs(b)-_sessionTimestampMs(a);And the new async function loadSession(sid){
const opts = arguments[1] || {};
if(!opts.skipLineageResolve && typeof _resolveSessionIdFromSidebarLineage==='function'){
const resolvedSid=_resolveSessionIdFromSidebarLineage(sid);
if(resolvedSid&&resolvedSid!==sid) sid=resolvedSid;
}The resolver scans the collapsed sidebar rows and only retargets when:
That's the right gate — it avoids retargeting plain non-lineage sessions that happen to be missing from the current sidebar payload (preserves the existing 404 self-heal path mentioned in the canonical-session-resolution RFC at #2922). TestsThe two new tests are sharp: sessions = [
{session_id:'parent', ..., pre_compression_snapshot:true, _lineage_root_id:'parent', _compression_segment_count:2},
{session_id:'child', ..., parent_session_id:'parent', _lineage_root_id:'parent', _compression_segment_count:2},
];
const collapsed = _collapseSessionLineageForSidebar(sessions);
...
assert [row["session_id"] for row in collapsed] == ["child"]
assert collapsed[0]["_lineage_collapsed_count"] == 2
assert [seg["session_id"] for seg in collapsed[0]["_lineage_segments"]] == ["child", "parent"]This is exactly the case the diff fixes — identical The second test exercises the direct-URL resolver: const _allSessions = [
{session_id:'child', ..., parent_session_id:'parent', _lineage_root_id:'parent', _compression_segment_count:2},
{session_id:'other', ..., (unrelated)},
];
console.log(JSON.stringify({parent:_resolveSessionIdFromSidebarLineage('parent'), child:_resolveSessionIdFromSidebarLineage('child'), other:_resolveSessionIdFromSidebarLineage('other')}));
...
assert result == {"parent": "child", "child": "child", "other": "other"}Confirms One subtle caseThe sort comparator inside candidates.sort((a,b)=>{
const bSeg=Number(b&&b._compression_segment_count||b&&b._lineage_collapsed_count||0);
const aSeg=Number(a&&a._compression_segment_count||a&&a._lineage_collapsed_count||0);
if(bSeg!==aSeg) return bSeg-aSeg;
const bSnapshot=!!(b&&b.pre_compression_snapshot);
const aSnapshot=!!(a&&a.pre_compression_snapshot);
if(bSnapshot!==aSnapshot) return aSnapshot-bSnapshot;
return _sessionTimestampMs(b)-_sessionTimestampMs(a);
});That matches the collapse comparator (good — same ordering rule used in two places). One subtle thing: if a stale visible row in DiagnosisThe fix matches the canonical-session-resolution RFC's Rule 2 verbatim ("snapshot parents defer to visible continuation tips"). The LGTM. One nit: the |
48a2e79
# Conflicts: # CHANGELOG.md
# Conflicts: # CHANGELOG.md
# Conflicts: # CHANGELOG.md
Summary
Tests
pytest -q tests/test_session_lineage_collapse.pypython3 -m py_compile api/models.py api/routes.py