Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
70676e4
Preserve validated local freshness recovery candidate
xyx2002OvO Oct 12, 2026
c6937eb
fix: preserve native turn recovery and packaged SDK continuity
xyx2002OvO Oct 13, 2026
da8955a
test: cover recovery identity transport and terminal settlement
xyx2002OvO Oct 13, 2026
135050f
docs: clarify local delegation and recovery handoff
xyx2002OvO Oct 13, 2026
0be3973
fix(checkpoint): retain legacy admission across repeated turn reads
xyx2002OvO Oct 13, 2026
f2f5fa0
test(collaboration): preserve exact input bytes in result-use fixtures
xyx2002OvO Oct 13, 2026
a42e3dd
fix(mcp): support quiet waits for unfinished admitted work
xyx2002OvO Oct 14, 2026
9684991
docs(mcp): explain unfinished wait and result recovery
xyx2002OvO Oct 14, 2026
ecf8691
fix: replay exact deferred completion receipt after settlement
xyx2002OvO Oct 14, 2026
02b3e8c
fix(chat): exclude lock diagnostics from request journals
xyx2002OvO Oct 14, 2026
7c484ef
fix(lark): support Windows private JSON long paths
xyx2002OvO Oct 14, 2026
24cc8c4
fix(runtime): preserve long Windows declaration IO
xyx2002OvO Oct 15, 2026
d285e42
fix(migration): preserve long Windows backup IO
xyx2002OvO Oct 15, 2026
6134895
fix(coordination): support long Windows shadow journal paths
xyx2002OvO Oct 15, 2026
e9daf30
fix(packaging): include retained adapter and runtime assets
xyx2002OvO Oct 15, 2026
d10bba0
fix: preserve recovery identities and portable local paths
xyx2002OvO Oct 18, 2026
417562f
Retain original lifecycle source through heartbeat recovery
xyx2002OvO Oct 19, 2026
0794acb
Keep committed monitor polls out of unbound Turn debt diagnostics
xyx2002OvO Oct 19, 2026
f0025cf
Publish freshness recovery regressions and owning packaged checkpoint…
xyx2002OvO Oct 19, 2026
b97a47e
Document default freshness recovery and product qualification limits
xyx2002OvO Oct 19, 2026
b3f89a3
fix: preserve terminal history with sealed lifecycle admission facts
xyx2002OvO Oct 19, 2026
651d977
fix: address long atomic Chat temporary paths on Windows
xyx2002OvO Oct 19, 2026
20ba29c
fix: reconcile freshness recovery with current main authority contracts
xyx2002OvO Oct 21, 2026
0f26f81
docs: align freshness qualification with canonical-only writes
xyx2002OvO Oct 21, 2026
465ea9b
fix(freshness): validate work basis on in-flight writeback
xyx2002OvO Oct 24, 2026
5d64266
fix(freshness): fence PostgreSQL and all protected result writebacks
xyx2002OvO Oct 24, 2026
8260468
fix(freshness): restore owner document and fixture prerequisites
xyx2002OvO Oct 24, 2026
5b70655
docs: preserve owner authority during freshness recovery
xyx2002OvO Oct 24, 2026
ced32e6
fix(freshness): bind superseded work to its original Turn
xyx2002OvO Oct 26, 2026
cfdffef
Merge evaluated freshness snapshot and combined scenario report
xyx2002OvO Oct 27, 2026
8704348
fix: recover proved result work through original Turn settlement
xyx2002OvO Oct 27, 2026
49a6e97
fix: preserve sealed lifecycle closeout within the admission second
xyx2002OvO Oct 27, 2026
93eab46
test: align freshness recovery journeys with current main contracts
xyx2002OvO Oct 27, 2026
f35c24a
docs: clarify recovery boundaries and historical evaluation provenance
xyx2002OvO Oct 27, 2026
b9ba175
fix(checkpoint): recover stale progress and preserve scoped source fr…
xyx2002OvO Oct 27, 2026
ee092a8
fix(chat): reread unavailable checkpoint observations without dispatch
xyx2002OvO Oct 27, 2026
079626d
docs(checkpoint): record scoped recovery and qualification boundaries
xyx2002OvO Oct 27, 2026
88467ff
fix(checkpoint): isolate verified settled reads across delivery and o…
xyx2002OvO Oct 27, 2026
1d5e37c
fix(checkpoint): preserve missing-read recovery and canonical chat ro…
xyx2002OvO Oct 27, 2026
226bb19
fix(checkpoint): allow bounded explicit direction-stop reentry
xyx2002OvO Oct 27, 2026
98404d7
test(checkpoint): reconcile recovery fixtures and validation budgets
xyx2002OvO Oct 27, 2026
bdad81a
docs(checkpoint): describe reentry and retain qualification limits
xyx2002OvO Oct 27, 2026
5484611
fix(checkpoint): preserve physical aliases and original-Turn recovery
xyx2002OvO Oct 28, 2026
77b9b2a
fix(coordination): preserve cold imports across Windows long paths
xyx2002OvO Oct 28, 2026
804735a
docs(checkpoint): clarify alias and recovery evidence boundaries
xyx2002OvO Oct 28, 2026
2b19da9
fix(checkpoint): preserve addressed locks across runtime directory al…
xyx2002OvO Oct 28, 2026
c000e71
fix(turn): recover missing terminal receipts without replacing origin…
xyx2002OvO Oct 28, 2026
817b1dc
fix(turn): retain main recovery safeguards across freshness integration
xyx2002OvO Oct 28, 2026
daee77d
test(turn): qualify ambiguous recovery and native host fixtures after…
xyx2002OvO Oct 28, 2026
a3d8fe7
test(turn): keep original observations through fresh direction and in…
xyx2002OvO Oct 28, 2026
4deab4d
fix(ci): restore module budget and checkpoint regression setup
xyx2002OvO Oct 28, 2026
834f6ae
fix(runtime): narrow native Windows permission APIs by platform
xyx2002OvO Oct 28, 2026
ae3da78
test(browser): assert original Turn readback and real owner recovery
xyx2002OvO Oct 28, 2026
16d2320
test(cli): qualify original Turn admission cost on matched native probes
xyx2002OvO Oct 28, 2026
e4b9b54
test(freshness): qualify batch IO and retain recovery fault boundaries
xyx2002OvO Oct 28, 2026
e3fd053
fix(freshness): settle reviewed maintainability and lint debt
xyx2002OvO Oct 29, 2026
2e45c0e
fix(freshness): qualify integrated recovery paths on Windows
xyx2002OvO Oct 29, 2026
0090c13
fix(freshness): preserve replan and native session recovery
xyx2002OvO Oct 29, 2026
51ed703
fix(turn): preserve journal recovery on Windows long paths
xyx2002OvO Oct 29, 2026
2c90033
fix(host): bind Windows launches and release failed cleanup resources
xyx2002OvO Oct 29, 2026
7e2a18e
fix(freshness): preserve recovery owners across main integration
xyx2002OvO Oct 29, 2026
77f597e
docs(freshness): retain recovery contracts and synthetic evidence
xyx2002OvO Oct 29, 2026
515c64b
test: calibrate native admission output budgets
xyx2002OvO Oct 29, 2026
f05f757
fix(heartbeat): retain admission failure and peer guidance
xyx2002OvO Oct 29, 2026
2ea6902
refactor(host): isolate Windows launch resource preparation
xyx2002OvO Oct 29, 2026
8009631
test(canary): isolate fixture Git namespaces from parent checkout
xyx2002OvO Oct 29, 2026
43c63c1
test(heartbeat): qualify complete failed-guard guidance growth once
xyx2002OvO Oct 29, 2026
0aae26e
test(freshness): preserve the complete original work-basis contract
xyx2002OvO Oct 29, 2026
32c27b5
fix(turn): retain the admitted native replan guard source
xyx2002OvO Oct 29, 2026
e9743f3
test(turn): distinguish unbound and malformed envelope plans
xyx2002OvO Oct 29, 2026
265d00c
test: align recovery fixtures with ownership and cleanup contracts
xyx2002OvO Oct 29, 2026
3c76400
fix: stage default replan CLI checkpoints after results
xyx2002OvO Oct 29, 2026
90490a4
fix: preserve the full replan CLI command prefix
xyx2002OvO Oct 30, 2026
344e9fa
fix: preserve pending direction through recovery and debit
xyx2002OvO Oct 30, 2026
e89e049
test(windows): release the actual lock holder before recovery
xyx2002OvO Oct 30, 2026
5f1a32a
fix(heartbeat): qualify composed recovery guidance after rebase
xyx2002OvO Oct 30, 2026
0448a0e
fix(recovery): retain original completion facts across terminal closeout
xyx2002OvO Oct 30, 2026
1c30d62
test(ui): qualify current packaged checkpoint recovery and reread
xyx2002OvO Oct 30, 2026
5868824
test(peer): execute continuation checks in the declared workspace
xyx2002OvO Oct 30, 2026
ebb8375
docs: capture final-head packaged recovery viewport
xyx2002OvO Oct 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// Actual packaged checkpoint controls + production owning HTTP/store/controller.
// Workspace navigation is synthetic; target /loopx responses are never fabricated.
import assert from "node:assert/strict";
import {spawn} from "node:child_process";
import {once} from "node:events";
import {createHash} from "node:crypto";
import {mkdir, readFile, writeFile} from "node:fs/promises";
import {resolve} from "node:path";
import {createInterface} from "node:readline";
import {createServer} from "node:net";
import {resolveTestPython} from "../../../../scripts/test-python.mjs";
import {launchBrowser, loadPlaywright, waitForHttp} from "../../../../examples/dashboard-browser-smoke-support.mjs";

const at=process.argv.indexOf("--output");
assert.ok(at>=0 && process.argv[at+1], "Declare a fresh evidence output directory");
const out=resolve(process.argv[at+1]);
await mkdir(out,{recursive:true});
const probe=createServer();probe.listen(0,"127.0.0.1");await once(probe,"listening");
process.env.LOOPX_PERSONAL_WORKSPACE_PORT=String(probe.address().port);
await new Promise((done,reject)=>probe.close(error=>error?reject(error):done()));
process.env.LOOPX_PERSONAL_WORKSPACE_PACKAGED="1";
const {repoRoot,port,startServer}=await import("../../../../examples/personal-workspace-browser/fixture.mjs");
const {openWorkspacePage,fetchWorkspaceBackend}=await import("../../../../examples/personal-workspace-browser/scenario-context.mjs");
const fixture=spawn(resolveTestPython({repoRoot}),["-u","apps/presentation/dashboard/smoke/checkpoint-recovery-http-fixture.py",resolve(out,"backend")],
{cwd:repoRoot,stdio:["pipe","pipe","pipe"],windowsHide:true});
const exited=once(fixture,"exit");
const lines=createInterface({input:fixture.stdout});const iterator=lines[Symbol.asyncIterator]();
let diagnostic="";fixture.stderr.on("data",chunk=>{diagnostic+=String(chunk);});
async function next(){const line=await iterator.next();assert.equal(line.done,false,diagnostic);return JSON.parse(line.value);}
async function command(value){fixture.stdin.write(`${value}\n`);return next();}
async function artifact(path){return {path,sha256:createHash("sha256").update(await readFile(path)).digest("hex")};}
let server,browser,workspace;
const requests=[];
try {
const {origin,session,original_identity}=await next();
server=await startServer();
const url=`http://127.0.0.1:${port}/chat/?statusUrl=/status.json`;
await waitForHttp(url);
browser=await launchBrowser(loadPlaywright().chromium);
workspace=await openWorkspacePage({newPage:options=>browser.newPage({locale:"zh-CN",...options})},url,{
beforeGoto:async(_api,page)=>{
page.__loopxRuntime.sessions.set(session.session_id,session);
// Only the unrelated workspace/navigation uses the existing synthetic API.
// Every target operation, including reads across reload, uses its owning server.
await page.route(`**/api/chat/sessions/${session.session_id}/loopx`,async route=>{
const request=route.request();
const body=request.method()==="POST"?request.postDataJSON():null;
const response=await fetchWorkspaceBackend(route,origin);
requests.push({method:request.method(),body,status:response.status(),response:await response.json()});
await route.fulfill({response});
});
},
});
const {page}=workspace;
await page.locator(".personal-goal-link",{hasText:"Product Release"}).click();
await page.getByRole("navigation",{name:"Goal 视图"}).getByRole("button",{name:"对话",exact:true}).click();
const section=page.getByRole("region",{name:"LoopX 运行模式"});
const retained=page.getByText("LoopX · 结果已保留,待协调员核验",{exact:true});
await retained.waitFor({timeout:60000});
const before=await command("inspect");
assert.deepEqual(before.counts,{result:1,debit:0});assert.equal(before.dispatches.length,0);
await page.reload();await retained.waitFor({timeout:60000});
const reloaded=await command("inspect");
assert.deepEqual(reloaded.counts,before.counts);assert.equal(reloaded.dispatches.length,0);
const writes=()=>requests.filter(row=>row.method==="POST" && !["operations","inspect"].includes(row.body?.operation));
assert.equal(writes().length,0,"Reload must not dispatch or mutate execution");
const button=page.getByRole("button",{name:"继续核验",exact:true});
await button.scrollIntoViewIfNeeded();
const screenshots=[];
let path=resolve(out,"retained-desktop.png");await page.screenshot({path,animations:"disabled"});screenshots.push(await artifact(path));
await button.click();
let after;const deadline=Date.now()+300000;
while(Date.now()<deadline){
after=await command("inspect");assert.deepEqual(after.failures,[]);
assert.ok(after.counts.debit<=1 && after.dispatches.length<=1);
if(after.counts.debit===1 && after.decisions.length===1)break;
await new Promise(done=>setTimeout(done,500));
}
assert.deepEqual(after.counts,{result:1,debit:1});assert.equal(after.dispatches.length,1);
assert.equal(after.result_sha256,before.result_sha256);
assert.equal(after.upstream_thread_id,before.upstream_thread_id,"Continue retains the original SDK session");
const posted=writes();
assert.equal(posted.length,1);assert.equal(posted[0].body.operation,"resume");assert.equal(posted[0].status,200);
await page.reload();
await page.getByText("LoopX · 已暂停",{exact:true}).waitFor({timeout:60000});
assert.equal(await retained.count(),0,"Settled native readback clears the pending-result label");
const replayed=await command("replay");
assert.deepEqual(replayed.counts,after.counts);assert.equal(replayed.dispatches.length,1);
assert.deepEqual(replayed.replayed_identity,original_identity);
assert.equal(replayed.result_sha256,before.result_sha256);
await page.setViewportSize({width:390,height:844});await page.emulateMedia({reducedMotion:"reduce"});
await page.getByRole("button",{name:"恢复推进",exact:true}).scrollIntoViewIfNeeded();
path=resolve(out,"settled-narrow.png");await page.screenshot({path,animations:"disabled"});screenshots.push(await artifact(path));
const unavailable=await command("unavailable");
assert.equal(unavailable.snapshot.coordinator_checkpoint.stage,"observation_unavailable");
assert.equal(unavailable.snapshot.coordinator_checkpoint.settlement_identity,undefined);
await page.reload();
await page.getByText("LoopX · 核验信息暂不可用",{exact:true}).waitFor({timeout:60000});
assert.equal(await page.getByText("原执行尚未完成结算",{exact:false}).count(),0);
const reread=page.getByRole("button",{name:"重新读取",exact:true});
const readsBeforeReread=requests.filter(row=>row.method==="GET").length;
await reread.click();
await page.waitForFunction(()=>Array.from(document.querySelectorAll("button"))
.some(button=>button.textContent?.trim()==="重新读取" && !button.disabled));
assert.ok(requests.filter(row=>row.method==="GET").length>readsBeforeReread,
"Reread must complete a real owning-backend observation");
assert.equal(writes().length,1,"Unavailable observation reread is not an execution request");
const held=await command("inspect");
assert.deepEqual(held.counts,{result:1,debit:1});assert.equal(held.dispatches.length,1);
path=resolve(out,"unavailable-narrow.png");await page.screenshot({path,animations:"disabled"});screenshots.push(await artifact(path));
await page.setViewportSize({width:1512,height:982});
path=resolve(out,"unavailable-desktop.png");await page.screenshot({path,animations:"disabled"});screenshots.push(await artifact(path));
await command("restore_observation");
await page.reload();
await page.getByRole("button",{name:"恢复推进",exact:true}).waitFor({timeout:60000});
assert.equal(writes().length,1);
const saved=await command("save");
assert.equal(writes().length,1);
assert.equal(workspace.errors.length,0,workspace.errors.join("\n"));
await writeFile(resolve(out,"http-observations.json"),JSON.stringify(requests,null,2));
const proof={packaged:true,target_http_mocked:false,transport:"deterministic_sdk",paid_calls:0,
non_owning_shell_fixture:"existing personal-workspace navigation/status API; target sessions/loopx uses production owner",
browser_version:browser.version(),clicked_continue_review:true,reloads:4,
unavailable_observation:{read_only_reread:true,restored:true,counts:held.counts},
original_identity,settled_identity:saved.settled_identity,replayed_identity:replayed.replayed_identity,
result_sha256_before:before.result_sha256,result_sha256_after:after.result_sha256,
business_counts_before:before.counts,business_counts_after:after.counts,business_counts_replayed:replayed.counts,
direction_dispatches:saved.dispatches.length,implementation_dispatches:0,
session_id_before:before.session_id,session_id_after:saved.session_id,
upstream_thread_id_before:before.upstream_thread_id,upstream_thread_id_after:saved.upstream_thread_id,
errors:workspace.errors,screenshots,native_evidence:[]};
for(const name of ["before.json","first-result.json","inspect.json","replay.json","save.json","unavailable.json","restore_observation.json"])
proof.native_evidence.push(await artifact(resolve(out,"backend",name)));
proof.native_evidence.push(await artifact(resolve(out,"http-observations.json")));
await writeFile(resolve(out,"proof.json"),JSON.stringify(proof,null,2));
console.log("checkpoint-recovery: passed (packaged click/reload, production owning HTTP/controller/native checkpoint, original identity/session/result, one debit and zero replay increments; deterministic SDK)");
} catch(error){
await writeFile(resolve(out,"http-observations-failed.json"),JSON.stringify(requests,null,2));
await writeFile(resolve(out,"failure.txt"),`${String(error)}\n${diagnostic}`);
if(workspace)await writeFile(resolve(out,"failure-body.txt"),await workspace.page.locator("body").innerText());
throw error;
} finally {
await workspace?.close();await browser?.close();server?.kill("SIGTERM");
fixture.stdin.end();if(fixture.exitCode===null)await exited;lines.close();
await writeFile(resolve(out,"backend-stderr.txt"),diagnostic);
}
Loading
Loading