Skip to content

Commit cc91ff0

Browse files
committed
fix(release): stabilize config restart QA
1 parent e842869 commit cc91ff0

3 files changed

Lines changed: 52 additions & 0 deletions

File tree

qa/scenarios/config/config-restart-capability-flip.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ steps:
6666
- ref: env
6767
- Capability flip
6868
- ref: sessionKey
69+
- set: setupStartIndex
70+
value:
71+
expr: state.getSnapshot().messages.length
6972
- try:
7073
actions:
7174
- call: patchConfig
@@ -92,6 +95,15 @@ steps:
9295
expr: config.setupPrompt
9396
timeoutMs:
9497
expr: liveTurnTimeoutMs(env, 30000)
98+
- call: waitForOutboundMessage
99+
args:
100+
- ref: state
101+
- lambda:
102+
params: [candidate]
103+
expr: "candidate.conversation.id === 'qa-operator' && String(candidate.text ?? '').includes('Protocol note')"
104+
- expr: liveTurnTimeoutMs(env, 30000)
105+
- sinceIndex:
106+
ref: setupStartIndex
95107
- call: readEffectiveTools
96108
saveAs: beforeTools
97109
args:

src/agents/session-write-lock.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import fsSync from "node:fs";
12
import fs from "node:fs/promises";
23
import os from "node:os";
34
import path from "node:path";
@@ -763,6 +764,35 @@ describe("acquireSessionWriteLock", () => {
763764
}
764765
});
765766

767+
it("retries when a reported stale same-process lock disappears before recovery", async () => {
768+
await withTempSessionLockFile(async ({ sessionFile, lockPath }) => {
769+
await fs.writeFile(
770+
lockPath,
771+
JSON.stringify({
772+
pid: process.pid,
773+
createdAt: new Date().toISOString(),
774+
starttime: FAKE_STARTTIME,
775+
}),
776+
"utf8",
777+
);
778+
let resolverCalls = 0;
779+
testing.setProcessStartTimeResolverForTest((pid) => {
780+
if (pid !== process.pid) {
781+
return null;
782+
}
783+
resolverCalls += 1;
784+
if (resolverCalls === 1) {
785+
fsSync.rmSync(lockPath, { force: true });
786+
}
787+
return FAKE_STARTTIME;
788+
});
789+
790+
const lock = await acquireSessionWriteLock({ sessionFile, timeoutMs: 500 });
791+
await lock.release();
792+
expect(resolverCalls).toBeGreaterThan(0);
793+
});
794+
});
795+
766796
it("removes held locks on termination signals", async () => {
767797
const signals = ["SIGINT", "SIGTERM", "SIGQUIT", "SIGABRT"] as const;
768798
const originalKill = process.kill.bind(process);

src/agents/session-write-lock.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,16 @@ async function removeReportedStaleLockIfStillStale(params: {
560560
}): Promise<boolean> {
561561
const nowMs = Date.now();
562562
const payload = await readLockPayload(params.lockPath);
563+
if (payload === null) {
564+
try {
565+
await fs.access(params.lockPath);
566+
} catch (error) {
567+
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
568+
return true;
569+
}
570+
throw error;
571+
}
572+
}
563573
const inspected = inspectLockPayloadForSession({
564574
payload,
565575
staleMs: params.staleMs,

0 commit comments

Comments
 (0)