feat(session-continuity): survive client history compaction — root-anchor fallback + tail-anchored overlap; acct= in reuse log (opt-in, DEVIN_CONNECT_SESSION_REUSE) - #248
Conversation
… + tail-anchored overlap; acct= in reuse log - overlapScore: document tail-anchored semantics (body already tail-anchored on master: contiguous run ending at the candidate's LAST hash). - resolveSessionId: root-anchor fallback re-associates the committed session when a compacted history's pairs were rewritten (0/N survive byte-for-byte) but the first input turn survives verbatim. Fires only when NO incoming hash matched any stored index (pair evidence gone) — a divergent dialog whose prefix pair still hits the index must not be re-associated. - commitAfterResponse: root-index forked states so the fallback's ambiguity rule (several live root candidates -> assign to none) can see same-opener forks and never hijack a fork into the original session. - chat.js: DEVIN_CONNECT reuse log now carries acct=<account id> (env-token fallback). - tests: compaction survival (root re-association + ambiguous no-hijack), tail-anchored overlap (prefix-only run scores 0; suffix match resolves), chat reuse-log acct= construction.
…guity rule, TTL eviction (baseline 34)
…ndex the new pair window; trailing newline
|
评审:机制是对的,三道闸我逐条驱动过。请补一条 —— PR 正文承诺的覆盖范围比实际大一档。 我实跑过什么head
三道闸我是分别驱动的,不是读代码看出来的。
M1(请补)— fork 场景下这个特性不生效,而正文没说我构造了这个仓库最常见的形态:两个对话同一个 opener(agent 客户端普遍如此),各自分叉,然后其中一个压缩。 没有安全问题 —— 我原本怀疑的跨对话泄漏不成立, 但结果是:只要有第二个对话共享同一个 opener,压缩存活就失效,B 掉到新 session,也就是这个 PR 要修的那个连续性丢失。而 PR 正文写的是:
这句话在单对话下成立,在 fork 下不成立。你的测试已经钉住了这个边界,正文没有。 两条都不难,但我倾向后者:
我倾向 1。方案 2 是在给一个「不可判定的输入」造判据,而歧义规则本身是正确的保守选择 —— 宁可退化成新 session,也不能猜错把 B 接到 A 上。这和你在 #242 评审里接受的那个取舍是同一个方向。 M2(请核)— 与 #242 在
|
中文 TL;DR
部分客户端会 compact 自己的历史,会话复用时最近的配对窗口(pair window)变空或过短,会话认不出来、每轮都被当新会话,continuity 和 stable ModelConfig 在长程 agent 作业里悄悄失效。本 PR 给会话解析加 root-anchor fallback:窗口不可靠时改用对话根锚点匹配,并在出现歧义(两个活会话同根)时拒绝误认;overlap 计分改为尾锚点加权(紧凑化切的是头不是尾)。另在 reuse 日志补 acct= 字段,按账号排障不用再猜。仍在 DEVIN_CONNECT_SESSION_REUSE 门控内,关闭时行为逐字不变。
Что меняется
src/session-continuity.js:src/handlers/chat.js: строка reuse-лога обогащенаacct=.Зачем
Клиентская компакция истории — нормальное поведение агентов на длинных прогонах. Без fallback сессия после компакии не резолвится, и именно тогда, когда continuity нужнее всего, он молча выключается.
Test plan
test/session-continuity.test.js(+test/chat-reuse-log.test.js): компакция клиентом истории (пустое/короткое окно пар) → резолв по root anchor; tail-anchored overlap различает свою/чужую сессию; два живых состояния на одном корне → отказ обоим; TTL-просрочка в fallback → новый session;acct=в reuse-логе.test/mutations/session-continuity-compaction-survival.json(3 мутации, все CAUGHT) + все spec репо: EXIT=0, anchor'ы ровно по разу.Безопасность
Гейт
DEVIN_CONNECT_SESSION_REUSEdefault OFF: при выключенном гейте код пути не исполняется, поведение побайтово неизменно. Fallback срабатывает только при отсутствии свежих парных свидетельств и только на единственного живого кандидата.