UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

428 lines (427 loc) • 25.2 kB
import { strict as assert } from "node:assert"; import { MAILBOX_INVALID_PEER_META_CODE, MAILBOX_TOMBSTONED_RECIPIENT_CODE } from "../mailbox-store.js"; import { beginContract } from "./contract-harness.js"; export const MAILBOX_CONTRACT_SCOPE = "default"; const msg = (content, sentAt = 1000) => ({ content, sentAt }); async function withStores(mk, fn) { const live = []; const make = () => { const s = mk(); live.push(s); return s; }; try { await fn(make); } finally { for (const s of live.splice(0)) s.close?.(); } } export async function mailboxStoreContract(mk, runAssertion) { const { run: runRaw, settle } = beginContract(runAssertion); const run = (name, fn) => runRaw(name, () => withStores(mk, fn)); const S = MAILBOX_CONTRACT_SCOPE; run("append 铸单调 seq;claimLease 取全部可见消息(不删);ack 才删;活租约=单消费者", async (make) => { const s = make(); assert.equal(await s.append(S, "a1", msg("m1")), 1); assert.equal(await s.append(S, "a1", msg("m2")), 2); assert.equal(await s.peekCount(S, "a1"), 2); const lease = await s.claimLease(S, "a1", "w1", 60_000, 10_000); assert.deepEqual(lease.messages.map((m) => m.content), ["m1", "m2"]); assert.equal(lease.maxSeq, 2); assert.equal(await s.claimLease(S, "a1", "w2", 60_000, 20_000), null); assert.equal(await s.peekCount(S, "a1"), 2); await s.ack(S, "a1", "w1", 2); assert.equal(await s.peekCount(S, "a1"), 0); }); run("X-1 无损:lease 过期/release 后消息按原 seq 回可见;seq 在箱的一生中永不复用", async (make) => { const s = make(); await s.append(S, "a1", msg("m1")); const l1 = await s.claimLease(S, "a1", "w1", 1_000, 10_000); assert.equal(l1.maxSeq, 1); const l2 = await s.claimLease(S, "a1", "w2", 1_000, 20_000); assert.deepEqual(l2.messages.map((m) => m.seq), [1]); await s.releaseLease(S, "a1", "w2"); const l3 = await s.claimLease(S, "a1", "w3", 1_000, 20_500); assert.deepEqual(l3.messages.map((m) => m.seq), [1]); await s.ack(S, "a1", "w3", 1); assert.equal(await s.append(S, "a1", msg("m2")), 2); }); run("lease 窗内 append:后到消息在下次 claim 时可见(lease 只覆盖 claim 时刻快照)", async (make) => { const s = make(); await s.append(S, "a1", msg("m1")); const l = await s.claimLease(S, "a1", "w1", 60_000, 10_000); assert.equal(l.maxSeq, 1); await s.append(S, "a1", msg("m2")); await s.ack(S, "a1", "w1", l.maxSeq); assert.equal(await s.peekCount(S, "a1"), 1); const next = await s.claimLease(S, "a1", "w2", 60_000, 20_000); assert.deepEqual(next.messages.map((m) => m.content), ["m2"]); }); run("drop 清整箱;reap 按最新消息龄整箱老化", async (make) => { const s = make(); await s.append(S, "a1", msg("old", 1_000)); await s.append(S, "a2", msg("fresh", 90_000)); assert.equal(await s.reap(S, 100_000, { maxAgeMs: 50_000 }), 1); assert.equal(await s.peekCount(S, "a1"), 0); assert.equal(await s.peekCount(S, "a2"), 1); await s.drop(S, "a2"); assert.equal(await s.peekCount(S, "a2"), 0); }); run("RB-86 空箱 ⇒ null:没消息就不发租约(既不假装投递,也不 fence 掉后来真正的消费者)", async (make) => { const s = make(); assert.equal(await s.claimLease(S, "never-written", "o1", 60_000, 1_000), null, "从未写过的箱"); await s.append(S, "a1", msg("m1")); const first = await s.claimLease(S, "a1", "o1", 60_000, 1_000); await s.ack(S, "a1", "o1", first.maxSeq); assert.equal(await s.peekCount(S, "a1"), 0); assert.equal(await s.claimLease(S, "a1", "o1", 60_000, 2_000), null, "全部 ack 后箱内零可见消息"); assert.equal(await s.claimLease(S, "a2", "ghost", 60_000, 3_000), null); await s.append(S, "a2", msg("real", 4_000)); const real = await s.claimLease(S, "a2", "o2", 60_000, 4_000); assert.deepEqual(real?.messages.map((m) => m.content), ["real"], "空取不该留下 fence 后来者的幽灵租约"); }); run("RB-261 守恒律:一条消息在被 ack 消费之前必须至少投递过一次(maxSeq 不得覆盖未投递项)", async (make) => { const s = make(); const appended = ["m1", "m2", "m3"]; for (const [i, c] of appended.entries()) await s.append(S, "a1", msg(c, 1_000 + i)); const delivered = new Set(); let round = 0; while ((await s.peekCount(S, "a1")) > 0) { round += 1; assert.ok(round < 10, "要么有限轮内收敛,要么就是投递不动了"); const owner = `w${round}`; const lease = await s.claimLease(S, "a1", owner, 60_000, 10_000 + round); assert.notEqual(lease, null, "还有可见消息时 claimLease 不得返回 null"); for (const m of lease.messages) delivered.add(m.content); await s.ack(S, "a1", owner, lease.maxSeq); } assert.deepEqual([...delivered].sort(), [...appended].sort(), "每条被消费掉的消息都必须先被投递过"); }); run("releaseLease owner-fenced:非持有者的 release 是 no-op(活租约的单消费者窗口不被外人撬开)", async (make) => { const s = make(); await s.append(S, "a1", msg("m1")); const held = await s.claimLease(S, "a1", "owner-A", 60_000, 10_000); assert.equal(held.messages.length, 1); await s.releaseLease(S, "a1", "not-the-owner"); assert.equal(await s.claimLease(S, "a1", "rival", 60_000, 11_000), null, "A 的活租约必须仍然 fence 住 rival"); await s.releaseLease(S, "a1", "owner-A"); const after = await s.claimLease(S, "a1", "rival", 60_000, 12_000); assert.deepEqual(after?.messages.map((m) => m.seq), [1], "归还后同一条按原 seq 回可见"); }); run("peerMeta 回环:典型 typed 记录逐字节回读;缺席保持缺席(pre-385/foreign 记录语义);空对象也是「在场」", async (make) => { const s = make(); const full = { fromSession: "sess_1", fromMode: "prompting", senderKey: "k-1", kind: "peer_message", fromScope: "team/a b", gateReceiptId: "gr-9", }; await s.append(S, "a1", { content: "typed", sentAt: 1_000, peerMeta: full }); await s.append(S, "a1", { content: "plain", sentAt: 1_001 }); await s.append(S, "a1", { content: "empty-meta", sentAt: 1_002, peerMeta: {} }); const lease = await s.claimLease(S, "a1", "w1", 60_000, 10_000); assert.deepEqual(lease.messages.map((m) => m.content), ["typed", "plain", "empty-meta"]); assert.deepEqual(lease.messages[0].peerMeta, full, "六字段逐字节回读"); assert.equal("peerMeta" in lease.messages[1], false, "未带 peerMeta 的记录回读时该键必须缺席(不是 undefined 值)"); assert.deepEqual(lease.messages[2].peerMeta, {}, "空对象=在场但无字段,与缺席区分"); }); run("peerMeta 坏值响亮:garbage 以具名码拒 append,且零副作用(不入箱、不耗 seq、不动租约)", async (make) => { const s = make(); const seqBefore = await s.append(S, "a1", { content: "anchor", sentAt: 1_000 }); const held = await s.claimLease(S, "a1", "holder", 60_000, 10_000); assert.equal(held?.messages.length, 1); const codeOf = (e) => e?.code; class Meta { fromSession = "s"; } const hiddenKey = { fromSession: "s" }; Object.defineProperty(hiddenKey, "bogus", { value: 1, enumerable: false }); for (const [label, bad] of [ ["fromMode 集外值", { fromMode: "root" }], ["kind 集外值", { kind: "gossip" }], ["未知键", { fromSession: "s", bogus: 1 }], ["空字符串", { senderKey: "" }], ["非字符串", { gateReceiptId: 7 }], ["数组", ["fromSession"]], ["null", null], ["字符串", "fromSession=x"], ["Date", new Date(0)], ["Map", new Map()], ["class 实例", new Meta()], ["symbol 键", { fromSession: "s", [Symbol("hidden")]: 1 }], ["不可枚举的未知键", hiddenKey], ]) { let thrown; try { await s.append(S, "a1", { content: `bad:${label}`, sentAt: 2_000, peerMeta: bad }); } catch (e) { thrown = e; } assert.notEqual(thrown, undefined, `${label}:必须拒`); assert.equal(codeOf(thrown), MAILBOX_INVALID_PEER_META_CODE, `${label}:拒必须带码`); } assert.equal(await s.peekCount(S, "a1"), 1, "被拒的 append 不得入箱"); assert.equal(await s.claimLease(S, "a1", "rival", 60_000, 11_000), null, "被拒的 append 不得动活租约"); await s.ack(S, "a1", "holder", held.maxSeq); assert.equal(await s.append(S, "a1", { content: "next", sentAt: 3_000 }), seqBefore + 1, "被拒的 append 不得消耗 seq"); }); run("peerMeta 不串引用:消费者改写租约批里的 peerMeta,不得改到下次投递的记录", async (make) => { const s = make(); await s.append(S, "a1", { content: "m1", sentAt: 1_000, peerMeta: { fromMode: "bypass", fromSession: "sess_1" } }); const first = await s.claimLease(S, "a1", "w1", 1_000, 10_000); first.messages[0].peerMeta.fromSession = "forged"; await s.releaseLease(S, "a1", "w1"); const again = await s.claimLease(S, "a1", "w2", 1_000, 20_000); assert.deepEqual(again.messages[0].peerMeta, { fromMode: "bypass", fromSession: "sess_1" }, "重投的记录必须是原样"); }); await settle(); } export async function mailboxAckOwnershipContract(mk, runAssertion) { const { run: runRaw, settle } = beginContract(runAssertion); const run = (name, fn) => runRaw(name, () => withStores(mk, fn)); const S = MAILBOX_CONTRACT_SCOPE; run("a non-holder's ack does not delete messages held under another owner's LIVE lease", async (make) => { const s = make(); await s.append(S, "a1", { content: "m1", sentAt: 1 }); await s.append(S, "a1", { content: "m2", sentAt: 2 }); const lease = await s.claimLease(S, "a1", "consumer-A", 60_000, 10_000); assert.equal(lease?.messages.length, 2); await s.ack(S, "a1", "stale-actor", lease.maxSeq); assert.equal(await s.peekCount(S, "a1"), 2, "the messages must survive — this caller never held the lease"); }); run("angle 4 — internal consistency: releaseLease and ack now apply the SAME owner fence (was the asymmetry that proved this was an oversight)", async (make) => { const s = make(); await s.append(S, "a1", { content: "m1", sentAt: 1 }); await s.claimLease(S, "a1", "real-owner", 60_000, 10_000); await s.releaseLease(S, "a1", "wrong-owner"); await s.ack(S, "a1", "wrong-owner", 1); assert.equal(await s.peekCount(S, "a1"), 1, "neither operation should have touched anything"); }); run("angle 5 — ack with no lease EVER claimed is a no-op, not a silent wipe", async (make) => { const s = make(); await s.append(S, "a1", { content: "m1", sentAt: 1 }); await s.ack(S, "a1", "nobody", Number.MAX_SAFE_INTEGER); assert.equal(await s.peekCount(S, "a1"), 1); }); run("the legitimate holder's own ack still works (regression check — the fix must not break the happy path)", async (make) => { const s = make(); await s.append(S, "a1", { content: "m1", sentAt: 1 }); await s.append(S, "a1", { content: "m2", sentAt: 2 }); const lease = await s.claimLease(S, "a1", "consumer-A", 60_000, 10_000); await s.ack(S, "a1", "consumer-A", lease.maxSeq); assert.equal(await s.peekCount(S, "a1"), 0); }); run("angle 3 in detail — the real loss sequence (stale owner outlives its own expired lease, a NEW owner has since taken over): the new owner's custody survives", async (make) => { const s = make(); await s.append(S, "a1", { content: "ship-the-release", sentAt: 1 }); await s.append(S, "a1", { content: "notify-oncall", sentAt: 2 }); const leaseA = await s.claimLease(S, "a1", "consumer-A", 1_000, 1_000); assert.equal(leaseA?.messages.length, 2); const leaseB = await s.claimLease(S, "a1", "consumer-B", 60_000, 5_000); assert.equal(leaseB?.messages.length, 2); await s.ack(S, "a1", "consumer-A", leaseA.maxSeq); assert.equal(await s.peekCount(S, "a1"), 2, "B's live custody must survive A's stale ack"); await s.ack(S, "a1", "consumer-B", leaseB.maxSeq); assert.equal(await s.peekCount(S, "a1"), 0); }); await settle(); } export async function mailboxBundledOnlyContract(mk, runAssertion) { const { run: runRaw, settle } = beginContract(runAssertion); const run = (name, fn) => runRaw(name, () => withStores(mk, fn)); run("RB-251:handle 含 NUL 被两个后端一致拒绝,且不得跨 (scope,handle) 串箱", async (make) => { const s = make(); const NUL = String.fromCharCode(0); await assert.rejects(s.append("s", `a${NUL}b`, msg("secret"))); assert.equal(await s.peekCount(`s${NUL}a`, "b"), 0, "歧义键下不得出现串箱可读"); await s.append("s", "plain", msg("ok")); assert.equal(await s.peekCount("s", "plain"), 1); }); run("多租户:同名 handle 在不同 scope 下是两个互不可见的箱(各自独立铸 seq)", async (make) => { const s = make(); assert.equal(await s.append("tenant-a", "shared-handle", msg("for-a")), 1); assert.equal(await s.append("tenant-b", "shared-handle", msg("for-b")), 1, "另一个 scope 的箱独立铸号"); assert.equal(await s.peekCount("tenant-a", "shared-handle"), 1); const a = await s.claimLease("tenant-a", "shared-handle", "w", 60_000, 10_000); assert.deepEqual(a.messages.map((m) => m.content), ["for-a"]); const b = await s.claimLease("tenant-b", "shared-handle", "w", 60_000, 10_000); assert.deepEqual(b.messages.map((m) => m.content), ["for-b"]); await s.ack("tenant-a", "shared-handle", "w", a.maxSeq); assert.equal(await s.peekCount("tenant-a", "shared-handle"), 0); assert.equal(await s.peekCount("tenant-b", "shared-handle"), 1, "跨 scope 的 ack 不得越界"); await s.drop("tenant-b", "shared-handle"); assert.equal(await s.peekCount("tenant-b", "shared-handle"), 0); }); await settle(); } export async function mailboxCrossProcessContract(hooks) { const { run: runRaw, settle } = beginContract(hooks.runAssertion); const run = (name, fn) => runRaw(name, async () => { const pair = await hooks.openPair(); try { await fn(pair.local, pair.peer); } finally { await pair.dispose(); } }); const S = MAILBOX_CONTRACT_SCOPE; const H = "session.shared"; const range = (n) => Array.from({ length: n }, (_, i) => i + 1); run("跨进程 seq 单铸:两个进程交错 append N+N ⇒ seq 恰为 1..2N(无重复无空洞),每条消息在任一方视角都可见", async (local, peer) => { const N = 40; const seqs = []; for (let i = 0; i < N; i++) { const [a, b] = await Promise.all([local.append(S, H, msg(`local-${i}`, 1_000 + i)), peer.append(S, H, msg(`peer-${i}`, 2_000 + i))]); seqs.push(a, b); } assert.deepEqual([...seqs].sort((x, y) => x - y), range(2 * N), "两方拿到的回执合起来必须恰是 1..2N"); assert.equal(await peer.peekCount(S, H), 2 * N, "对方进程的观察面必须看到本方的 append"); assert.equal(await local.peekCount(S, H), 2 * N); const lease = await local.claimLease(S, H, "cycle-1", 60_000, 10_000); assert.deepEqual(lease.messages.map((m) => m.seq), range(2 * N), "本方 claim 必须按 seq 序取到全部 2N 条"); assert.equal(lease.maxSeq, 2 * N); const contents = new Set(lease.messages.map((m) => m.content)); for (let i = 0; i < N; i++) { assert.ok(contents.has(`local-${i}`), `local-${i} 不得丢`); assert.ok(contents.has(`peer-${i}`), `peer-${i} 不得丢`); } }); run("lease/ack 不跨进程交叉:一方的活租约 fence 住另一方的 claim;非持有方的 ack 是 no-op;持有方的 ack 对另一方立即可见;高水位跨对方的 ack 存活", async (local, peer) => { await local.append(S, H, msg("m1", 1)); await peer.append(S, H, msg("m2", 2)); const held = await peer.claimLease(S, H, "cycle-peer", 60_000, 10_000); assert.deepEqual(held.messages.map((m) => m.seq), [1, 2]); assert.equal(await local.claimLease(S, H, "cycle-local", 60_000, 11_000), null, "对方进程的活租约必须 fence 住本方"); await local.ack(S, H, "cycle-local", held.maxSeq); assert.equal(await peer.peekCount(S, H), 2, "非持有方的 ack 不得动持有方手上的批"); await peer.ack(S, H, "cycle-peer", held.maxSeq); assert.equal(await local.peekCount(S, H), 0, "持有方的 ack 必须被本方看见"); assert.equal(await local.claimLease(S, H, "cycle-local", 60_000, 12_000), null); assert.equal(await local.append(S, H, msg("m3", 3)), 3, "seq 高水位必须跨对方进程的 ack 存活(永不复用)"); await peer.append(S, H, msg("m4", 4)); const held2 = await peer.claimLease(S, H, "cycle-peer-2", 1_000, 20_000); assert.deepEqual(held2.messages.map((m) => m.seq), [3, 4]); const takeover = await local.claimLease(S, H, "cycle-local-2", 60_000, 30_000); assert.deepEqual(takeover.messages.map((m) => m.seq), [3, 4], "过期租约的接管跨进程成立,seq 原样"); }); run("一方的 housekeeping 不丢另一方的 append:两进程各自反复压缩/重写期间交错写入 120 条,任一方视角都完整", async (local, peer) => { const N = 60; for (let i = 0; i < N; i++) { await Promise.all([local.append(S, H, msg(`L${i}`, 1_000 + i)), peer.append(S, H, msg(`P${i}`, 2_000 + i))]); } const fromPeer = await peer.claimLease(S, H, "cycle-peer", 60_000, 10_000); assert.deepEqual(fromPeer.messages.map((m) => m.seq), range(2 * N), "对方视角:seq 1..2N 全在"); await peer.releaseLease(S, H, "cycle-peer"); const fromLocal = await local.claimLease(S, H, "cycle-local", 60_000, 11_000); assert.deepEqual(fromLocal.messages.map((m) => m.seq), range(2 * N), "本方视角:seq 1..2N 全在"); const contents = fromLocal.messages.map((m) => m.content).sort(); assert.deepEqual(contents, [...range(N).map((i) => `L${i - 1}`), ...range(N).map((i) => `P${i - 1}`)].sort()); await local.ack(S, H, "cycle-local", fromLocal.maxSeq); assert.equal(await peer.peekCount(S, H), 0, "本方的 ack 对方可见"); }); run("reap 看得见对方进程的旧消息,哪怕本方缓存里这个箱是空的(已加载的空缓存不得替对方的旧消息说「没有」)", async (local, peer) => { await local.append(S, H, msg("mine", 1_000)); const held = await local.claimLease(S, H, "cycle-local", 60_000, 1_000); await local.ack(S, H, "cycle-local", held.maxSeq); await peer.append(S, H, msg("old-from-peer", 2_000)); assert.equal(await local.reap(S, 100_000, { maxAgeMs: 50_000 }), 1, "对方写的过期消息必须被本方 reap 看见并老化"); assert.equal(await peer.peekCount(S, H), 0); assert.equal(await peer.append(S, H, msg("after", 200_000)), 3, "高水位跨 reap 存活(对方视角)"); }); run("reap 与 drop 的 seq 语义跨进程:一方 reap 后另一方继续高水位;一方 drop 后另一方从 1 重铸", async (local, peer) => { await peer.append(S, H, msg("old", 1_000)); assert.equal(await local.reap(S, 100_000, { maxAgeMs: 50_000 }), 1, "本方 reap 必须看见对方写的旧消息"); assert.equal(await peer.peekCount(S, H), 0); assert.equal(await peer.append(S, H, msg("after-reap", 200_000)), 2, "reap 清箱但保高水位(RB-90 跨进程)"); await local.drop(S, H); assert.equal(await peer.peekCount(S, H), 0, "本方 drop 对方可见"); assert.equal(await peer.append(S, H, msg("after-drop", 300_000)), 1, "drop 结束箱的一生:对方从 1 重铸"); assert.equal(await local.peekCount(S, H), 1); }); await settle(); } export async function mailboxTombstonedRecipientContract(mk, hooks) { const { run: runRaw, settle } = beginContract(hooks.runAssertion); const run = (name, fn) => runRaw(name, () => withStores(mk, fn)); const S = MAILBOX_CONTRACT_SCOPE; const codeOf = (e) => e?.code; run("预删除态的收件人:append 响亮拒且带码(既不静默收下级联即将删掉的消息,也不裸抛)", async (make) => { const s = make(); await hooks.tombstone(s, S, "a1"); let thrown; try { await s.append(S, "a1", msg("m1")); } catch (e) { thrown = e; } assert.notEqual(thrown, undefined, "静默收下 = 给发件人一张级联马上撕掉的回执"); assert.equal(codeOf(thrown), MAILBOX_TOMBSTONED_RECIPIENT_CODE, "裸抛与拒同形:消费方要能按码分诊"); let again; try { await s.append(S, "a1", msg("m2")); } catch (e) { again = e; } assert.equal(codeOf(again), MAILBOX_TOMBSTONED_RECIPIENT_CODE); }); run("拒的粒度是收件人,不是开关:同 scope 下另一个活收件人照常收信", async (make) => { const s = make(); await hooks.tombstone(s, S, "a1"); assert.equal(await s.append(S, "a2", msg("still-live")), 1, "活收件人不受邻居的删除级联牵连"); assert.equal(await s.peekCount(S, "a2"), 1); }); run("收件人身份是 (scope, handle) 整体:A 租户的删除级联不得拒掉 B 租户的同名收件人", async (make) => { const s = make(); await hooks.tombstone(s, "tenant-a", "a1"); assert.equal(await s.append("tenant-b", "a1", msg("other-tenant")), 1, "同名 handle 在另一个租户下是另一个收件人"); assert.equal(await s.peekCount("tenant-b", "a1"), 1); }); run("两件套还得是单射的:把 (scope, handle) 拼成一个字符串记态,不得让两个不同收件人撞成一个", async (make) => { const s = make(); await hooks.tombstone(s, "tenant a", "b"); assert.equal(await s.append("tenant", "a b", msg("distinct-recipient")), 1, "拼键歧义不得把另一个收件人一起拒掉"); assert.equal(await s.peekCount("tenant", "a b"), 1); }); run("副作用轴 · 活租约:被拒的 append 不得动别人手上的租约(单消费者围栏不因删除窗口松开)", async (make) => { const s = make(); await s.append(S, "a1", msg("in-flight")); const held = await s.claimLease(S, "a1", "consumer-A", 60_000, 10_000); assert.equal(held?.messages.length, 1); await hooks.tombstone(s, S, "a1"); await assert.rejects(s.append(S, "a1", msg("after-tombstone", 2_000)), "预删除态下的 append 必须拒"); assert.equal(await s.claimLease(S, "a1", "rival", 60_000, 11_000), null, "A 的活租约必须仍然 fence 住别人"); await s.ack(S, "a1", "consumer-A", held.maxSeq); assert.equal(await s.peekCount(S, "a1"), 0); }); run("拒的是入口,不是清仓:被拒的 append 零副作用,已入箱的消息按原 seq/内容原封不动", async (make) => { const s = make(); const seq = await s.append(S, "a1", msg("parked-before")); await hooks.tombstone(s, S, "a1"); let thrown; let refused = false; try { await s.append(S, "a1", msg("after-tombstone", 2_000)); } catch (e) { refused = true; thrown = e; } assert.equal(refused, true, "预删除态下的 append 必须拒"); assert.equal(codeOf(thrown), MAILBOX_TOMBSTONED_RECIPIENT_CODE, "箱非空时的拒同样要带码"); assert.equal(await s.peekCount(S, "a1"), 1, "被拒的 append 不得入箱(幽灵投递),也不得清箱"); const lease = await s.claimLease(S, "a1", "w1", 60_000, 10_000); assert.deepEqual(lease?.messages.map((m) => m.seq), [seq]); assert.deepEqual(lease?.messages.map((m) => m.content), ["parked-before"], "取到的仍是拒之前那一条"); }); await settle(); }