test: cover runtime regression scenarios
This commit is contained in:
@@ -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");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user