跳转至

English

Recipe:持久本地状态底座

1. 场景与非场景

适用:需要持久化事件日志并保证顺序与完整性,重建或校验派生快照,以及检查或恢复协作式单写者锁。

不适用:需要在 Foundation 定义 workflow 状态机(禁止);需要抵御同权限恶意进程(fencing 不承诺该场景)。

2. 架构选择及能力 ID

首选能力:foundation.harness.state-store(append-only 事件、hash chain、快照与锁检查/恢复)。事件含义与 reducer 转移由调用方拥有。

3. 前置条件与信任边界

  • STATE_GENESIS_DIGEST 作为链起点。
  • 信任边界:事件日志是唯一权威,snapshot 为派生缓存;confirmOwnerTerminated 是调用方提供的外部信任锚,不承诺抵御同权限恶意进程。

4. 最小代码

import { mkdtempSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import {
  openStateStore,
  appendEvent,
  readEvents,
  writeSnapshot,
  readSnapshot,
  inspectStateStoreLock,
  recoverStateStoreLock,
} from "skill-family-harness-node";

const root = mkdtempSync(join(tmpdir(), "sf-state-"));
const store = openStateStore(root, { owner: "writer-a", expectedSchemas: [] });
appendEvent(store, { eventType: "demo", payload: { n: 1 } });
writeSnapshot(store, readEvents(store));
const snap = readSnapshot(store);
const lock = inspectStateStoreLock(root); // { owner, fencing, ageMs, recovering }
await recoverStateStoreLock(root, {
  expectedOwner: lock.owner,
  expectedFencing: lock.fencing,
  confirmOwnerTerminated: true,
});

以上代码展示了开库、追加事件、写快照、查锁与显式恢复的顺序。

5. 预期输出与证据

readEvents 返回追加的事件,readSnapshot 返回派生快照,inspectStateStoreLock 返回 owner/fencing/ageMs/recovering。证据:packages/skill-family-harness-node/test/state-store.test.mjs(含 34 处断言)。

6. 安全/失败负例

// 负例:第二写者立即收到 store-locked
const other = openStateStore(root, { owner: "writer-b", expectedSchemas: [] });
// 抛 HarnessError:details.kind = "store-locked"

hash chain 断裂、锁 fencing 不匹配、恢复缺少 confirmOwnerTerminated 均失败关闭。

7. 可复制验证命令

node --test packages/skill-family-harness-node/test/state-store.test.mjs

8. 调用方继续拥有的业务逻辑

  • 事件业务含义、reducer 转移。
  • confirmOwnerTerminated 信任锚(Foundation 之外确认旧写者已终止)。

9. 升级与回滚注意事项

  • 状态底座只提供机制;业务状态机/终态归 loop-agent。
  • 崩溃遗留锁需外部取证后显式恢复,不自动偷锁;系统保持可诊断锁死而非静默覆盖。