Wealth of Networks

Technical reference / relationship v1

The contract,
in detail.

The current specification, published directly from the implementation. An initial native contract, not an external standard.

Identifier: relationship/v1. Status: implemented initial native contract; not an external standard. It specifies meaning and authorized operations, not a database, transport, or model runtime.

Records

An entity has id, workspace_id, collection_id, namespace, version, type, kind=entity, revision, data, empty participants, optional lifecycle state, archived, and timestamps. A relationship has the same envelope and kind=relationship, with named participants roles. Each role contains an array. Read references are {id: UUID} or {restricted: true}. Creation and role patches accept UUID strings; redacted projections are never replacement input.

IDs are stable. namespace/version/type pins a type in an immutable program package. Participants can be entities or relationships; cycles are allowed but never implicitly traversed. There is no global identity deduplication or contact merge. Applications may search before creating records. An entity describing a person/agent is not a credential or authority principal.

Programs

A package contains namespace, positive integer version, types, and optional views. Each type declares kind, schema, optional roles, lifecycle, and commands. Roles declare min, max, and allowed namespace/type strings. A lifecycle declares initial and states. Commands declare an input schema, optional guard, from/to, set_data, and finite emit entries. Views declare type, optional where, and projected fields. See the bundled examples for exact JSON representations. Unknown package/type/command keywords are rejected rather than silently introducing behavior.

Schema subset: type, properties, required, additionalProperties, enum, items, minLength, maxLength, minimum, maximum, minItems, maxItems, and string format=date-time. Objects must declare properties/required and additionalProperties=false. Types are object, array, string, integer, number, boolean, and null. Default maximum string length is 4,000 and array length is 100. Definition depth is at most 10. This is explicitly not a complete JSON Schema engine.

Rules use exactly one operator per expression map: path, all, any, not, present, eq, ne, gt, gte, lt, lte. Paths start with data, input, or state and have at most 8 components. Depth is at most 10; Boolean operand lists contain at most 30 expressions. Numeric comparisons fail closed for nonnumeric values. Constants are JSON scalar/array values.

set_data maps declared target fields to expressions; the result must still satisfy the schema. from/to must name declared states. emit is at most 10 {kind:"work.requested",task:...} entries. Each emitted event references its originating record, program version and command. It is a durable intent, not hosted execution, tool consent, or verified external completion.

Operations and transports

The shared operation registry is platform/src/won/api.clj. It defines required arguments and input shapes for both transports. REST uses POST /v1/operations with {operation:"record.get",arguments:{workspace_id:...,record_id:...}}. Browser callers use their session, exact Origin and X-CSRF-Token. OAuth bearer clients can use the same REST boundary. MCP uses /mcp, tools/list, and tools/call. Operation dots become underscores in tool names. All operations have an object response. Unknown operations/arguments are rejected.

Required mutation fields include idempotency_key; record changes also require expected_revision. record.update accepts patch:{set:{...},remove:[fieldNames]} and optional roles:{add:{role:[ids]},remove:{role:[ids]}}. It cannot change lifecycle state. command.list explains requirements using optional supplied input. command.execute applies a named command only if current authority, input, state, guard, and revision all permit it.

Read operations include capabilities, workspaces, collections, program versions, example packages, record retrieval/search, command discovery, history and change feed. Mutations include workspace creation/membership, collection creation/access, program drafting/activation, record creation/patch/ archive and command execution. Human membership changes and workspace creation remain console-only. Authorized agents may draft/activate programs using explicitly delegated scopes.

Paging, authorization and history

Lists/search accept limit (1–100, default 20) and an opaque-to-clients cursor. Search filters include namespace/type/state/query/collection, or an explicit namespace/version/view. Queries search only authorized record data; they do not search or expand inaccessible participants. Views preserve record envelopes and authorization but project only selected data fields. Cursors are bound to workspace and filter/history context. Do not construct or edit cursors.

Change events have stable event_id, ordered numeric id, actor/client attribution, optional record/revision, kind, timestamp, and payload. A mutation stores a record snapshot; work requests store their task intent. Current access and participant redaction apply even to old snapshots. Feed responses include next_cursor when more data may remain, and checkpoint to poll for later changes. Consumers store the checkpoint and deduplicate event IDs. A sparse scan may return no items with a continuation. History is immutable internally, but its authorized projection may change with permissions. No event or relationship confers external authority.

Invalid arguments return 400, missing/restricted records 404, insufficient delegated authority 403, stale revisions/transition conditions/idempotency conflicts 409, and schema failures 422. MCP tool failures return isError=true with the public explanation. Unauthenticated MCP requests return 401 with protected-resource metadata discovery.

Download this contract as Markdown →