





















@@ -66,6 +66,65 @@ function cloneBigIntStatWith(
6666}
67676868describe("embedded attempt session lock lifecycle", () => {
69+it("recognizes an unchanged session file trusted by the previous prompt release", async () => {
70+const sessionFile = await createTempSessionFile();
71+const options = { ...lockOptions, sessionFile };
72+const first = await createEmbeddedAttemptSessionLockController({
73+ acquireSessionWriteLock,
74+lockOptions: options,
75+});
76+77+expect(await first.readTrustedCurrentSessionFileSnapshot()).toBeUndefined();
78+await first.releaseForPrompt();
79+await first.dispose();
80+81+const second = await createEmbeddedAttemptSessionLockController({
82+ acquireSessionWriteLock,
83+lockOptions: options,
84+});
85+expect(await second.readTrustedCurrentSessionFileSnapshot()).toBeDefined();
86+await second.dispose();
87+});
88+89+it("does not trust a session file changed after the previous prompt release", async () => {
90+const sessionFile = await createTempSessionFile();
91+const options = { ...lockOptions, sessionFile };
92+const first = await createEmbeddedAttemptSessionLockController({
93+ acquireSessionWriteLock,
94+lockOptions: options,
95+});
96+await first.releaseForPrompt();
97+await first.dispose();
98+await fs.appendFile(sessionFile, '{"type":"message","id":"external"}\n', "utf8");
99+100+const second = await createEmbeddedAttemptSessionLockController({
101+ acquireSessionWriteLock,
102+lockOptions: options,
103+});
104+expect(await second.readTrustedCurrentSessionFileSnapshot()).toBeUndefined();
105+await second.dispose();
106+});
107+108+it("publishes a known owned append for the next attempt", async () => {
109+const sessionFile = await createTempSessionFile();
110+const options = { ...lockOptions, sessionFile };
111+const first = await createEmbeddedAttemptSessionLockController({
112+ acquireSessionWriteLock,
113+lockOptions: options,
114+});
115+await fs.appendFile(sessionFile, '{"type":"message","id":"owned"}\n', "utf8");
116+first.refreshAfterOwnedSessionWrite();
117+await first.releaseForPrompt();
118+await first.dispose();
119+120+const second = await createEmbeddedAttemptSessionLockController({
121+ acquireSessionWriteLock,
122+lockOptions: options,
123+});
124+expect(await second.readTrustedCurrentSessionFileSnapshot()).toBeDefined();
125+await second.dispose();
126+});
127+69128it("serializes embedded attempts that share a session file owner", async () => {
70129const sessionFile = await createTempSessionFile();
71130const firstOwner = await acquireEmbeddedAttemptSessionFileOwner({ sessionFile });
@@ -1045,6 +1104,90 @@ describe("embedded attempt session lock lifecycle", () => {
10451104expect(release).toHaveBeenCalledTimes(3);
10461105});
104711061107+it("authorizes entry-cache advancement only under the exact trusted file lock", async () => {
1108+const sessionFile = await createTempSessionFile();
1109+const release = vi.fn(async () => {});
1110+const acquireSessionWriteLockLocal = vi.fn(async () => ({ release }));
1111+const controller = await createEmbeddedAttemptSessionLockController({
1112+acquireSessionWriteLock: acquireSessionWriteLockLocal,
1113+lockOptions: { ...lockOptions, sessionFile },
1114+});
1115+1116+await controller.releaseForPrompt();
1117+const stat = await fs.stat(sessionFile, { bigint: true });
1118+const snapshot = {
1119+dev: stat.dev,
1120+ino: stat.ino,
1121+size: stat.size,
1122+mtimeNs: stat.mtimeNs,
1123+ctimeNs: stat.ctimeNs,
1124+};
1125+1126+expect(controller.canAdvanceSessionEntryCache(snapshot)).toBe(false);
1127+await expect(
1128+controller.withSessionWriteLock(() => {
1129+expect(controller.canAdvanceSessionEntryCache(snapshot)).toBe(true);
1130+return "locked";
1131+}),
1132+).resolves.toBe("locked");
1133+expect(controller.canAdvanceSessionEntryCache(snapshot)).toBe(false);
1134+});
1135+1136+it("publishes an exact owned snapshot only while the write lock is active", async () => {
1137+const sessionFile = await createTempSessionFile();
1138+const controller = await createEmbeddedAttemptSessionLockController({
1139+acquireSessionWriteLock: vi.fn(async () => ({
1140+release: vi.fn(async () => {}),
1141+})),
1142+lockOptions: { ...lockOptions, sessionFile },
1143+});
1144+const readSnapshot = async () => {
1145+const stat = await fs.stat(sessionFile, { bigint: true });
1146+return {
1147+dev: stat.dev,
1148+ino: stat.ino,
1149+size: stat.size,
1150+mtimeNs: stat.mtimeNs,
1151+ctimeNs: stat.ctimeNs,
1152+};
1153+};
1154+const initialSnapshot = await readSnapshot();
1155+1156+expect(controller.publishOwnedSessionFileSnapshot(initialSnapshot)).toBe(false);
1157+await controller.withSessionWriteLock(async () => {
1158+expect(controller.publishOwnedSessionFileSnapshot(initialSnapshot)).toBe(true);
1159+await fs.appendFile(sessionFile, '{"type":"message","id":"owned"}\n', "utf8");
1160+expect(controller.publishOwnedSessionFileSnapshot(initialSnapshot)).toBe(false);
1161+expect(controller.publishOwnedSessionFileSnapshot(await readSnapshot())).toBe(true);
1162+});
1163+expect(controller.publishOwnedSessionFileSnapshot(await readSnapshot())).toBe(false);
1164+await controller.dispose();
1165+});
1166+1167+it("publishes only an unchanged repair-validated snapshot while retaining the lock", async () => {
1168+const sessionFile = await createTempSessionFile();
1169+const acquireSessionWriteLockLocal = vi.fn(async () => ({
1170+release: vi.fn(async () => {}),
1171+}));
1172+const controller = await createEmbeddedAttemptSessionLockController({
1173+acquireSessionWriteLock: acquireSessionWriteLockLocal,
1174+lockOptions: { ...lockOptions, sessionFile },
1175+});
1176+const stat = await fs.stat(sessionFile, { bigint: true });
1177+const snapshot = {
1178+dev: stat.dev,
1179+ino: stat.ino,
1180+size: stat.size,
1181+mtimeNs: stat.mtimeNs,
1182+ctimeNs: stat.ctimeNs,
1183+};
1184+1185+expect(controller.publishValidatedSessionFileSnapshot(snapshot)).toBe(true);
1186+await fs.appendFile(sessionFile, '{"type":"message","id":"external"}\n', "utf8");
1187+expect(controller.publishValidatedSessionFileSnapshot(snapshot)).toBe(false);
1188+await controller.dispose();
1189+});
1190+10481191it("refreshes the prompt fence after an owned session manager append", async () => {
10491192const sessionFile = await createTempSessionFile();
10501193const release = vi.fn(async () => {});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。