mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-21 18:47:02 +03:00
Address review: a superseded Go never opens a second session
An overlay renews its lease right before Go, then captures and uploads the element before its generate event leaves. When that outlasts the lease and its result post is lost, a rescuer can claim the target and Go, and the helper accepted both generate events: two sessions for one request. The generate envelope now carries this page's clientId, and the helper refuses a generate event for a target that another page holds under a live lease, or that was already answered with a different session (`served_agent_targets`, recorded on every ok resolution): 409 `agent_target_already_served`, nothing journaled. The overlay treats that refusal like a foreign session and hands the surface back. The answering session's own event stays welcome, so the common path (result post first, then the event) is unchanged. Tests: two Rust integration cases (rival lease, answered elsewhere, welcome for the serving session) and a Node protocol case, contract pins for the envelope and the refusal handling, contract doc. Written with AI assistance (Claude). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
committed by
Abdul Wahab
co-authored by
Claude Fable 5
parent
b5210471fb
commit
7adb81672d
@@ -7736,6 +7736,14 @@
|
||||
}).then(async res => {
|
||||
if (res.ok) return res;
|
||||
const body = await res.json().catch(() => ({}));
|
||||
// The helper refused to open a second session for an agent target
|
||||
// another page already served (this page's lease lapsed while it was
|
||||
// capturing): drop the local session and hand the surface back.
|
||||
if (body.error === 'agent_target_already_served' && msg.type === 'generate'
|
||||
&& msg.id && msg.id === currentSessionId) {
|
||||
abandonSupersededGo(msg.id);
|
||||
return null;
|
||||
}
|
||||
// The server refused to journal progress for a session it has never
|
||||
// seen: this browser is carrying state from another project or a
|
||||
// wiped store (two apps sharing a localhost port). Continuing to
|
||||
@@ -7757,6 +7765,14 @@
|
||||
return sessionCreationGate.then(doSend);
|
||||
}
|
||||
|
||||
function abandonSupersededGo(sessionId) {
|
||||
if (sessionId !== currentSessionId) return;
|
||||
console.warn('[impeccable] Another page already served this agent target; clearing session ' + sessionId + '.');
|
||||
markSessionHandled();
|
||||
cleanup({ instantChrome: true });
|
||||
showToast('Another tab already served this request, so this session was cleared.', 6000);
|
||||
}
|
||||
|
||||
let abandonedForeignSessionId = null;
|
||||
function abandonForeignSession(sessionId) {
|
||||
if (abandonedForeignSessionId === sessionId || sessionId !== currentSessionId) return;
|
||||
@@ -8192,6 +8208,7 @@
|
||||
// as well as from the overlay's own result post.
|
||||
basePayload.agentTarget = {
|
||||
targetId: agentTargetForGo.targetId,
|
||||
clientId: AGENT_TARGET_CLIENT_ID,
|
||||
result: {
|
||||
ok: true,
|
||||
matchCount: agentTargetForGo.matchCount,
|
||||
|
||||
Reference in New Issue
Block a user