Package Contracts

Two internal packages carry contracts that other perspectives depend on existing and behaving exactly as documented. They are small, frozen, and load-bearing. This page is the canonical description of what each package owes its consumers.

@cv/mutations

lib/mutations/ is the typed op catalog and the batch router. It is the single source of truth for the workspace broker contract: what kinds of writes exist, what payload each one carries, and how they compose.

Contract:

  • opsCatalog.ts exports the union type of every legal op. New op kinds — or incompatible payload changes — bump OP_CATALOG_VERSION so the broker can reject stale clients with a precise error.
  • OpIdEnvelope mixin stamps each op with an opId nanoid that the server uses to deduplicate retries. The server keys (workspace_id, sub_doc, op_id) against workspace_sub_doc_ops so a network retry returns the original commit clock instead of double- applying.
  • applyOp(doc, op) is the apply-side adapter. It rejects unknown kinds with unknown_op_kind and the current catalog version so a stale consumer fails loud, not silent.
  • batch is the atomic-composition primitive. Sub-ops carry { subDoc?, op }. A same-sub-doc batch lands as one Yjs transaction, one CAS update, one op-log row, one broadcast. A cross-sub-doc batch rides D1's env.DB.batch([...]) so all CAS updates commit together.

Consumer expectations:

  • ui drives editor flows by composing cvl.* action ops that expand to node.* sub-ops inside one batch.
  • mcp speaks the same catalog so an agent and a human edit through identical primitives — the basis of [[api-mcp-shared-operations]].
  • relay/cf stays op-agnostic at the byte level; it relays Yjs frames without parsing the catalog.

The catalog version is currently 8. Adding an op without bumping the version is a bug; relying on a version <= N envelope without checking the catalog is also a bug.

@cv/health

lib/health/ is the cross-perspective state-shape package. It defines the three concentric types — Health, Check, Metric — that every perspective (admin, wiki, ops/status) consumes to render the same operational picture.

Contract:

  • Health is the outermost shape: a perspective's overall green / amber / red, with a list of Check instances that contributed.
  • Check is a single boolean-or-graded assertion plus its observation window. Checks are stable IDs; consumers tag UI by check.id, not by index.
  • Metric is a numeric observation a Check can quote (latency, error rate, quota-percent-consumed). Metrics carry units so renders cannot accidentally drop a multiplier.
  • The package owns the shape and the vocabulary. It does not own observation sources. Each perspective populates its Health from its own observability stack (Axiom / Cloudflare Analytics / local /metrics pulls / internal probes).

Consumer expectations:

  • cv-cockpit-data projects Health for the cockpit study without inventing new types.
  • status perspective renders public-facing health by reading identically-shaped Health from every perspective and reducing them.
  • wiki displays its build-time health snapshot using the same types so the wiki Atlas and the live ops/status page never speak different dialects.

The package's job is to keep the dialect identical across perspectives. If a new operational concept needs a new type, it goes here; introducing parallel health shapes in a single perspective is the failure mode this contract exists to prevent.

Actor Policy Gate

Graph metadata editing, CVL selection cardinality, and similar guarded writes share one policy shape: validators emit hard, soft, and info issues; the actor policy gate decides whether the actor can save. Humans may save soft violations with warnings, agents need force: true for soft violations, and system/pipeline writers must obey soft and hard rules. Domain validators remain domain-specific.

The graph metadata API/MCP contract is documented in GRAPH-METADATA-EDITOR.md.

Source: wiki/content/architecture/PACKAGE-CONTRACTS.md