Skip to content

docs: state the contract conformance requirements authors must meet - #93

Open
sanity wants to merge 1 commit into
mainfrom
docs/5320-conformance-requirements
Open

docs: state the contract conformance requirements authors must meet#93
sanity wants to merge 1 commit into
mainfrom
docs/5320-conformance-requirements

Conversation

@sanity

@sanity sanity commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Problem

The merge laws are in the whitepaper, but not in the API docs the person writing a contract actually reads. An author can implement update_state as last-write-wins today without ever being told that is wrong, and deployed contracts have done exactly that: freenet/freenet-core#5153 measured last-write-wins merges and mutual rejection accounting for a large share of all update work on the network.

Approach

Documentation only. No code changes.

Two earlier PRs already covered part of this ground (#92, idempotent and associative merge; #90, the delta-size requirement), so this fills the remaining gaps rather than restating them:

  • Canonical byte representation. Every valid logical state must have exactly one encoding. The platform compares states by bytes and has no way to know that two encodings mean the same thing, so it treats them as still-diverged and keeps trying to reconcile. Includes the practical advice an author needs: sort map and set entries, fix field order, avoid formats whose iteration order is not deterministic.

  • Merging is update_state. This is the framing that makes the failure mode legible. Returning the current state unchanged asserts merge(A, B) == A; if the peer holding B runs the same contract and does the same in reverse, the two results disagree, the peers never converge, and every future sync retries forever. It is easy to write that as a reasonable-looking "reject stale updates" check, which is exactly why it needs saying out loud.

  • summarize_state determinism, with the reason: peers compare summaries to decide whether they have converged, so a summary that varies with hash iteration order makes two peers holding identical state look permanently divergent (State updates permanently lost for rarely-changing fields: silent ContractQueueFull drop + sender-side neighbor-summary poisoning freenet-core#4857).

  • get_state_delta determinism, plus the explicit note that deltas do not need a single global canonical encoding, unlike state. Two peers reconciling from different starting points may legitimately produce different delta bytes, and delta correctness is judged by applying them and comparing the resulting canonical states.

  • Emitted states must be valid, and states declared Valid must already be canonical.

What is deliberately unchanged

The existing warnings that noncompliant behaviour may get a contract deprioritized or removed from the network.

An earlier draft of this PR softened them, reasoning that no such enforcement ships today. That is accurate, but removing a deterrent the project deliberately published is a policy decision rather than a documentation fix, and the direction of freenet/freenet-core#5320 is to make those sentences true. Softening now and re-hardening later would be churn.

Testing

cargo doc --no-deps -p freenet-stdlib builds. The 4 warnings it emits are pre-existing and all in files this PR does not touch (state.rs, update.rs, client_events.rs); the changed file produces none.

Refs freenet/freenet-core#5320

[AI-assisted - Claude]

The merge laws are in the whitepaper but not in the API docs the person
writing a contract actually reads. An author can implement `update_state` as
last-write-wins today without ever being told that is wrong, and deployed
contracts have done exactly that (freenet-core#5153).

Fills the gaps left by #92 (idempotent + associative merge) and #90 (delta
size), without restating either:

- **Canonical byte representation.** Every valid logical state must have exactly
  one encoding. The platform compares states by bytes and cannot know that two
  encodings mean the same thing, so it treats them as still-diverged and keeps
  trying to reconcile. Includes the practical advice: sort map and set entries,
  fix field order, avoid formats with nondeterministic iteration order.
- **Merging is `update_state`.** This is the framing that makes the failure mode
  legible. Returning the current state unchanged asserts `merge(A,B) == A`; if
  the peer holding B does the same in reverse, the two disagree, never
  converge, and retry forever. It is easy to write that as a reasonable-looking
  "reject stale updates" check, which is why it needs saying explicitly.
- **`summarize_state` determinism**, and why: peers compare summaries to decide
  whether they have converged, so one that varies with hash iteration order
  makes two identical peers look permanently divergent (freenet-core#4857).
- **`get_state_delta` determinism**, plus the explicit note that deltas do NOT
  need a global canonical encoding, unlike state — two peers reconciling from
  different starting points may legitimately produce different bytes, and delta
  correctness is judged by applying them and comparing canonical states.
- **Emitted states must be valid**, and states declared `Valid` must already be
  canonical.

Deliberately unchanged: the existing warnings that noncompliance may get a
contract deprioritized or removed. An earlier draft softened them, on the
grounds that no such enforcement ships today. That is accurate but it is not
ours to decide, and the direction of freenet-core#5320 is to make those
sentences true, so softening now and re-hardening later is churn.

Documentation only; no code changes. `cargo doc` produces no new warnings.

Refs freenet/freenet-core#5320

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0131oS6YAD9gMWigX8v4QR4J
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant