import { afterEach, describe, it } from "@std/testing/bdd"; import { expect } from "@std/expect"; import { Identity } from "@commonfabric/identity"; import { StorageManager } from "@commonfabric/runner/storage/cache.deno"; import { Runtime } from "../src/runtime.ts"; /** * PR D regression guard (docs/specs/content-addressed-action-identity- * implementation-plan.md): the pattern-scoped function registries * (`verifiedPatternFunctions` / `verifiedPatternLoadIds` / `associatePattern`) * were deleted. They existed to disambiguate equal `implementationRef`s across * separate loads of the same module; under content addressing that * disambiguation is unnecessary because the SES verifier forbids module-scope * mutable state, so any live instance of one module identity is interchangeable * (instance state flows through inputs, never closures). * * This pins that property end-to-end: two pieces compiled from BYTE-IDENTICAL * programs (two distinct loads) each run their handler correctly and keep their * own instance state isolated. */ const signer = await Identity.fromPassphrase("multi-instance-resolution"); const space = signer.did(); const PROGRAM = { main: "/main.tsx", files: [{ name: "/main.tsx", contents: `/// import { handler, pattern, Default, Writable } from "commonfabric"; const bump = handler<{ by?: number }, { count: Writable }>( (event, state) => { state.count.set(state.count.get() + (event.by ?? 1)); }, ); export default pattern<{ count: Default }>(() => { const count = new Writable(0).for("count"); return { count, bump: bump({ count }) }; }); `, }], }; describe("multi-instance verified-function resolution", () => { let storageManager: ReturnType | undefined; let runtime: Runtime | undefined; afterEach(async () => { await runtime?.dispose(); await storageManager?.close(); runtime = undefined; storageManager = undefined; }); it("two loads of an identical program run and isolate per-instance state", async () => { storageManager = StorageManager.emulate({ as: signer }); runtime = new Runtime({ apiUrl: new URL(import.meta.url), storageManager, cfcEnforcementMode: "observe", }); const runOne = async (cause: string) => { // A SEPARATE compile → distinct module-function instances sharing the // same content identity / implementationRef. const tx0 = runtime!.edit(); const pattern = await runtime!.patternManager.compilePattern(PROGRAM, { space, tx: tx0, }); const resultCell = runtime!.getCell<{ count: number }>( space, cause, undefined, tx0, ); // deno-lint-ignore no-explicit-any const r = runtime!.run(tx0, pattern, {}, resultCell) as any; await tx0.commit(); await r.pull(); return r; }; const a = await runOne("instance-a"); const b = await runOne("instance-b"); // Drive each instance's handler a different number of times. a.key("bump").send({ by: 1 }); a.key("bump").send({ by: 1 }); a.key("bump").send({ by: 1 }); b.key("bump").send({ by: 1 }); await runtime.idle(); // Each instance ran its handler (resolution succeeded across both loads) // and kept ISOLATED state — no cross-talk despite the shared // implementationRef / content identity. expect(a.key("count").get()).toBe(3); expect(b.key("count").get()).toBe(1); }); });