NEO.K / MSSP FIELD LAB011-store-boundary
編號011-store-boundary
語言javascript
版本v1.0
日期2026-08-11
行數593
執行node src/main.mjs

011 — What you are holding after a read

candidate. The first example in this lab with state that outlives the process.

What this program does

It stores orders, refuses invalid ones, and then asks the question a store is usually silent about: what did the caller just get handed?

node src/main.mjs             # write, read back, mutate what came out
node src/main.mjs --strict    # exit 1 if the store hands out live references
node src/island_test.mjs      # 32 checks across 8 sections
$ node src/main.mjs

== writing
    ok  ord-1001     written
    ok  ord-1002     written
    !!  ord-1003     total 9 does not match the 4 item(s) listed

== what happens to a mutation made through what the store handed over
    a later read of the same key       before ["widget","gasket"]
                                       after  ["widget","gasket"]

    store.get(k) !== store.get(k):  true
    the contract says this store hands back: a fresh object on every read
    so the mutation went into a copy and the medium never saw it

The structural decision

Persistence is not one thing. Splitting it is the whole example:

the part which set why
the medium — files, memory, a database TMS a capability; swap it and the system is still itself
the handout strategy — copies or live references TMS a file that imports nothing and runs alone; the island test settles it
which strategy this deployment runs SCL where a deployment decision belongs
what counts as a valid record, and the read/write path SMS remove it and the store is a filesystem with extra steps
that the strategy is declared, and the declaration verified by running it FMS the contract term is not which one — it is whether anyone said, and whether saying it means anything

A store either copies or it does not, and the caller usually finds out by being wrong. This table changed on the day it shipped — see below.

Why now

Ten examples in, not one of them had state that outlived the process. The roadmap turns to real market applications at 20/20 — e-commerce, reporting — and every mechanism in this lab currently assumes a single program under src/ with no UI and no persistence. Metron and Pragma both published predictions on mssp-board about how that breaks. This is the first entry that goes and looks rather than predicting.

The island test

Section 3 is what the example exists for. Five value assertions — the ones an ordinary suite writes about a store — run under both handout strategies:

  PASS  all 5 value assertions pass under copies
  PASS  all 5 pass under live-references too - which is the finding: they cannot tell the two apart
  PASS  identity separates them - copies=true, live-references=false
  PASS  so does mutating what you were handed and reading again - 1 item(s) vs 2

Two observations separate the strategies and neither is about values. The mutation one only fires if the test knew to mutate. The identity one is a single line and fires whether anyone thought of it or not.

Section 4 is the one that caught me while writing it.

  PASS  in this process, both media read the record back - and one of them stores nothing at all
  PASS  a separate process finds the json-dir record - 1 record(s)
  PASS  and finds nothing the memory medium 'stored' - 0 record(s)
  PASS  the two media disagree only once a second process asks - the in-process check above passed for both

An in-process read cannot distinguish a store from a cache. The memory medium is in the example as the control that makes that check able to fail — without a medium whose persistence claim is false, "I wrote it and read it back" proves nothing at all.

Section 2 drills the same way: the two media agreeing is only evidence because a medium that drops writes makes the comparison fail.

live-references is not a straw man

shelve.Shelf(writeback=True) is exactly this strategy, and CPython ships it, documents it, and defaults away from it. Measured in archaeology 011 the same day:

writeback d[k].append(x) survives d[k] is d[k]
False (default) lost False
True kept True

Same API, same call, opposite semantics, and the observable that separates them is object identity — which no caller checks.

The correction, hours after publishing

The first version of this example put the handout strategies in SMS, and the 開發區 entry written the same morning said they belonged in FMS, and the archaeology filed the same day put them in TMS/handouts/. Three sets, three documents, one day, all mine, and I did not notice.

The AI Board host asked the question that exposed it: is this a fourth thing, or is your definition of SMS too narrow?

The method's own criteria answer it without an appeal to taste:

The strategies are TMS/handouts/ now, and section 5 is the obligation made runnable:

  PASS  copies: declared MUTATION_SURVIVES=false, measured false
  PASS  live-references: declared MUTATION_SURVIVES=true, measured true
  PASS  a handout declaring copy semantics while caching would be caught - declared false, measured true

The third line is the drill. Without it the first two are two declarations agreeing with each other, which is the whole subject of mssp-d-003.

The second correction, the next day, and it was in FMS

Metron and Pragma independently checked the first correction and found that it had not finished. The code moved to TMS/handouts/, the README was rewritten — and src/FMS/contract.json still carried the superseded ownership text: the handout as an FMS term, sets.FMS owning the strategies, sets.TMS listing only media. Commit 6cb30bf never touched that file.

All 27 checks stayed green, because every one of them verifies behaviour or TMS units and none of them reads FMS's own description of the sets. So the file whose entire job is to declare the structure carried a false declaration, in the example that argues FMS should carry the obligation to declare.

Their classification, which I have kept: a descriptive artifact contradiction, not a runtime failure.

The repair is not just the text. FMS now carries a machine-readable units map and section 1b compares it to the tree:

  PASS  TMS/media: declared 2, on disk 2 - json_dir.mjs, memory.mjs
  PASS  TMS/handouts: declared 2, on disk 2 - copies.mjs, live_references.mjs
  PASS  a declared unit that is not on disk would be caught - declared three, found two
  PASS  a file on disk that FMS does not declare would be caught - declared one, found two

Drilled by making FMS lie:

  FAIL  TMS/handouts: declared 1, on disk 2 - copies.mjs, live_references.mjs

Prose cannot be checked; a list can. That is the whole of the mechanism, and it is the reason the map exists next to the sentences rather than instead of them.

The mistake I made writing the test

The island test originally held one shared ORDER literal. Under live-references the store caches the object the caller passed in, so mutating what came back mutated the literal, and every section after it silently received a different record.

It is now a factory rather than a constant, with the reason in a comment. The hazard the example is about, met while writing the test for it.

What this example does not solve

Measurable, not measured. What copying costs on a record large enough to care, and how often callers really mutate what a store handed them.

Not measurable here. Whether copies are the right default. A store that hands out live references is a correct design when its callers know — the defect is being silent about which one you are, which is why FMS carries the obligation to declare rather than the choice itself.

And where the declaration lives is not settled by one example. The placement above was wrong for half a day and was corrected by a question from outside, not by anything in the artifact catching it.

And concurrency, at all. One process, one writer. Two writers would break this store and nothing here would notice. That is a limitation of the example, not a finding about stores — and it is the first thing that will have to change when this meets a real application.

Source

FMS

FMS/contract.json
{
  "name": "011-store-boundary",
  "what_it_is": "A record store with the boundary made explicit: which set owns the medium, which owns what a valid record is, and what the caller is holding after a read.",
  "the_structural_decision": "Persistence is not one thing. The medium is a capability (TMS). The handout strategy — what a read hands back — is ALSO a capability (TMS): a file that imports nothing and runs alone. Which of each this deployment runs is SCL. What counts as a valid record and the read/write path are SMS. What FMS keeps is not the choice but the OBLIGATION: that the strategy is named and that naming it is verified by running it.",
  "why_now": "Ten examples in, not one of them has state that outlives the process. Neo's roadmap turns to real market applications at 20/20 — e-commerce, reporting — and every mechanism in this lab currently assumes a single program under src/ with no UI and no persistence. Both Metron and Pragma published predictions on mssp-board about how that breaks. This is the first entry that goes and looks.",
  "status": "candidate",
  "media": {
    "memory": {
      "persists_across_processes": false,
      "note": "a control, so that section 4 has a case whose persistence claim is false"
    },
    "json-dir": {
      "persists_across_processes": true,
      "note": "one file per record"
    }
  },
  "handouts": {
    "copies": {
      "hands_back": "a fresh object on every read",
      "consequence": "a mutation through what you were handed is invisible to the store and to every later reader"
    },
    "live-references": {
      "hands_back": "the same object every read, cached in this process",
      "consequence": "a mutation through what you were handed is visible to later readers in this process and is never written to the medium",
      "not_a_straw_man": "This is shelve.Shelf(writeback=True), which CPython ships, documents and defaults away from. Measured in archaeology 011 the same day: under the default, d[k].append(x) is silently lost; under writeback it survives, and 200 pure reads leave 200 entries cached."
    }
  },
  "the_observation_that_separates_them": "store.get(k) !== store.get(k). Every assertion written in terms of VALUES passes under both strategies. Object identity is the only observable that differs, and no caller checks it.",
  "record": {
    "shape": {
      "id": "non-empty string",
      "items": "array of {sku: string, qty: positive integer}",
      "total": "must equal the sum of the quantities listed"
    },
    "who_owns_it": "SMS - a store that will accept anything is a filesystem with extra steps"
  },
  "sets": {
    "FMS": "this file: the guarantee that a strategy is declared and checked by execution, the record shape, the observation that separates the strategies, and the units map below",
    "SCL": "which medium and which handout this deployment uses, and whether a live reference is fatal",
    "SMS": "what a valid record is, the read/write path, and the identity check",
    "TMS": "one file per medium and one per handout strategy — each takes plain data, declares what it does, and reaches no sibling set",
    "DMS": "what was written, what was read back, and what nothing here is watching"
  },
  "non_goals": [
    "Being a database. Two media and a JSON round-trip.",
    "Concurrency. Nothing here is safe against two writers, and nothing here pretends to be - see what this example does not solve.",
    "Claiming copies are always right. A large record copied on every read is a real cost, and this example does not measure it."
  ],
  "units": {
    "TMS/media": [
      "json_dir.mjs",
      "memory.mjs"
    ],
    "TMS/handouts": [
      "copies.mjs",
      "live_references.mjs"
    ]
  },
  "_correction_2026_08_12": "Metron and Pragma independently found that this file still carried the ownership text superseded on 2026-08-11: the handout strategy as an FMS term, sets.FMS owning the strategies, and sets.TMS listing only media. Commit 6cb30bf moved the code and rewrote the README and did not touch this file, and all 27 island checks stayed green because they verify behaviour and TMS units rather than this ownership metadata. Classification theirs: a descriptive artifact contradiction, not a runtime failure. The `units` map above exists so that the next drift of this kind is a failing check rather than a reading."
}

SCL

SCL/policy.json
{
  "medium": "json-dir",
  "handout": "copies",
  "live_reference_is_fatal": true,
  "_note": "island_test.mjs runs both handouts and both media regardless of what this says. A policy able to silence the comparison would make the comparison worthless."
}
SCL/policy.mjs
// Which medium and handout this deployment uses, and what it refuses to ship.
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";

const here = path.dirname(fileURLToPath(import.meta.url));
const config = JSON.parse(fs.readFileSync(path.join(here, "policy.json"), "utf8"));

export const medium = () => config.medium;
export const handout = () => config.handout;
export const liveReferenceIsFatal = () => Boolean(config.live_reference_is_fatal);

SMS

SMS/store.mjs
// The store: what a valid record is, and the read/write path.
//
// What a read HANDS BACK is not decided here. The strategies are TMS units,
// resolved by id — 008 cost a day to the difference between an id that is
// looked up and an id that decides what runs, and 2026-08-11 cost an hour to
// the difference between a strategy that lives in SMS and one that does not.
import * as copies from "../TMS/handouts/copies.mjs";
import * as liveReferences from "../TMS/handouts/live_references.mjs";

const HANDOUTS = Object.fromEntries(
  [copies, liveReferences].map((module) => [module.NAME, module]));

export function validate(record) {
  const problems = [];
  if (typeof record?.id !== "string" || !record.id) problems.push("id must be a non-empty string");
  if (!Array.isArray(record?.items)) problems.push("items must be an array");
  else {
    for (const [index, item] of record.items.entries()) {
      if (typeof item?.sku !== "string") problems.push(`items[${index}].sku must be a string`);
      if (!Number.isInteger(item?.qty) || item.qty < 1) problems.push(`items[${index}].qty must be a positive integer`);
    }
    const counted = record.items.reduce((sum, item) => sum + (item?.qty ?? 0), 0);
    if (record.total !== counted) problems.push(`total ${record.total} does not match the ${counted} item(s) listed`);
  }
  return problems;
}

export function resolveHandout(name) {
  const module = HANDOUTS[name];
  if (!module) {
    return { problem: `handout "${name}" has no implementation - fail closed (known: ${Object.keys(HANDOUTS).sort().join(", ")})` };
  }
  return { module };
}

export const handoutNames = () => Object.keys(HANDOUTS).sort();

export function openStore({ medium, handout }) {
  const { module, problem } = resolveHandout(handout);
  if (problem) return { problem };

  const policy = module.make(JSON.parse);
  const store = {
    handout,
    handsBack: module.HANDS_BACK,
    put(record) {
      const problems = validate(record);
      if (problems.length) return { written: false, problems };
      medium.write(record.id, JSON.stringify(record));
      policy.remember(record.id, record);
      return { written: true, problems: [] };
    },
    get(key) {
      const serialised = medium.read(key);
      if (serialised === null) return null;
      return policy.answer(serialised, key);
    },
    keys: () => medium.keys(),
  };
  return { store };
}

// The observation that separates the strategies, and the only cheap one.
// Every check written in terms of values passes under both.
export function handsOutCopies(store, key) {
  return store.get(key) !== store.get(key);
}

// The declaration a handout makes about itself, checked by running it rather
// than by reading it. Two labels agreeing is the mssp-d-003 shape.
export function mutationSurvives(makeStore, key, mutate) {
  const store = makeStore();
  mutate(store.get(key));
  return JSON.stringify(store.get(key));
}

TMS

TMS/handouts/copies.mjs
// Deserialise on every read. What the caller gets is theirs.
//
// Moved here from SMS on 2026-08-11, the day it shipped, after the Board host
// asked whether this belonged in FMS at all. The island test answers: it is a
// file that imports nothing and can be run alone, which is what a TMS unit is.
// Leaving it in SMS would have meant a third strategy is an edit to SMS - the
// accretion 缺點 2 names as the method's most likely way to fail.
export const NAME = "copies";
export const HANDS_BACK = "a fresh object on every read";
export const MUTATION_SURVIVES = false;

export function make(deserialise) {
  return {
    remember() {},
    answer: (serialised) => deserialise(serialised),
  };
}
TMS/handouts/live_references.mjs
// Deserialise once and hand the same object back forever.
//
// Not a straw man: this is shelve.Shelf(writeback=True), which CPython ships
// and documents. What makes it legitimate there is that a caller who opened the
// file knows; what makes it a hazard is that whoever is handed the store does
// not - see archaeology 011.
export const NAME = "live-references";
export const HANDS_BACK = "the same object every read, retained in this process";
export const MUTATION_SURVIVES = true;

export function make(deserialise) {
  const cache = new Map();
  return {
    // shelve does exactly this on write when writeback is on: the object the
    // CALLER passed in becomes the cached one, so the store and the caller now
    // share it. That is what mutated a shared literal in this example's own test.
    remember(key, value) { cache.set(key, value); },
    answer(serialised, key) {
      if (!cache.has(key)) cache.set(key, deserialise(serialised));
      return cache.get(key);
    },
  };
}
TMS/media/json_dir.mjs
// A medium that is one file per record on disk.
//
// It imports node:fs, which is the whole point of it - the island rule this
// lab enforces is that a TMS unit must not reach a SIBLING TMS, not that it
// must be import-free. A medium with no way to touch its medium is not one.
import fs from "node:fs";
import path from "node:path";

export const MEDIUM = "json-dir";
export const PERSISTS_ACROSS_PROCESSES = true;

const fileFor = (dir, key) => path.join(dir, `${encodeURIComponent(key)}.json`);

export function make({ dir }) {
  fs.mkdirSync(dir, { recursive: true });
  return {
    read: (key) => {
      const file = fileFor(dir, key);
      return fs.existsSync(file) ? fs.readFileSync(file, "utf8") : null;
    },
    write: (key, serialised) => { fs.writeFileSync(fileFor(dir, key), serialised, "utf8"); },
    keys: () => fs.readdirSync(dir).filter((n) => n.endsWith(".json"))
      .map((n) => decodeURIComponent(n.slice(0, -5))).sort(),
  };
}
TMS/media/memory.mjs
// A medium that keeps records in this process and nowhere else.
//
// It is here so the store can be tested without a filesystem, and so that
// section 4 of the island test has something whose persistence claim is
// FALSE - a control. A test that only ever runs against a medium that really
// persists cannot tell "written" from "still in memory".
export const MEDIUM = "memory";
export const PERSISTS_ACROSS_PROCESSES = false;

export function make() {
  const cells = new Map();
  return {
    read: (key) => (cells.has(key) ? cells.get(key) : null),
    write: (key, serialised) => { cells.set(key, serialised); },
    keys: () => [...cells.keys()].sort(),
  };
}

DMS

DMS/report.mjs
// What was written, what came back, and what nothing here is watching.

export function written(results, out) {
  for (const { record, outcome } of results) {
    const mark = outcome.written ? "ok" : "!!";
    out(`    ${mark}  ${record.id.padEnd(12)} ${outcome.written ? "written" : outcome.problems.join("; ")}`);
  }
}

export function readBack(store, keys, out) {
  for (const key of keys) {
    const record = store.get(key);
    out(`    ${key.padEnd(12)} ${record ? `${record.items.length} item(s), total ${record.total}` : "not found"}`);
  }
}

export function boundary(label, before, after, out) {
  out(`    ${label.padEnd(34)} before ${JSON.stringify(before)}`);
  out(`    ${"".padEnd(34)} after  ${JSON.stringify(after)}`);
}

export function gaps(out) {
  out("\n  measurable, not measured here:");
  out("    - what copying costs on a record large enough to care");
  out("    - how often callers actually mutate what a store handed them");
  out("\n  not measurable by this program at all:");
  out("    - whether copies are the right default for a given system. A cache that");
  out("      hands out live references is a correct design when the callers know it;");
  out("      what makes it a defect is being silent about which one you are.");
  out("    - anything about concurrency. One process, one writer. Two writers would");
  out("      break this store and nothing here would notice, which is a limitation");
  out("      of the example rather than a finding about stores.");
}

root

island_test.mjs
// The island test.
//
//   node src/island_test.mjs
//
// Section 3 is the one this example exists for: the assertions an ordinary
// suite writes about a store pass under BOTH handout strategies. Section 4 is
// the one that caught me while writing it - an in-process read cannot tell a
// store from a cache, and the memory medium is here as the control that proves
// the check can come out false.
import { execFileSync } from "node:child_process";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { fileURLToPath } from "node:url";

import * as store from "./SMS/store.mjs";
import * as jsonDir from "./TMS/media/json_dir.mjs";
import * as memory from "./TMS/media/memory.mjs";
import * as liveRefs from "./TMS/handouts/live_references.mjs";

const here = path.dirname(fileURLToPath(import.meta.url));
const CONTRACT = JSON.parse(fs.readFileSync(path.join(here, "FMS", "contract.json"), "utf8"));
const MEDIA = { memory, "json-dir": jsonDir };
const failures = [];

const check = (label, ok, detail = "") => {
  process.stdout.write(`  ${ok ? "PASS" : "FAIL"}  ${label}${detail ? ` - ${detail}` : ""}\n`);
  if (!ok) failures.push(label);
};
const say = (line = "") => process.stdout.write(`${line}\n`);
const tempDir = () => fs.mkdtempSync(path.join(os.tmpdir(), "mssp-011-"));
// A factory, not a constant. A shared literal would be mutated by the
// live-references section and quietly break every section after it - which
// is the hazard this example is about, met while writing the test for it.
const order = () => ({ id: "ord-1", items: [{ sku: "widget", qty: 2 }], total: 2 });

function opened(mediumName, handout, dir) {
  const medium = MEDIA[mediumName].make({ dir });
  return store.openStore({ medium, handout }).store;
}

say("\n== 1. every TMS unit is an island and declares what it is");
const mediaDir = path.join(here, "TMS", "media");
const files = fs.readdirSync(mediaDir).filter((n) => n.endsWith(".mjs")).sort();
check("there are two medium files", files.length === 2, files.join(", "));
for (const file of files) {
  const source = fs.readFileSync(path.join(mediaDir, file), "utf8");
  const reaches = [...source.matchAll(/^\s*import[^"']*["']([^"']+)["']/gm)].map((m) => m[1]);
  const siblings = reaches.filter((spec) => /\.\.\/|FMS|SCL|SMS|DMS/.test(spec));
  check(`${file} reaches no sibling set`, siblings.length === 0,
    reaches.join(", ") || "no imports at all");
}
for (const [name, module] of Object.entries(MEDIA)) {
  check(`${name} declares MEDIUM and whether it survives the process`,
    module.MEDIUM === name && typeof module.PERSISTS_ACROSS_PROCESSES === "boolean",
    `persists=${module.PERSISTS_ACROSS_PROCESSES}`);
}
// The handout strategies became TMS units on the day this shipped, after the
// Board host asked whether the decision belonged in FMS at all. It had been in
// three sets in one day: FMS in 開發區, SMS here, TMS in archaeology 011.
const handoutDir = path.join(here, "TMS", "handouts");
const handoutFiles = fs.readdirSync(handoutDir).filter((n) => n.endsWith(".mjs")).sort();
check("there are two handout files, and they are TMS units", handoutFiles.length === 2,
  handoutFiles.join(", "));
for (const file of handoutFiles) {
  const source = fs.readFileSync(path.join(handoutDir, file), "utf8");
  const reaches = [...source.matchAll(/^\s*import[^"']*["']([^"']+)["']/gm)].map((m) => m[1]);
  check(`${file} reaches no sibling set`, reaches.length === 0,
    reaches.join(", ") || "no imports at all");
}

say("\n== 1b. what FMS says is where things are, checked against the tree");
// Added 2026-08-12, after Metron and Pragma found that this file still carried
// the ownership text superseded the day before. The code moved, the README was
// rewritten, and 27 checks stayed green because none of them read FMS's own
// description of the sets. Prose cannot be checked; a units map can.
const declaredUnits = CONTRACT.units ?? {};
check("FMS declares where its TMS units live", Object.keys(declaredUnits).length > 0,
  Object.keys(declaredUnits).join(", "));
for (const [where, expected] of Object.entries(declaredUnits)) {
  const dir = path.join(here, ...where.split("/"));
  const onDisk = fs.existsSync(dir)
    ? fs.readdirSync(dir).filter((n) => n.endsWith(".mjs")).sort()
    : null;
  check(`${where}: declared ${expected.length}, on disk ${onDisk ? onDisk.length : "no such directory"}`,
    onDisk !== null && JSON.stringify(onDisk) === JSON.stringify([...expected].sort()),
    onDisk ? onDisk.join(", ") : "missing");
}
// Two drills, one for each direction the map can be wrong.
const compare = (declared, actual) => JSON.stringify([...declared].sort()) === JSON.stringify([...actual].sort());
check("a declared unit that is not on disk would be caught",
  !compare(["copies.mjs", "live_references.mjs", "ghost.mjs"], ["copies.mjs", "live_references.mjs"]),
  "declared three, found two");
check("a file on disk that FMS does not declare would be caught",
  !compare(["copies.mjs"], ["copies.mjs", "live_references.mjs"]),
  "declared one, found two");

say("\n== 2. the medium is swappable, and an unknown one stops the run");
const results = {};
for (const name of Object.keys(MEDIA)) {
  const orders = opened(name, "copies", tempDir());
  orders.put(order());
  results[name] = JSON.stringify({ keys: orders.keys(), record: orders.get("ord-1") });
}
check("both media give the store identical observable results",
  new Set(Object.values(results)).size === 1, `${Object.keys(results).join(" vs ")}`);
// The drill: if that comparison cannot come out false, it proves nothing.
const brokenMedium = { read: () => null, write: () => {}, keys: () => [] };
const broken = store.openStore({ medium: brokenMedium, handout: "copies" }).store;
broken.put(order());
check("a medium that drops writes makes that comparison fail",
  JSON.stringify({ keys: broken.keys(), record: broken.get("ord-1") }) !== results.memory,
  "so section 2 is a measurement, not a formality");
check("an unknown handout id stops the run",
  Boolean(store.openStore({ medium: memory.make({}), handout: "live-refs" }).problem),
  store.openStore({ medium: memory.make({}), handout: "live-refs" }).problem);

say("\n== 3. the value assertions an ordinary suite writes pass under BOTH strategies");
const observed = {};
for (const handout of ["copies", "live-references"]) {
  const orders = opened("memory", handout, tempDir());
  orders.put(order());
  const record = orders.get("ord-1");
  observed[handout] = {
    values: [
      record.id === "ord-1",
      record.total === 2,
      record.items.length === 1,
      record.items[0].sku === "widget",
      JSON.stringify(orders.keys()) === '["ord-1"]',
    ],
    identity: store.handsOutCopies(orders, "ord-1"),
  };
  // the second observation: mutate what you were handed, then read again
  const handed = orders.get("ord-1");
  handed.items.push({ sku: "smuggled", qty: 99 });
  observed[handout].afterMutation = orders.get("ord-1").items.length;
}
const valueChecks = observed.copies.values.length;
check(`all ${valueChecks} value assertions pass under copies`,
  observed.copies.values.every(Boolean));
check(`all ${valueChecks} pass under live-references too`,
  observed["live-references"].values.every(Boolean),
  "which is the finding: they cannot tell the two apart");
check("identity separates them",
  observed.copies.identity !== observed["live-references"].identity,
  `copies=${observed.copies.identity}, live-references=${observed["live-references"].identity}`);
check("so does mutating what you were handed and reading again",
  observed.copies.afterMutation !== observed["live-references"].afterMutation,
  `${observed.copies.afterMutation} item(s) vs ${observed["live-references"].afterMutation}`);
say("        Two observations separate them and neither is about values. The");
say("        mutation one only fires if the test knew to mutate; the identity");
say("        one is one line and fires whether anyone thought of it or not.");

say("\n== 4. an in-process read cannot tell a store from a cache");
const diskDir = tempDir();
opened("json-dir", "copies", diskDir).put(order());
const memoryDir = tempDir();
const inMemory = opened("memory", "copies", memoryDir);
inMemory.put(order());
check("in this process, both media read the record back",
  Boolean(opened("json-dir", "copies", diskDir).get("ord-1")) && Boolean(inMemory.get("ord-1")),
  "and one of them stores nothing at all");
const dumpOf = (dir) => {
  try {
    return JSON.parse(execFileSync(process.execPath,
      [path.join(here, "main.mjs"), "--dump", dir], { encoding: "utf8" }));
  } catch { return {}; }
};
const fromDisk = dumpOf(diskDir);
const fromMemory = dumpOf(memoryDir);
check("a separate process finds the json-dir record", Boolean(fromDisk["ord-1"]),
  `${Object.keys(fromDisk).length} record(s)`);
check("and finds nothing the memory medium 'stored'", Object.keys(fromMemory).length === 0,
  `${Object.keys(fromMemory).length} record(s)`);
check("the two media disagree only once a second process asks",
  Boolean(fromDisk["ord-1"]) !== Boolean(fromMemory["ord-1"]),
  "the in-process check above passed for both");

say("\n== 5. each handout's declaration is checked by running it");
for (const handout of store.handoutNames()) {
  const { module } = store.resolveHandout(handout);
  const orders = opened("memory", handout, tempDir());
  orders.put(order());
  orders.get("ord-1").items.push({ sku: "smuggled", qty: 99 });
  const survived = orders.get("ord-1").items.length === 2;
  check(`${handout}: declared MUTATION_SURVIVES=${module.MUTATION_SURVIVES}, measured ${survived}`,
    survived === module.MUTATION_SURVIVES, module.HANDS_BACK);
}
// The drill: without it, the two lines above are two declarations agreeing
// with each other - the mssp-d-003 shape. A unit whose label says copies while
// its behaviour caches must come out as a disagreement.
const mislabelled = { MUTATION_SURVIVES: false, make: liveRefs.make };
const lying = opened("memory", "live-references", tempDir());
lying.put(order());
lying.get("ord-1").items.push({ sku: "smuggled", qty: 99 });
check("a handout declaring copy semantics while caching would be caught",
  (lying.get("ord-1").items.length === 2) !== mislabelled.MUTATION_SURVIVES,
  `declared ${mislabelled.MUTATION_SURVIVES}, measured true`);

say("\n== 6. fail closed");
const unknown = store.openStore({ medium: memory.make({}), handout: "whatever" });
check("an unresolvable handout returns a problem and no store",
  Boolean(unknown.problem) && unknown.store === undefined);
const strict = opened("memory", "copies", tempDir());
for (const [label, record] of [
  ["a record with no id", { items: [], total: 0 }],
  ["a total that disagrees with the items", { id: "x", items: [{ sku: "a", qty: 2 }], total: 5 }],
  ["a fractional quantity", { id: "x", items: [{ sku: "a", qty: 1.5 }], total: 1.5 }],
]) {
  const outcome = strict.put(record);
  check(`${label} is refused`, !outcome.written, outcome.problems[0]);
}
check("and nothing was written by any of them", strict.keys().length === 0,
  `${strict.keys().length} key(s)`);

say("\n== 7. what this example does not solve");
say("        MEASURABLE, NOT MEASURED");
say("          - what copying costs on a record large enough to care");
say("          - how often callers really mutate what a store handed them");
say("        NOT MEASURABLE HERE");
say("          - whether copies are the right default. A store handing out live");
say("            references is a correct design when its callers know; the defect");
say("            is being silent about which one you are. FMS is where that goes.");
say("          - concurrency. One process, one writer. Two writers would break");
say("            this store and nothing here would notice.");

say(failures.length ? `\n${failures.length} failure(s)` : "\nall checks passed");
for (const f of failures) say(`  - ${f}`);
process.exit(failures.length ? 1 : 0);
main.mjs
// A store whose boundary is a term of the contract rather than a surprise.
//
//   node src/main.mjs              write, read back, and mutate what was handed over
//   node src/main.mjs --strict     exit 1 if the store hands out live references
//   node src/main.mjs --dump DIR   reopen a json-dir store and print it (used by the island test)
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { fileURLToPath } from "node:url";

import * as report from "./DMS/report.mjs";
import * as policy from "./SCL/policy.mjs";
import * as store from "./SMS/store.mjs";
import * as jsonDir from "./TMS/media/json_dir.mjs";
import * as memory from "./TMS/media/memory.mjs";

const here = path.dirname(fileURLToPath(import.meta.url));
const CONTRACT = JSON.parse(fs.readFileSync(path.join(here, "FMS", "contract.json"), "utf8"));
const MEDIA = { memory, "json-dir": jsonDir };

export function resolveMedium(name, config) {
  const module = MEDIA[name];
  if (!module) {
    return { problem: `medium "${name}" has no implementation - fail closed (known: ${Object.keys(MEDIA).sort().join(", ")})` };
  }
  return { module, medium: module.make(config) };
}

const ORDERS = [
  { id: "ord-1001", items: [{ sku: "widget", qty: 2 }, { sku: "gasket", qty: 1 }], total: 3 },
  { id: "ord-1002", items: [{ sku: "widget", qty: 1 }], total: 1 },
  { id: "ord-1003", items: [{ sku: "widget", qty: 4 }], total: 9 },
];

function dump(dir) {
  const { medium } = resolveMedium("json-dir", { dir });
  const opened = store.openStore({ medium, handout: "copies" });
  const out = {};
  for (const key of opened.store.keys()) out[key] = opened.store.get(key);
  process.stdout.write(JSON.stringify(out));
  return 0;
}

function main(argv) {
  const out = (line = "") => process.stdout.write(`${line}\n`);
  const dumpAt = argv.indexOf("--dump");
  if (dumpAt !== -1) return dump(argv[dumpAt + 1]);

  const dir = fs.mkdtempSync(path.join(os.tmpdir(), "mssp-011-"));
  const { module, medium, problem } = resolveMedium(policy.medium(), { dir });
  if (problem) { out(`  !! ${problem}`); return 1; }

  const opened = store.openStore({ medium, handout: policy.handout() });
  if (opened.problem) { out(`  !! ${opened.problem}`); return 1; }
  const { store: orders } = opened;

  out(`\n== medium ${module.MEDIUM}, handout ${policy.handout()}`);
  out(`   persists across processes: ${module.PERSISTS_ACROSS_PROCESSES}`);

  out("\n== writing");
  report.written(ORDERS.map((record) => ({ record, outcome: orders.put(record) })), out);

  out("\n== reading back");
  report.readBack(orders, orders.keys(), out);

  out("\n== what happens to a mutation made through what the store handed over");
  const handed = orders.get("ord-1001");
  const before = handed.items.map((item) => item.sku);
  handed.items.push({ sku: "smuggled", qty: 99 });
  const after = orders.get("ord-1001").items.map((item) => item.sku);
  report.boundary("a later read of the same key", before, after, out);
  const separate = store.handsOutCopies(orders, "ord-1001");
  out(`\n    store.get(k) !== store.get(k):  ${separate}`);
  out(`    the contract says this store hands back: ${CONTRACT.handouts[policy.handout()].hands_back}`);
  out(`    ${separate
    ? "so the mutation went into a copy and the medium never saw it"
    : "so the mutation is visible to later readers here and was never written"}`);

  report.gaps(out);

  if (argv.includes("--strict") && !separate && policy.liveReferenceIsFatal()) return 1;
  return 0;
}

process.exitCode = main(process.argv.slice(2));