90 — Network and contracts
BuiltRendered from 90-network-contract-architecture.md in the public repository. Edits belong there.
This page states how one instance publishes its identity, how two instances form an encrypted contract, and how a sandbox reads documents another sandbox published to it. The canonical contracts are contract_formation.md, hosted_alias_interface.md and tool_package_update_contract.md under docs/contracts/. The channel surface built on this layer is described in 91.
The implementation is in fnd_app/instances/_shared/runtime/. File names below are in that directory unless a path is given.
Identity: the contact card
Each instance has a contact card in the registrar. Two card fields carry its network identity (micyte/core/datum_ops/field_registry.py):
| Field | Address | Content |
|---|---|---|
public_signature | 3-1-17 | The instance's Ed25519 public key, as base64 of the raw 32 bytes (44 characters). |
instance_endpoint | 3-1-18 | The address the instance accepts contract requests at. |
The dns cell is the instance's website domain; it is not the endpoint. An instance with no instance_endpoint is not reachable and its inbound contract route does not answer.
A handshake verifies the requester against the key on its card. The contract record does not carry the key; a contract that carried its own authorizing key would authorize itself.
The public_signature field holds 64 characters. A PEM-encoded Ed25519 key (about 113 characters) does not fit; the PEM is rebuilt from the base64 at verify time.
Signing keys
instance_keys.py keeps keys in the instance's private key directory: files 0600 inside a 0700 directory. It refuses to write with wider permissions and refuses to re-mint an existing key with different bytes.
The signing key is derived, not random: HKDF-SHA256(root_seed, salt="mycite.v2.identity.v1", info="<msn_id>|<generation>") gives the Ed25519 seed (derive_signing_seed). The root seed is generated once per instance. The same address under the same root always gives the same key; recover_instance_key re-derives a lost key file from a restored root. A new msn gives a new key; a rotation increments the generation.
Per-contract symmetric keys are random and minted during the handshake.
The handshake
contract_handshake.py:
| Step | Function | What it does |
|---|---|---|
| Request | build_request | Signed with the requester's card key; carries a fresh X25519 ephemeral key. |
| Verify | verify_request | Checks the signature against the requester's card. |
| Offer | build_offer | The responder mints the contract's symmetric key and seals it to the ECDH shared secret. |
| Open | open_offer | The requester unseals the key. |
| Traffic | seal_traffic / open_traffic | Every later message is sealed with that key. |
| Expiry | key_is_expired | Key age against key_period_seconds (default 30 days). |
Schemas: mycite.v2.network.contract.request.v1, .offer.v1, .sealed.v1. Clock skew tolerance: 120 seconds.
The ephemeral key is signed so that a third party cannot substitute its own.
build_request does not store its ephemeral key, so sending the same request again also collects the answer: an undecided request returns "recorded"; a decided one returns the existing key re-sealed to the ephemeral in hand. A repeated request never mints a new key and keeps the original key_minted_at.
Replay protection
contract_sequence_store.py keeps the last accepted sequence number per contract and key epoch in contract_transport.sqlite3. accept_sequence uses one atomic UPDATE … WHERE last_seq < ?, so a message with an old or repeated sequence number is refused.
Contract lifecycle
contract_negotiation.py: open_request, receive_request, accept_request, answer_request, refuse_request, revoke_contract. _legal_events derives the allowed events from the record's state; an event that is not allowed raises. contract_store.py stores records with schema mycite.portal.contract.v2 in the instance's private contracts directory. Revoking a contract destroys its key.
Inbound and outbound routes
- Outbound.
instance_client.py:post_contract_requestposts to/__instance/contract/requestat the endpointendpoint_forreads off the peer's card. - Inbound. The
/__instance/route verifies the card signature before it records anything. It is separate from/__channel/, which has only GET routes. - Closed channels.
closed_channel_admission.pyadmits a caller that presents traffic sealed with the contract key, or a signed bootstrap request (clock skew 300 seconds). Every refusal returns the same 404 an unknown channel returns; the reason is logged, not returned.
The local audit log refuses records carrying key material (FORBIDDEN_LOCAL_AUDIT_KEYS in fnd_app/packages/modules/cross_domain/local_audit/service.py).
Reading another sandbox's documents: sources manifests
micyte/core/sources.py. A sandbox does not read another sandbox's documents directly. It reads its own sources manifest, whose rows the owning sandbox published to it. A row holds a name, a kind and a content hash at rf.3-1-12.
The hash depends on the row's kind:
| Kind | Hash pinned |
|---|---|
datum_document | The document-id version hash. |
boundary, taxonomy, profiles, events | The MSS bitstream hash of the document's datum closure. |
The two hashes differ for the same document. A stale pin is a fault and is fixed by re-pinning. A missing or unverifiable source is reported, not treated as a failure.
Citation
A hyphae (micyte/core/mss/hyphae.py, schema mycite.v2.mos.hyphae.v2) is the network's citation form. build_hyphae(address, *, index, document, source_msn) requires the document, refuses a document that does not contain the address, and writes the canonical document_id into the payload. Hyphae v1 is refused. A datum address is local to its document; the same address appears in many documents, so a closure is resolved through DocumentScopedIndex (micyte/core/mss/document_adapter.py), which reads the document's own rows first.
Not built
- Discovery without a contract. There is no published registry an instance can pull, without a contract, to find a peer's card. An instance must already know the peer.
- Resolving a magnet reference on a remote instance. The reference form
hy.<msn>.<sandbox>.<document>.<version_hash>.<address>is defined; no operation resolves it across instances. - A rotation policy. Expiry is time-based only; whether rotation re-handshakes or ratchets is undecided.
- Joining from an open channel. Joining requires a contract, so a browser on an open channel cannot join.
/__channel/has no write route and will not get one. - Delivery between two instances on different machines. It has not happened.
fnd_app/tests/integration/test_contract_delivery_over_tcp.pyruns two instances over a real socket with separate private directories.
fnd_app/packages/modules/cross_domain/network_root/service.py is a presenter over the local audit log. Its contract_id and contract_filters filter audit rows and are unrelated to network contracts.