fix(data): 四處情緒/sync 狀態的讀改寫還沒進鎖,等於繞過了上次的修正
B4 加了 updateJson/updateEmotion,但這幾個呼叫點還是「loadEmotion → 改 → writeJson」的裸讀改寫,鎖形同不存在: - sleep 的 emotion-decay、remember --emotion(每輪對話的熱路徑)、 Stop hook 與 SessionEnd hook 的時間衰減,四處都改走 pl.updateEmotion()。 衰減與 delta 的算法一個字都沒動,只是把讀與寫收進同一把鎖裡。 - sync.json 同理:背景 sync push 跟前景指令會同時寫它,兩邊撞上時後寫的會把 pushed_at/overwrites 整段蓋掉——覆蓋紀錄就這樣安靜地消失。新增 updateSyncState()(帶鎖),六處 loadSyncState + saveSyncState 成對使用全部 改過去;補預設欄位的邏輯抽成 normalizeSyncState() 給兩邊共用。 saveSyncState 沒有呼叫端了,直接移掉,免得下次又有人拿它裸寫。 sync.json 的欄位格式與 overwrites 留 10 筆的行為都沒變。 selftest 448 項(+1):新增「並行 8 次 remember --emotion 跟循序結果一樣」, 把對話熱路徑的情緒寫入也蓋進競態測試——原本只蓋到 emotion --apply。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -870,6 +870,23 @@ console.log("\n並行寫入:read-modify-rewrite 不能吃掉同時 append 的
|
||||
const parallel = joyOf();
|
||||
check("並行 8 次 `emotion --apply` 跟循序 8 次結果一樣(情緒更新不遺失)",
|
||||
Math.abs(parallel - sequential) < 0.01, `循序 ${sequential} / 並行 ${parallel}`);
|
||||
|
||||
// ②-b `remember --emotion` 是每一輪對話都會走的熱路徑,它的情緒寫入也必須在鎖裡
|
||||
const sayArgs = ["remember", "--session", "sess-race-9999", "--role", "user",
|
||||
"--text", "熱路徑", "--salience", "10", "--emotion", "joy=+5"];
|
||||
resetJoy();
|
||||
for (let i = 0; i < 8; i += 1) cli(sayArgs);
|
||||
const saySequential = joyOf();
|
||||
resetJoy();
|
||||
startAt = Date.now() + 900;
|
||||
await Promise.all(Array.from({ length: 8 }, () => child(`${BARRIER}
|
||||
const { spawnSync } = await import("node:child_process");
|
||||
waitUntil(${startAt});
|
||||
spawnSync(process.execPath, [${JSON.stringify(CLI)}, ...${JSON.stringify(sayArgs)}], { stdio: "ignore" });`)));
|
||||
const sayParallel = joyOf();
|
||||
check("並行 8 次 `remember --emotion`(對話熱路徑)跟循序結果一樣",
|
||||
Math.abs(sayParallel - saySequential) < 0.01, `循序 ${saySequential} / 並行 ${sayParallel}`);
|
||||
|
||||
cli(["release", "--session", "sess-race-9999"]);
|
||||
|
||||
// ③ withFileLock 本身:N 個程序各做一次 read-increment-write,一次都不能掉
|
||||
|
||||
Reference in New Issue
Block a user