[
  {
    "id": "1",
    "title": "1. Overview and Thesis",
    "clauses": [
      {
        "id": "1.1",
        "title": "A memory SDK and MCP server that merges subagents' memory into one project memory",
        "summary": "A lead agent that never attended the earlier sessions receives the shared context of the agents that did.",
        "tests": [
          {
            "package": "@offcut/acceptance",
            "file": "packages/acceptance/src/acceptance.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "1.2",
        "title": "The core is merging: sources preserved, duplicates consolidated in retrieval, related records grouped, contradictions kept visible",
        "summary": "Merging returns one item for an exact duplicate and groups related records, without destroying any source record or hiding a conflict.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/acceptance",
            "file": "packages/acceptance/src/acceptance.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "1.3",
        "title": "OFFCUT is not a relayer: it stores, merges and retrieves memory itself",
        "summary": "The memory path stores, merges and retrieves here: the whole cycle completes with every outbound call trapped, and the path carries no HTTP client at all.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/spec-1-3-not-a-relayer.test.ts"
          }
        ],
        "status": "pinned",
        "note": "Pinned as the negative it is. Forwarding is the thing that must not happen, so the whole cycle — add, import, merge, recall, inspect, export, forget — is run with fetch throwing, the record is read straight out of the store tables, the duplicate collapse is recomputed after the client is thrown away, and the memory path is swept for any HTTP client. It does not prove that nothing is reached by some means other than fetch; the sweep of the files themselves is what stands in for that."
      },
      {
        "id": "1.4",
        "title": "Product boundary: no watermelon trading",
        "summary": "No trades, swaps, arbitrage, market monitoring, portfolios or transaction signing anywhere in the product.",
        "tests": [
          {
            "package": "@offcut/web",
            "file": "apps/web/src/__tests__/token-section.test.tsx"
          },
          {
            "package": "@offcut/web",
            "file": "apps/web/src/__tests__/rewards-page.test.tsx"
          },
          {
            "package": "@offcut/web",
            "file": "apps/web/src/__tests__/wallet-modal.test.ts"
          },
          {
            "package": "@offcut/acceptance",
            "file": "packages/acceptance/src/spec-surface-inventory.test.ts"
          }
        ],
        "status": "partly",
        "note": "Two of the three places this could go wrong are asserted now: the site’s language, and the product’s own API, whose complete tool list is pinned exactly and swept for trading vocabulary, for wallet and chain parameters, and for anything a market would need. What no test does is sweep every file in the workspace for a trading surface somebody could add without adding a tool."
      }
    ]
  },
  {
    "id": "2",
    "title": "2. Entities and Roles",
    "clauses": [
      {
        "id": "2.1",
        "title": "A workspace is one project's memory, scoped to selected agents",
        "summary": "A workspace is not a common database: records never cross from one workspace to another.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/api",
            "file": "apps/api/src/__tests__/api.e2e.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "2.2",
        "title": "A source record carries an author and a source, kept separate from its evidence",
        "summary": "Authorship and supporting evidence are separate fields on every record, and an unknown record type is refused rather than stored.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/validation-errors.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "2.3",
        "title": "Merged memory references the source records and versions it was built from",
        "summary": "A derived block pins the exact versions it used and goes stale when one of them changes.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "2.4",
        "title": "Context is the relevant portion of merged memory within permissions and a size limit",
        "summary": "A recall answers within the caller’s permissions and the size limit it was given, says when it had to stop, and takes nothing out of the store.",
        "tests": [
          {
            "package": "@offcut/acceptance",
            "file": "packages/acceptance/src/acceptance.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/spec-2-4-context-within-the-limit.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/agent-limit.test.ts"
          }
        ],
        "status": "pinned",
        "note": "Both halves are pinned now: an answer spends no more than the budget it was handed and marks itself incomplete, it never spends that budget on records the caller may not see, and shortening removes nothing from the store. What the numbers should be was OPEN-3; they exist in LIMITS today and the refusal past the maximum is pinned too, but no test claims those values are the right ones."
      },
      {
        "id": "2.5",
        "title": "$OFFCUT is an asset separate from memory",
        "summary": "The token is not a memory mechanism; the memory core runs with no wallet, chain or token configured.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/web",
            "file": "apps/web/src/__tests__/token-section.test.tsx"
          }
        ],
        "status": "pinned",
        "note": "The spec's \"product utility is [OPEN]\" was answered by the owner on 2026-09-15; see the owner-decisions section."
      },
      {
        "id": "2.6",
        "title": "No participant acquires powers it was not granted",
        "summary": "An agent cannot grant itself permissions, create another agent, or act as the owner; identity comes from the connection.",
        "tests": [
          {
            "package": "@offcut/api",
            "file": "apps/api/src/__tests__/api.e2e.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          }
        ],
        "status": "pinned"
      }
    ]
  },
  {
    "id": "3",
    "title": "3. Mechanics",
    "clauses": [
      {
        "id": "3.1a",
        "title": "Connection: MCP server or SDK, a workspace, granted access, results written through memory tools",
        "summary": "An agent authenticates, writes through the memory tools, and the next session reads the same workspace back.",
        "tests": [
          {
            "package": "@offcut/acceptance",
            "file": "packages/acceptance/src/acceptance.test.ts"
          },
          {
            "package": "@offcut/api",
            "file": "apps/api/src/__tests__/api.e2e.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "3.1b",
        "title": "Existing notes enter only through an explicit JSON import; connection is not automatic access to every chat",
        "summary": "Nothing enters memory that was not written or imported on purpose, and no tool offers a way to ingest anything by itself.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/spec-3-1b-nothing-enters-by-itself.test.ts"
          },
          {
            "package": "@offcut/acceptance",
            "file": "packages/acceptance/src/spec-surface-inventory.test.ts"
          }
        ],
        "status": "pinned",
        "note": "Pinned from both ends. In the core, a workspace whose agents have all connected and authenticated is still empty until a record is handed over deliberately, and an agent that was not granted import is refused. On the MCP surface, no tool takes a path, a folder, a url or a chat export, so the material an import loads has to be carried in the call itself."
      },
      {
        "id": "3.2a",
        "title": "A record's fields, and agentId taken from the verified connection",
        "summary": "An agentId supplied in a request body is ignored; the writer is the connection that carried the write.",
        "tests": [
          {
            "package": "@offcut/api",
            "file": "apps/api/src/__tests__/api.e2e.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "3.2b",
        "title": "Every write carries an idempotency key; a replay returns the previous result and a reused key with new content is rejected",
        "summary": "Retrying a write creates no second record, and the same key carrying different content is refused.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/api",
            "file": "apps/api/src/__tests__/api.e2e.test.ts"
          },
          {
            "package": "@offcut/web",
            "file": "apps/web/src/__tests__/api.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "3.2c",
        "title": "A write is acknowledged after it is persisted; a correction is a new version and a stale version cannot overwrite",
        "summary": "Acknowledged records survive a restart, and a correction built on a stale version is refused on both surfaces.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/api",
            "file": "apps/api/src/__tests__/api.e2e.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "3.3a",
        "title": "Merging happens inside one workspace and one authorized audience",
        "summary": "A private record does not become shared because its topic matches, and records never merge across workspaces.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "3.3b",
        "title": "The merge table: a duplicate returns one item, related items group, a conflict is flagged, an authorized correction updates the current version",
        "summary": "Each row of the merge behaviour table, with every source record left intact.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/acceptance",
            "file": "packages/acceptance/src/acceptance.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "3.3c",
        "title": "An uncertain semantic relationship leaves the records separate",
        "summary": "An ambiguous pair stays two items: nothing is discarded, and nothing is joined, for a cleaner summary.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/spec-3-3c-uncertain-relationships.test.ts"
          }
        ],
        "status": "pinned",
        "note": "Pairs a similarity model would happily fold together are fed to the engine and stay separate — two items, no collapse, and no conflict invented out of free text — with a control proving the engine does act once the relationship is stated as an explicit signal. Without that control the other assertions could be satisfied by an engine that merges nothing at all."
      },
      {
        "id": "3.3d",
        "title": "A derived block cites source IDs and versions; a stale block is rebuilt before it is served as current",
        "summary": "Shared memory is records and relationships, not one enormous prompt, and staleness clears only by rebuilding.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/summaries.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "3.4a",
        "title": "Retrieval checks access first; inaccessible and deleted records contribute to nothing",
        "summary": "A foreign or revoked caller gets no content, no summary and no metadata, and a deleted record leaves no trace in a count.",
        "tests": [
          {
            "package": "@offcut/acceptance",
            "file": "packages/acceptance/src/acceptance.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/api",
            "file": "apps/api/src/__tests__/api.e2e.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "3.4b",
        "title": "A recall returns text, sources, versions and unresolved conflicts; a budget too small returns a flag and references, never one side",
        "summary": "Both sides of a conflict stay visible however small the budget, and two equally-permissioned callers get identical context.",
        "tests": [
          {
            "package": "@offcut/acceptance",
            "file": "packages/acceptance/src/acceptance.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "3.4c",
        "title": "No data means an empty result, never an invented answer",
        "summary": "Memory is not replaced with a guess: no data means an empty result, and a question that matches nothing returns stored text and says so.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/credits.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/spec-3-4c-empty-not-invented.test.ts"
          }
        ],
        "status": "pinned",
        "note": "Three shapes of “no data” are pinned directly — an empty workspace, a workspace where every record is another agent’s private one, and a workspace whose only record has been deleted — plus the line the builder does not cross when records exist but the words miss: it says so in a note and returns stored text rather than writing an answer of its own."
      },
      {
        "id": "3.4d",
        "title": "Access checks apply to cached results; revocation blocks what follows",
        "summary": "A revoked key is refused on the very next request, and every later operation by that principal fails.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/api",
            "file": "apps/api/src/__tests__/api.e2e.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "3.5a",
        "title": "A conflict resolution records the chosen version, the rationale and the decision author",
        "summary": "A conflict reappears on every recall until an authorized resolution names who decided, and reopens when a third value arrives.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "3.5b",
        "title": "Deletion removes the record and its dependent blocks from every subsequent response; indexes and managed copies are cleaned",
        "summary": "A deleted record returns through no path, and restoring a snapshot does not resurrect one.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/backup.test.ts"
          },
          {
            "package": "@offcut/acceptance",
            "file": "packages/acceptance/src/acceptance.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "3.6",
        "title": "The end-to-end example: three agents, one question, one merged context",
        "summary": "A new lead agent answers \"what remains before release?\" from three sessions it never attended, and a later fix does not erase the bug report.",
        "tests": [
          {
            "package": "@offcut/acceptance",
            "file": "packages/acceptance/src/acceptance.test.ts"
          }
        ],
        "status": "pinned",
        "note": "The specification's own example is the suite's PRIMARY acceptance check, which replays it: the same question, the same three sessions."
      }
    ]
  },
  {
    "id": "4",
    "title": "4. Components and Roles",
    "clauses": [
      {
        "id": "4.0a",
        "title": "SDK and MCP server run on one core, with one access layer, store, merge engine and context builder",
        "summary": "The same query through the SDK and through MCP returns the same context, and a write through one is readable through the other.",
        "tests": [
          {
            "package": "@offcut/acceptance",
            "file": "packages/acceptance/src/acceptance.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "4.0b",
        "title": "The first release is local; every connection to a workspace uses the same store",
        "summary": "One store per installation, created and migrated on first use, with its location decided by one documented variable.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/bootstrap.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/db.test.ts"
          }
        ],
        "status": "pinned",
        "note": "The store is Prisma over SQLite or PostgreSQL. The spec's final choice is OPEN-2 and is still the owner's to ratify."
      },
      {
        "id": "4.1",
        "title": "The eight operations — add, import, merge, recall, inspect, resolve, forget, export — on both surfaces",
        "summary": "Every operation exists under the name the spec gives it, on the SDK, over MCP and over HTTP.",
        "tests": [
          {
            "package": "@offcut/web",
            "file": "apps/web/src/__tests__/operations.test.tsx"
          },
          {
            "package": "@offcut/api",
            "file": "apps/api/src/__tests__/api.e2e.test.ts"
          },
          {
            "package": "@offcut/acceptance",
            "file": "packages/acceptance/src/acceptance.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "4.2a",
        "title": "Trust boundary: permissions belong to a verified connection",
        "summary": "A client that cannot distinguish subagents is treated as one principal, and the key is the identity.",
        "tests": [
          {
            "package": "@offcut/api",
            "file": "apps/api/src/__tests__/api.e2e.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "4.2b",
        "title": "Trust boundary: memory text is data, never instructions",
        "summary": "A record saying \"ignore the rules\" is stored verbatim and buys nothing, and the model is told the same about record text.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/summaries.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "4.2c",
        "title": "Trust boundary: local storage is protected by the operating system, not by SDK checks",
        "summary": "A process with direct access to the database file is outside what OFFCUT can defend, and the code does not pretend otherwise.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/spec-4-2c-local-store-trust-boundary.test.ts"
          }
        ],
        "status": "partly",
        "note": "What a test can pin is the shape of the boundary, and it does: the permission check holds on the path the SDK owns, and raw SQL against the same file walks straight past it and leaves no audit trail — openly, by design, so a quietly added tamper seal would turn this red. The other half of the clause, that operating-system permissions are what protect the file, is about the operating system and stays outside the suite."
      },
      {
        "id": "4.2d",
        "title": "Trust boundary: text leaves the system only with explicit owner permission, disabled by default",
        "summary": "Nothing is sent to an external model until an owner turns it on, and only an owner can turn it on.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/summaries.test.ts"
          }
        ],
        "status": "pinned"
      }
    ]
  },
  {
    "id": "5",
    "title": "5. Economics",
    "clauses": [
      {
        "id": "5.1",
        "title": "Local SDK and MCP need no wallet, gas or token purchase",
        "summary": "The full write, merge, recall, delete and export cycle runs with no wallet, chain or model configured.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/acceptance",
            "file": "packages/acceptance/src/acceptance.test.ts"
          },
          {
            "package": "@offcut/api",
            "file": "apps/api/src/__tests__/api.e2e.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "5.2",
        "title": "Storage and compute come from the user's infrastructure; pricing and licensing are undecided (OPEN-7)",
        "summary": "No paid tier exists, and none is described anywhere.",
        "tests": [],
        "status": "unpinned",
        "note": "Unpinned because it is undecided, not because it is unfinished work: pricing and licensing are a commercial decision (OPEN-7), and nothing in the product claims a price, so there is nothing for a test to hold to."
      },
      {
        "id": "5.3",
        "title": "The token is named OFFCUT AGENT with the symbol OFFCUT",
        "summary": "The name, the symbol and the ticker stay in step wherever they are printed.",
        "tests": [
          {
            "package": "@offcut/web",
            "file": "apps/web/src/__tests__/token.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "5.4",
        "title": "Token launch: Robinhood Chain 4663, pons v2; launch parameters are OPEN-7",
        "summary": "Until an address is supplied the site says there is none; once one is, it is validated, shown in full, copied in full and linked.",
        "tests": [
          {
            "package": "@offcut/web",
            "file": "apps/web/src/__tests__/token.test.ts"
          },
          {
            "package": "@offcut/web",
            "file": "apps/web/src/__tests__/contract-address.test.tsx"
          }
        ],
        "status": "pinned",
        "note": "No contract address has been supplied, so the launched state is pinned by tests rather than demonstrated by a deployment."
      },
      {
        "id": "5.5",
        "title": "Token utility is undecided; no invented staking, tax, buyback or payouts",
        "summary": "The section says the role is open rather than filling itself with a mechanic nobody agreed to.",
        "tests": [
          {
            "package": "@offcut/web",
            "file": "apps/web/src/__tests__/token-section.test.tsx"
          }
        ],
        "status": "partly",
        "note": "Superseded in part on 2026-09-15: the owner deliberately added a reward program, so OPEN-7 is no longer fully open. The check was replaced rather than deleted — the page may describe that program and no other mechanic. See the owner-decisions section."
      },
      {
        "id": "5.6",
        "title": "Storing memory is not an onchain operation, and holding the token grants no access to other users' records",
        "summary": "Memory and the token touch nowhere: the core does not know whether a token exists, and a payout address is not a sign-in.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/wallet-payout-vs-identity.test.ts"
          }
        ],
        "status": "pinned"
      }
    ]
  },
  {
    "id": "6",
    "title": "6. Invariants",
    "clauses": [
      {
        "id": "6.1",
        "title": "Invariant 1 — every record has a workspace, author, source and version; merging destroys no source",
        "summary": "Authorship and evidence are separate fields, a superseded version stays readable, and merging leaves every source intact.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "6.2",
        "title": "Invariant 2 — merging never broadens access",
        "summary": "A private record stays out of a shared block even when the topic matches, and nothing merges across workspaces.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "6.3",
        "title": "Invariant 3 — a retried write creates no second record; identical text from another author keeps its provenance",
        "summary": "The stored result replays for the same key, a reused key with new content is rejected, and two agents saving the same sentence keep both names.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/acceptance",
            "file": "packages/acceptance/src/acceptance.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "6.4",
        "title": "Invariant 4 — acknowledged records survive a restart; concurrent corrections never silently overwrite",
        "summary": "Everything acknowledged reads back after reconnecting, a stale correction is refused, and exactly one of two racing corrections wins.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/acceptance",
            "file": "packages/acceptance/src/acceptance.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "6.5",
        "title": "Invariant 5 — a detected conflict cannot vanish without a recorded resolution or a deletion",
        "summary": "The conflict is reported on every recall, closes only through a resolution that names its author, and reopens on a third value.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/acceptance",
            "file": "packages/acceptance/src/acceptance.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "6.6",
        "title": "Invariant 6 — derived memory cites real source versions, and a stale summary is never served as current",
        "summary": "A block is pinned to the versions it was built from, marked stale when one moves, and cleared only by a rebuild.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/summaries.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "6.7",
        "title": "Invariant 7 — a deleted record never returns through search, export, cache or a dependent summary",
        "summary": "All four paths are checked, the payload is wiped, the tombstone stays honest, and a restore replays the deletion.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/backup.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "6.8",
        "title": "Invariant 8 — SDK and MCP enforce the same access and mutation rules",
        "summary": "Two equally-permissioned callers get byte-identical context, and permission flags apply the same whichever operation is called.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/acceptance",
            "file": "packages/acceptance/src/acceptance.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "6.9",
        "title": "Invariant 9 — memory text grants no permission, and revocation blocks what follows",
        "summary": "An injection attempt is stored verbatim and buys nothing; once access is revoked every later operation fails.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "6.10",
        "title": "Invariant 10 — the local core runs without the token or an external model",
        "summary": "The whole cycle completes with nothing configured, and an import's claimed author never becomes the verified one.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/acceptance",
            "file": "packages/acceptance/src/acceptance.test.ts"
          }
        ],
        "status": "pinned"
      }
    ]
  },
  {
    "id": "7",
    "title": "7. Risks and Calibration",
    "clauses": [
      {
        "id": "7.r1",
        "title": "Risk: combining different facts because the wording is similar",
        "summary": "Only exact duplicates are merged; an ambiguous pair is meant to stay separate.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/spec-3-3c-uncertain-relationships.test.ts"
          }
        ],
        "status": "partly",
        "note": "The mitigation is pinned from both sides now — merging leaves every source intact, and pairs that only look alike are left alone while an explicit signal still merges them. What is missing is the calibration the section asks for: there is no labelled set of duplicates, complements and conflicts to measure against, and the semantic thresholds are OPEN-4."
      },
      {
        "id": "7.r2",
        "title": "Risk: losing context through shortening",
        "summary": "Source records are preserved, and a truncated answer carries references and an incompleteness indicator.",
        "tests": [
          {
            "package": "@offcut/acceptance",
            "file": "packages/acceptance/src/acceptance.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/spec-2-4-context-within-the-limit.test.ts"
          }
        ],
        "status": "pinned",
        "note": "Both halves of the mitigation are asserted: a shortened answer carries references and says it is incomplete, and every source record is still in the store afterwards, unchanged. What no test does is judge how much shortening is acceptable — that is a calibration nobody has measured, and the numbers in LIMITS are chosen rather than derived from one."
      },
      {
        "id": "7.r3",
        "title": "Risk: cross-project leakage — negative tests on every path",
        "summary": "Retrieval, merge, cache, export and the HTTP surface each refuse an outsider, and answer identically for a workspace that does not exist.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/api",
            "file": "apps/api/src/__tests__/api.e2e.test.ts"
          },
          {
            "package": "@offcut/acceptance",
            "file": "packages/acceptance/src/acceptance.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "7.r4",
        "title": "Risk: author spoofing through agentId",
        "summary": "Identity comes from the connection, and an imported claim of authorship is stored separately from it.",
        "tests": [
          {
            "package": "@offcut/api",
            "file": "apps/api/src/__tests__/api.e2e.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          }
        ],
        "status": "pinned",
        "note": "OPEN-1, the client connection design, is still open; what is pinned is this server's own behaviour."
      },
      {
        "id": "7.r5",
        "title": "Risk: write conflicts or process failure",
        "summary": "Transactions, versions and idempotency keys, exercised with concurrent writes and forced restarts.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/backup.test.ts"
          },
          {
            "package": "@offcut/acceptance",
            "file": "packages/acceptance/src/acceptance.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "7.r6",
        "title": "Risk: malicious instructions inside memory",
        "summary": "Record text never authorizes anything, and the model is told the text is data.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/summaries.test.ts"
          }
        ],
        "status": "pinned",
        "note": "The spec says so itself: what an external agent does with the text it was handed is not something OFFCUT controls."
      },
      {
        "id": "7.r7",
        "title": "Risk: deleted information remains in a copy",
        "summary": "Derived data is invalidated, indexes cleaned, snapshots pruned, and the deletion ledger is never pruned.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/backup.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          }
        ],
        "status": "pinned",
        "note": "Retention defaults to 30 days in code. Whether 30 days is the policy is OPEN-5, which is the owner's to settle."
      },
      {
        "id": "7.r8",
        "title": "Risk: an external model or its summary is wrong",
        "summary": "The module is off by default, and a failure costs the summary and nothing else.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/summaries.test.ts"
          }
        ],
        "status": "pinned",
        "note": "The authorized provider and the quality checks are OPEN-4."
      },
      {
        "id": "7.1",
        "title": "7.1 Acceptance — the eight checks and the primary check",
        "summary": "Every row of the acceptance table is a test, and the primary check demonstrates a new agent continuing a task from merged memory.",
        "tests": [
          {
            "package": "@offcut/acceptance",
            "file": "packages/acceptance/src/acceptance.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "7.2",
        "title": "Before release: supported clients, data format, limits and deletion policy must be fixed",
        "summary": "A release gate, not a behaviour.",
        "tests": [],
        "status": "unpinned",
        "note": "Unpinned because it is a release gate rather than a behaviour: the items in it are OPEN-1, OPEN-2, OPEN-3 and OPEN-5, they belong to the owner and the team, and no test can take a decision."
      }
    ]
  },
  {
    "id": "8",
    "title": "8. Open Questions",
    "clauses": [
      {
        "id": "OPEN-1",
        "title": "Which MCP clients are supported, and how do they separate permissions between subagents?",
        "summary": "Undecided. The server treats a client that cannot distinguish subagents as one principal.",
        "tests": [
          {
            "package": "@offcut/api",
            "file": "apps/api/src/__tests__/api.e2e.test.ts"
          }
        ],
        "status": "partly",
        "note": "Only the fallback behaviour is pinned. No supported-client list exists."
      },
      {
        "id": "OPEN-2",
        "title": "Which local store and record schema, and how are migrations defined?",
        "summary": "Answered in code by Prisma over SQLite or PostgreSQL, with a bootstrap that creates and migrates the store on first use. Not yet ratified as the decision.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/bootstrap.test.ts"
          }
        ],
        "status": "partly",
        "note": "Pinned as far as code can pin it: the bootstrap tests assert the schema this store ships with. Which store OFFCUT commits to is still an owner decision."
      },
      {
        "id": "OPEN-3",
        "title": "Maximum agents, record size, workspace size and context limit",
        "summary": "Four numbers now exist in packages/core/src/types.ts and are enforced; the maximum size of a workspace is still not set anywhere.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/agent-limit.test.ts"
          }
        ],
        "status": "partly",
        "note": "Record text stops at 20 000 characters, one import at 1 000 records, a retrieval at 6 000 characters by default and 60 000 at most, and a workspace at 200 live agent keys — each refused in the same shape as the others, each justified in the code from something already in the system rather than chosen for looks. What the clause also asks for and still has no number is the maximum size of a workspace itself. The agent cap counts and inserts in separate statements, so two owners minting at the same instant can land a workspace one over its cap; that is deliberately harmless — an over-limit workspace keeps working and the next mint is refused — and deliberately written down."
      },
      {
        "id": "OPEN-4",
        "title": "Are model summaries needed in the first release, with which provider, and how is quality evaluated?",
        "summary": "Undecided. The module exists, is off by default, and validates references rather than truth.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/summaries.test.ts"
          }
        ],
        "status": "partly",
        "note": "What is pinned is that the module is safe when off and honest when on. Whether it ships, and how its quality is judged, is open."
      },
      {
        "id": "OPEN-5",
        "title": "Backup cleanup timing, and restoration without resurrecting deleted data",
        "summary": "Half answered: a restore replays deletions and retention defaults to 30 days. The policy itself is not ratified.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/backup.test.ts"
          }
        ],
        "status": "partly",
        "note": "The 30-day default and the deletion ledger are pinned. The retention policy itself has not been agreed."
      },
      {
        "id": "OPEN-6",
        "title": "Package names, license and name/ticker clearance",
        "summary": "Undecided. The @offcut npm organisation is reserved and nothing has been published; publishing is a team decision, not a specification requirement.",
        "tests": [],
        "status": "unpinned",
        "note": "Unpinned because it is undecided, not because it is unfinished work: the @offcut organisation is reserved and nothing has been published, publishing is a team decision rather than a requirement of the specification, and a reservation is not a thing a test can assert."
      },
      {
        "id": "OPEN-7",
        "title": "Is there a paid service, how is $OFFCUT used, and what are the confirmed launch parameters?",
        "summary": "Partly answered: on 2026-09-15 the owner gave the token a reward utility. Pricing, and the launch parameters including the contract address, are still open.",
        "tests": [
          {
            "package": "@offcut/rewards",
            "file": "packages/rewards/src/__tests__/accrual.test.ts"
          },
          {
            "package": "@offcut/web",
            "file": "apps/web/src/__tests__/token-section.test.tsx"
          }
        ],
        "status": "partly",
        "note": "See the owner-decisions section for what was decided and what it deliberately overrides."
      }
    ]
  },
  {
    "id": "9",
    "title": "9. Optional Extension — Model Summaries",
    "clauses": [
      {
        "id": "9.1",
        "title": "Not required for basic merging, and disabled by default",
        "summary": "Nothing is sent anywhere until an owner turns it on, and only an owner may.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/summaries.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "9.2",
        "title": "Output is labelled derived, cites source versions and passes structural validation",
        "summary": "Invented citations are rejected and real ones kept, the block names the model that wrote it, and a deterministic block is never replaced by a model one.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/summaries.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "9.3",
        "title": "The model gains no permission to change sources, resolve conflicts or reach a new audience",
        "summary": "Whatever the model returns, nothing is changed, nobody's conflict is decided, and another agent's private records are never sent.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/summaries.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "9.4",
        "title": "When the model fails, the linked records come back without a summary",
        "summary": "A missing credential, a provider error or an unexpected shape costs the summary; writing, merging and retrieval carry on.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/summaries.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "9.5",
        "title": "The provider credential never leaves the process",
        "summary": "Not in an error, not in a report of a refusal, not in a quoted reply, and never as plaintext in the store.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/summaries.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/secrets.test.ts"
          }
        ],
        "status": "pinned",
        "note": "Beyond the specification, which says nothing about credential storage. The tests exist because the module needs a credential."
      }
    ]
  },
  {
    "id": "owner",
    "title": "Owner's decisions taken after v3.1",
    "clauses": [
      {
        "id": "own.1",
        "title": "OPEN-7 partly closed: the token was given a utility on 2026-09-15",
        "summary": "Section 5 forbade inventing a mechanic to fill the section. The owner lifted that ban deliberately and added a reward program, so the divergence is recorded here rather than discovered later.",
        "tests": [
          {
            "package": "@offcut/web",
            "file": "apps/web/src/__tests__/token-section.test.tsx"
          }
        ],
        "status": "pinned",
        "note": "The check against invented mechanics was replaced, not deleted: the page may describe this program and nothing else."
      },
      {
        "id": "own.2",
        "title": "What is paid for: memory another agent actually retrieved, once in a record's life",
        "summary": "A record credits its author when a different agent retrieves it, once however many retrievals or agents follow — a uniqueness constraint in the database, not a rule in code.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/credits.test.ts"
          },
          {
            "package": "@offcut/api",
            "file": "apps/api/src/__tests__/api.e2e.test.ts"
          }
        ],
        "status": "pinned",
        "note": "Superseded later the same week: retrievals are now a product statistic and confirmed AI spend is what pays. The mechanism still runs and is still tested."
      },
      {
        "id": "own.3",
        "title": "What that cuts off: record spam, agent spam, repeat reads, reading your own records",
        "summary": "Writing earns nothing however much of it there is, agents earn nothing by existing, and nobody is paid for reading themselves.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/credits.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "own.4",
        "title": "What it does not cut off, knowingly: one person with two agents",
        "summary": "No metric resistant to farming exists while accounts are free; the money is protected by a daily ceiling, a per-earner cap, and rules that live off-chain and can change in a minute.",
        "tests": [
          {
            "package": "@offcut/rewards",
            "file": "packages/rewards/src/__tests__/accrual.test.ts"
          },
          {
            "package": "@offcut/rewards",
            "file": "packages/rewards/src/__tests__/config.test.ts"
          }
        ],
        "status": "pinned",
        "note": "One accrual test measures the gap instead of closing it: a farm spread over five addresses is paid 2.77x what the same spend earns behind one."
      },
      {
        "id": "own.5",
        "title": "Accepted consequence: a user with one agent earns nothing",
        "summary": "One agent, however much it writes and reads back, earns nothing — and the earning starts the moment a second agent uses that memory.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/credits.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/spec-own-5-single-agent-earns-nothing.test.ts"
          }
        ],
        "status": "pinned",
        "note": "Run as the scenario it actually is rather than as two halves: a single agent writes a week of records, reads every one of them back, and the total stays zero. A “solo bonus” added later to make that number less discouraging is what this would catch."
      },
      {
        "id": "own.6",
        "title": "The wallet on the site is for receiving rewards, never for memory",
        "summary": "Writing and reading still need no wallet and no network. The wallet is a second sign-in door and a payout address, and where you are paid is not who you are.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/invariants.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/wallet-payout-vs-identity.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/wallet-identity.test.ts"
          },
          {
            "package": "@offcut/api",
            "file": "apps/api/src/__tests__/api.e2e.test.ts"
          },
          {
            "package": "@offcut/web",
            "file": "apps/web/src/__tests__/login-doors.test.tsx"
          },
          {
            "package": "@offcut/web",
            "file": "apps/web/src/__tests__/link-wallet.test.tsx"
          }
        ],
        "status": "pinned",
        "note": "Invariant 10 still passes, which is the point: the core does not know a wallet exists."
      },
      {
        "id": "own.7",
        "title": "The metric that pays is confirmed AI spend through a supported integration",
        "summary": "An agent's claim earns nothing until the provider confirms the generation; one request counts once, every refusal is named with its reason, and spend nobody can confirm is reported as unconfirmed rather than as zero.",
        "tests": [
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/usage.test.ts"
          },
          {
            "package": "@offcut/core",
            "file": "packages/core/src/__tests__/openrouter.test.ts"
          },
          {
            "package": "@offcut/rewards",
            "file": "packages/rewards/src/__tests__/accrual.test.ts"
          },
          {
            "package": "@offcut/api",
            "file": "apps/api/src/__tests__/api.e2e.test.ts"
          },
          {
            "package": "@offcut/web",
            "file": "apps/web/src/__tests__/link-usage-key.test.tsx"
          },
          {
            "package": "@offcut/acceptance",
            "file": "packages/acceptance/src/usage-tool-description.test.ts"
          }
        ],
        "status": "pinned"
      },
      {
        "id": "own.8",
        "title": "Distribution is onchain: a cumulative Merkle root, published per period, claimed once",
        "summary": "A period settles once, the root only ever grows, a claim pays the difference and cannot be spent twice, and the publisher key can misdirect rewards but cannot take them.",
        "tests": [
          {
            "package": "@offcut/contracts",
            "file": "packages/contracts/test/OffcutRewards.test.ts"
          },
          {
            "package": "@offcut/rewards",
            "file": "packages/rewards/src/__tests__/merkle.test.ts"
          },
          {
            "package": "@offcut/rewards",
            "file": "packages/rewards/src/__tests__/ledger.test.ts"
          },
          {
            "package": "@offcut/publisher",
            "file": "apps/publisher/src/__tests__/publishing.test.ts"
          },
          {
            "package": "@offcut/publisher",
            "file": "apps/publisher/src/__tests__/settlement.test.ts"
          },
          {
            "package": "@offcut/web",
            "file": "apps/web/src/__tests__/claim-rewards.test.tsx"
          },
          {
            "package": "@offcut/web",
            "file": "apps/web/src/__tests__/rewards.test.ts"
          }
        ],
        "status": "pinned",
        "note": "Nothing has been deployed. The contract suite runs against a local chain and no distributor address is configured."
      },
      {
        "id": "own.9",
        "title": "The disclosure the owner agreed to appears where the figure is",
        "summary": "The contract is upgradeable, the owner can withdraw what is in it, this is not trustless, and none of it is required to use the memory system.",
        "tests": [
          {
            "package": "@offcut/web",
            "file": "apps/web/src/__tests__/rewards-page.test.tsx"
          }
        ],
        "status": "pinned"
      }
    ]
  }
]
