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.tsexports the union type of every legal op. New op kinds — or incompatible payload changes — bumpOP_CATALOG_VERSIONso the broker can reject stale clients with a precise error.OpIdEnvelopemixin stamps each op with anopIdnanoid that the server uses to deduplicate retries. The server keys(workspace_id, sub_doc, op_id)againstworkspace_sub_doc_opsso a network retry returns the original commit clock instead of double- applying.applyOp(doc, op)is the apply-side adapter. It rejects unknown kinds withunknown_op_kindand the current catalog version so a stale consumer fails loud, not silent.batchis 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'senv.DB.batch([...])so all CAS updates commit together.
Consumer expectations:
- ui drives editor flows by composing
cvl.*action ops that expand tonode.*sub-ops inside onebatch. - 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:
Healthis the outermost shape: a perspective's overall green / amber / red, with a list ofCheckinstances that contributed.Checkis a single boolean-or-graded assertion plus its observation window. Checks are stable IDs; consumers tag UI bycheck.id, not by index.Metricis a numeric observation aCheckcan 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
Healthfrom its own observability stack (Axiom / Cloudflare Analytics / local/metricspulls / internal probes).
Consumer expectations:
- cv-cockpit-data projects
Healthfor the cockpit study without inventing new types. - status perspective renders public-facing health by reading
identically-shaped
Healthfrom 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.