test: cover runtime regression scenarios

This commit is contained in:
2026-08-03 15:08:01 +08:00
parent 7082881624
commit 776d56320a
4 changed files with 633 additions and 2 deletions
@@ -0,0 +1,73 @@
import { describe, expect, it } from "vitest";
import { ConversationStore } from "./conversation-store";
class MemoryStorage implements Storage {
private readonly values = new Map<string, string>();
public get length(): number { return this.values.size; }
public clear(): void { this.values.clear(); }
public getItem(key: string): string | null { return this.values.get(key) ?? null; }
public key(index: number): string | null { return [...this.values.keys()][index] ?? null; }
public removeItem(key: string): void { this.values.delete(key); }
public setItem(key: string, value: string): void { this.values.set(key, value); }
}
const conversationID = "user_test:2:agent_channel";
const createdAt = "2026-08-03T00:00:00.000Z";
describe("ConversationStore", () => {
it("keeps the inclusive sync cursor at zero after a send acknowledgement", () => {
const store = new ConversationStore(new MemoryStorage());
store.open(conversationID);
store.appendLocalText("local_001", "hello", createdAt);
store.markSubmitted("local_001", 41, createdAt);
expect(store.snapshot()).toMatchObject({ cursor: 0, outbox: [] });
expect(store.snapshot().items).toEqual([expect.objectContaining({
local_id: "local_001",
message_seq: 41,
item: expect.objectContaining({ kind: "user-message", delivery: expect.objectContaining({ status: "submitted" }) }),
})]);
});
it("deduplicates the inclusive sync echo of a locally submitted user message", () => {
const store = new ConversationStore(new MemoryStorage());
store.open(conversationID);
store.appendLocalText("local_001", "hello", createdAt);
store.markSubmitted("local_001", 41, createdAt);
const restored = store.recordSyncedUserText(41, "hello", createdAt);
expect(restored).toBeUndefined();
expect(store.snapshot()).toMatchObject({ cursor: 41 });
expect(store.snapshot().items).toHaveLength(1);
});
it("persists a local echo and restores it for the same conversation", () => {
const storage = new MemoryStorage();
const first = new ConversationStore(storage);
first.open(conversationID);
first.appendLocalText("local_002", "persist me", createdAt);
const reopened = new ConversationStore(storage);
const snapshot = reopened.open(conversationID);
expect(snapshot.cursor).toBe(0);
expect(snapshot.outbox).toEqual([expect.objectContaining({ local_id: "local_002", payload: "persist me" })]);
expect(snapshot.items).toEqual([expect.objectContaining({
local_id: "local_002",
item: expect.objectContaining({ kind: "user-message", text: "persist me" }),
})]);
});
it("accepts one remote message per IM sequence and advances the cursor only from sync data", () => {
const store = new ConversationStore(new MemoryStorage());
store.open(conversationID);
const item = { kind: "markdown" as const, id: "evt_remote_001", markdown: "remote" };
expect(store.recordIncoming(item, 42, createdAt)).toBe(true);
expect(store.recordIncoming(item, 42, createdAt)).toBe(false);
expect(store.snapshot()).toMatchObject({ cursor: 42 });
expect(store.snapshot().items).toHaveLength(1);
});
});
@@ -0,0 +1,74 @@
import { describe, expect, it } from "vitest";
import { parseEnvelopeJSON } from "../protocol";
import { InteractionKernel } from "./interaction-kernel";
function envelope(overrides: Record<string, unknown> = {}): string {
return JSON.stringify({
v: 1,
id: "evt_kernel_001",
type: "lineup.v1.text",
conversation_id: "conversation_kernel_test",
sender: { kind: "agent", id: "agent_test" },
payload: { markdown: "# Hello\n\n**trusted**" },
...overrides,
});
}
describe("InteractionKernel", () => {
it("accepts a valid typed envelope and projects its trusted markdown item", () => {
const kernel = new InteractionKernel();
const result = kernel.ingest({ raw: envelope(), source: "sync", transport_id: "41" });
expect(result.disposition).toBe("accepted");
expect(result.items).toEqual([expect.objectContaining({
kind: "markdown",
id: "evt_kernel_001",
markdown: "# Hello\n\n**trusted**",
})]);
expect(result.snapshot.seen_envelope_ids).toBe(1);
});
it("rejects invalid protocol JSON while preserving legacy plain text as safe markdown", () => {
const kernel = new InteractionKernel();
const invalidProtocol = parseEnvelopeJSON("{");
const legacyText = kernel.ingest({ raw: "{", source: "sync" });
const unknown = kernel.ingest({
raw: envelope({ id: "evt_kernel_unknown", type: "lineup.v1.unknown" }),
source: "live",
});
expect(invalidProtocol).toMatchObject({ ok: false, fallback: { code: "invalid_json" } });
expect(legacyText.items).toEqual([expect.objectContaining({ kind: "markdown", markdown: "{" })]);
expect(unknown.items).toEqual([expect.objectContaining({ kind: "fallback", reason: "unsupported_type", id: "evt_kernel_unknown" })]);
});
it("deduplicates one envelope id across sync and live transport sources", () => {
const kernel = new InteractionKernel();
const first = kernel.ingest({ raw: envelope(), source: "sync" });
const duplicate = kernel.ingest({ raw: envelope(), source: "live" });
expect(first.disposition).toBe("accepted");
expect(duplicate).toMatchObject({ disposition: "duplicate", items: [] });
expect(duplicate.snapshot.seen_envelope_ids).toBe(1);
});
it("projects the latest agent status by actor and retains a bounded dedupe set", () => {
const kernel = new InteractionKernel(2);
const thinking = kernel.ingest({
raw: envelope({ id: "evt_status_thinking", type: "lineup.v1.agent.status", payload: { status: "thinking", detail: "planning" } }),
source: "sync",
received_at: "2026-08-03T00:00:00.000Z",
});
kernel.ingest({ raw: envelope({ id: "evt_other", payload: { markdown: "one" } }), source: "sync" });
kernel.ingest({ raw: envelope({ id: "evt_newer", payload: { markdown: "two" } }), source: "sync" });
expect(thinking.snapshot.agent_presence).toEqual([expect.objectContaining({
status: "thinking",
detail: "planning",
envelope_id: "evt_status_thinking",
updated_at: "2026-08-03T00:00:00.000Z",
})]);
// The first id has expired from the bounded set and is accepted again.
expect(kernel.ingest({ raw: envelope({ id: "evt_status_thinking" }), source: "live" }).disposition).toBe("accepted");
});
});