Surface — Coverage Manifest (v0.10.1)

Companion to language-spec.md. Read overview.md first for the pitch.

Purpose. Surface promises to make the boundaries of a system visible. This file enumerates every dimension Surface covers, which construct addresses each, since when, and crucially what Surface deliberately does not cover in this version.

If a dimension is not in §1 and not in §3, it is out of scope for v0.10.1 — neither covered nor deliberately excluded; it just hasn't been considered yet. Such dimensions are tracked in ../../../TODO.md and are a normal feedback channel from R-round agents.

This document is normative. A Surface conformance test must:

  • Reject every spec missing a §1 required construct.
  • Not silently address any §3 excluded dimension.

1. Dimensions Surface covers

The table is read as: dimension → the language construct that addresses it → since-version → status.

Status codes:

  • R = required (compiler errors if absent).
  • S = supported (available; opt-in or context-dependent).
  • D = derived (computed/checked from other declarations; no explicit user-facing construct).

1.1 Structural

DimensionConstructSinceStatus
Module identity & compositionmodule <QualifiedName>v0.2R
Multi-file modulesfiles unioned by module headerv0.4S
Nested / sub-modulesqualified module names; module Foo.Barv0.2S
Module visibilitymodule … privatev0.2S
External configurationextern <Name> : <Type>v0.3S
Model parametersconst <Name> : <Type>v0.2S

1.2 Domain modelling

DimensionConstructSinceStatus
Types (Nat/Int/Bool/Set/Seq/Map/…)§3 type grammarv0.2R
Records & tagged unions{ field: T, … }; `ABC`
Map totalityMap[K -> V] partial; total via comprehensionv0.7R
Cartesian products & tuple keysA cross B; (a, b)v0.6S
Actors & subtypingactor A; actor B extends Av0.3R
Events (typed observations)event Name(…)v0.3R
Observables (pure derived views)observable name(…) : T = exprv0.4S
Actor-relative observablesobservable for u: <Actor> …v0.9S
derived surface statestate { f: T derived [shape: …] } (projection lives in substrate's maps)v0.10S
State-field retention classstate { f: T retention: <cls> }v0.10S
private state-field modifierstate { f: T private }v0.10S (convention)

1.3 Behaviour

DimensionConstructSinceStatus
Surface state & actionssurface { state {…} action …(…) … }v0.2R
Positive preconditionswhen <Pre>v0.2R
Error modelraises { Name when G }v0.3R
Branch coveragelabeled if/else; project-level coverage checkv0.7R
Bounded iterationfor x in S do …v0.4S
Optional unwrapif let Some(x) := … then …v0.7S
Choose / Hilbert epsilonchoose <name>: T. P; choose x in S. Pv0.4S
Aggregation across replicasaggregate Comp[id].expr using <agg>v0.6S
Atomic step (within then)one TLA+ next-state disjunct per leaf branchv0.2D
Action return valuesaction … -> T … return ev0.3S

1.4 Mandatory coverage slots on actions (v0.9, expanded v0.10)

Each slot is a closed enum with explicit waived: "<reason>" escape. v0.10 adds freshness (seventh slot) and introduces defaults { … } and internal_action for ceremony reduction (§6.4.5 / §6.4.6).

SlotQuestionSince
idempotencyIs replay safe? Keyed by what?v0.9
auth_channelHow does the caller's identity arrive (now a SET, v0.10)?v0.9 / v0.10 set form
retentionWhat data class is touched, and how long is it retained?v0.9
rate_limitWhat rate is permitted per actor/target/global?v0.9
observabilityWhich actors learn that this action happened, via which events?v0.9
availabilityWhat is this action's expected availability class?v0.9
freshnessHow stale may the result be (symbolic epochs)?v0.10

See language-spec.md §6.4 for the closed enum of legal values per slot. The slot pass (surface check --slots) is a precondition for codegen.

v0.10 ceremony-reduction constructs:

  • defaults { … } (§6.4.5): a top-level block inside surface that fills slots not explicitly assigned per action. Explicit per-action overrides take precedence. Every slot still resolves to a definite value; no "implicit waiver" via omission.
  • internal_action (§6.4.6): a keyword that auto-fills four slots (auth_channel: trusted_caller, rate_limit: waived: "internal", availability: maintenance_window, and an implicit internal marker for the docs projection). Three slots remain mandatory (idempotency, retention, observability, freshness).

1.5 Refinement (surface ↔ substrate)

DimensionConstructSinceStatus
State projectionmaps { surface_field = expr }v0.2R
Action realisationrealizes { surface.A(…) by Comp.a when … }v0.2R
Internal (non-realising) actionsinternal { Comp.action; Comp.*; … }v0.3R
External / out-of-band actionsrealizes { surface.A(…) by EXTERNAL }v0.4S
Stutter for no-effect branchesrealizes { surface.A[label] by stutter } (compose)v0.7S
Default-deny on substrate actionsevery substrate action ∈ realizes ∪ internalv0.3R
Auxiliary variablesauxiliary { history h := … ; prophecy p := * }v0.3S
Partial field ownershippartial substrate … owns { … }v0.5S
Compose of peer substratescompose <N> = <S1> + <S2> { … }v0.5S
Cross-substrate guardsrealizes { … when <other_substrate>.<aux> … }v0.6S
Cross-substrate aux (two-way contract)aux … cross_visible invariant …v0.7S
Replicated componentsreplicate C[id in IDS] { … }v0.4S
FIFO channels (with multiplicity)channel C { from A[…] to B[…] }v0.4S
Cross-substrate channelschannel C { … } inside composev0.5S
Fairnessfairness weak/strong Av0.3R for liveness
Error refinementmirror-guard or disable-action pattern (§6.2.1)v0.7R

1.6 Verification artefacts

DimensionConstructSinceStatus
Safety propertiesproperty name { always P }v0.3S
Liveness propertiesproperty name { eventually P }v0.3S
Scenarios (executable use cases)scenario "…" kind: … { … }v0.3S
Forbidden tracesscenario … kind: forbidden { … }v0.3S
Reusable history predicateshistory_predicate name(…) { … }v0.5S
Time-relative state snapshotsstate_at(e)v0.7S
Event-log helpersevents_before / events_after / first / last / count / betweenv0.6S

1.7 Security

DimensionConstructSinceStatus
Integrity reachabilityattacker A { controls … goal … }v0.3S
Authentication mappingauthentication { surface_actor of … = … }v0.3R when attacker is run
Permission predicatesBoolean observable referenced from whenv0.7S

1.8 Static obligations (v0.10 — full catalog, §15)

DimensionObligation kindRuleSeveritySince
Availability dependence (read)availability_depends_on(C)R-AVAIL-READmediumv0.9
Availability dependence (channel)availability_depends_on(C)R-AVAIL-CHANNELmediumv0.9
Availability declared vs closureavailability_consistency(...)R-AVAIL-CONSISTENCYhighv0.10
Channel reliability class mismatchavailability_channel_class(...)R-AVAIL-CHANNEL-CLASShighv0.10
Trust transitivitytrust_transitive(C)R-TRUST-PARAM-AUTHhighv0.9
Concurrent write conflictswrite_conflict(field)R-WRITE-CONFLICThighv0.9
Replay amplificationreplay_amplification(action)R-REPLAY-AMPmediumv0.9
Retention propagation across actionsretention_propagation(src, dst)R-RETENTION-FLOWhighv0.9
Information flow (state → sink)information_flow(src, sink)R-INFO-FLOWhighv0.10
Anonymous action reads PIIpii_anon(action, field)R-PII-ANONmediumv0.10
Actor-view leakactor_view_leak(obs, actor_var)R-ACTOR-VIEW-LEAKhigh (hard error)v0.9
Derived-state assignmentderived_write(field, action)R-DERIVED-WRITEhigh (hard error)v0.10
Strong freshness without sync ackfreshness_channel(action, channel)R-FRESHNESS-CHANNELhighv0.10

Framework remains closed — new rules enter only via versioned spec changes (v0.10 added six; v1.0 will freeze the framework itself).

1.9 Output artefacts

DimensionConstructSinceStatus
TLA+ codegen (surface)surface emit tlav0.3S
PlusCal codegen (substrate)surface emit pluscalv0.3S
Gherkin skeletonssurface emit gherkinv0.3S
Markdown docs (with slot checklist)surface emit docsv0.3 (slots v0.9)S

2. Mandatory action slots — detailed reference

Reproduced from language-spec.md §6.4 for review-without-cross-referencing. The normative form is in the spec.

SlotClosed enum (abridged)
idempotencyidempotent | idempotent by(<args>) | at_most_once | at_least_once | waived
auth_channelsession | bearer_token | signed_request | capability_url | mtls | trusted_caller | anonymous | waived
retentionephemeral | transactional | audit(period=D) | pii(class=C, ttl=D) | secret | waived
rate_limitper_actor(n, per=D) | per_target(arg, n, per=D) | global(n, per=D) | unlimited | waived
observabilitycaller_only(E, …) | target(arg, E, …) | broadcast(E, …) | silent | waived
availabilitycritical | best_effort | maintenance_window | read_only_failover | waived

Waivers are not silence. A waived: "<reason>" slot is visible in source, in the docs projection, and in the obligation pass output. A reviewer can grep for waived: and audit every one. The intent is that "this dimension does not apply to this action" is a positive design decision, not the absence of a decision.


3. Deliberately excluded from v0.9

Each entry: what is excluded, why, where you would expect to find it if Surface had it, and the targeted version if any.

3.1 Confidentiality / non-interference / 2-safety

Excluded because: confidentiality is a hyperproperty (a relation between pairs of executions, not a property of a single execution). TLA+ reachability cannot express it directly; encoding requires Apalache-only tricks. The R3 formal-methods critique deemed this out of scope. v0.9 maintains the v0.3 decision.

Workaround: model the integrity-side of confidentiality ("attacker causes effect Y") with attacker blocks (§10). Pure read-only leaks remain out of scope.

Target version: none. Will be revisited only if a concrete use case demands it.

3.2 Real (wall-clock) time

Excluded because: introducing real-valued time complicates the semantics for rare cases. v0.10 introduces symbolic time via freshness: bounded(epochs=n) and stale_while_revalidate (§1.4 + spec §6.4.1). An "epoch" is a count of substrate propagation steps; an "epoch" is not a second. The retention: audit(period=D) slot uses a Duration const for documentation but the value is not used in checking. Wall-clock time remains parked.

Target version: none planned. Real-time attackers and duration arithmetic would require a different checker (TLA+ Timed, etc.) and are not currently a need.

3.3 Cross-module liveness composition

Excluded because: liveness does not compose by trace inclusion; proving an eventually at the parent level from eventuallys at the child level requires assume/guarantee fairness, which is research-grade.

Target version: v0.11 (was provisionally targeted at v0.8 in the v0.7 docs, then v0.10; v0.10 spent its budget on slot hardening and the rule catalog).

3.4 Author-extensible obligation rules

Excluded because: allowing organisations to add rules would let two Surface specs mean different things in different orgs. The closed catalog (§15) is the language; new rules enter only via versioned spec changes. v0.10 expanded the catalog from 6 to 12 built-in rules; v1.0 will freeze the framework but keep the catalog language-versioned.

Target version: not currently planned.

3.5 surface diff between spec versions

Excluded because: bidirectional refinement on potentially renamed actions/state is research-grade. Dropped from v0.3, still dropped.

Target version: none.

3.6 Inter-instance messaging inside one replicate

Excluded because: Edge[i].sends to Edge[j] would require a more elaborate channel typing rule. Use a third component (a bus) or a shared channel via compose.

Target version: none planned.

3.7 Attacker inheritance

Excluded because: compose by copy/paste is fine while there is no real-world attacker library. Revisit when an actual reusable attacker pattern emerges.

Target version: none planned.

3.8 Channel semantics enums

Excluded because: exactly_once doesn't really exist; modelling unreliability with explicit internal actions on a plain FIFO channel is the canonical approach and is more truthful.

Target version: none.

3.9 Module value parameters

Excluded because: replicate covers per-instance values inside a substrate; extern covers module-level configuration. Adding a third mechanism would be redundant.

Target version: none planned.

3.10 Confidence levels / probability

Excluded because: Surface is a discrete-state formal language. Probabilistic refinement (Markov chain / Markov decision process) would be a different language; can be revisited but is not on the roadmap.

Target version: none planned.

3.11 Hierarchical compose

Excluded because: compose v0.5 joins partial substrates that target the same surface. Hierarchical composition (parent surface refined jointly by sub-module surfaces) is the v0.4 module/sub-module story and is separate. Combining the two is not currently a real need.

Target version: none planned.


4. Tooling matrix

Tool invocationPassWhereCatches
surface check --slotsSlot passFrontendMissing/illegal §6.4 slots
surface check --obligationsObligation passFrontendUnacknowledged §15 derived obligations
surface check --refinementRefinementTLA+ backendSubstrate diverges from surface
surface check --livenessTemporalTLA+ backendeventually violated under fairness
surface check --attacker <name>ReachabilityTLA+ backendIntegrity counter-example
surface checkAll of the aboveBothPipeline default
surface emit tla / pluscalCodegenBackendProduces .tla / PlusCal
surface emit docsDoc projectionFrontendMarkdown with slot checklist
surface emit gherkinTest skeletonsFrontendGherkin from scenarios
surface migrate v0.7 v0.9MigrationFrontendInserts waivers; flags review sites

Frontend vs. backend. The frontend passes are deterministic and local; they require no model checker and produce Rust-style errors that point to a fix site. The backend passes use TLA+/PlusCal and TLC/Apalache and produce counter-example traces. Most of Surface's value (the slot pass + the obligation pass) is in the frontend.

v0.9 positioning. TLA+/PlusCal is Surface's primary backend, not its semantics. The language has its own toolchain and would still be useful if a different backend (e.g. Lean, Coq, an Alloy embedding, or a bespoke checker) replaced TLA+. Surface specs are not "TLA+ with sugar"; they are boundary descriptions with a TLA+ codegen.


5. Compatibility / migration

5.1 v0.7 → v0.9

Three breaking changes:

  1. Mandatory action slots (§6.4). Every action must carry the six slots or be migrated. The surface migrate v0.7 v0.9 tool inserts waived: "v0.7 migration; review" at every missing slot; specs compile after migration but each waiver is a review site.
  2. observable for <Actor> (§5.3) is a new construct. Pre-v0.9 specs continue to type-check; opting in is voluntary, but v0.9 examples migrate global actor-relative state to the new form.
  3. Obligation pass (§15). Specs that import cross_visible aux variables, declare param. authentication, or fan messages out through channels will produce obligation warnings/errors on first surface check. Add an acknowledged { … } block or restructure.

The TLA+/PlusCal codegen is unchanged between v0.7 and v0.9. v0.9 is a frontend upgrade, not a semantics change.

5.2 v0.9 → v0.10

Six changes, three of which require source edits:

  1. freshness: slot is mandatory on every surface action. The migrator inserts freshness: waived: "v0.9 migration; review"; replace per action.
  2. Slots apply to surface actions only. Any v0.9 spec that accidentally put slots on substrate component actions is rejected; strip them.
  3. auth_channel may be a set. Single-value usage is unchanged (one-element set is sugar); multi-channel actions migrate to set form.
  4. acknowledged { … } syntax tightened (§15.3): because: is per-entry; duplicate cross-substrate acks must agree. v0.9 specs that used per-block because: need a one-line rewrite.
  5. E_ACK_ORPHAN is now W_ACK_NO_RULE (warning, not error). Proactive acknowledgements are legal.
  6. New constructs (opt-in, no breakage): derived from state fields (§6.6), defaults { … } block (§6.4.5), internal_action (§6.4.6), state-field retention: annotations (§6.5).

surface migrate v0.9 v0.10 handles 1–5 mechanically; 6 is voluntary adoption. The v0.10 examples (url-shortener, twitter) demonstrate the new constructs.

The obligation rule catalog grew from 6 to ~12 rules; existing v0.9 specs may produce new warnings/errors from the v0.10 rules (notably R-AVAIL-CONSISTENCY catches declared-vs-closure availability mismatches that v0.9 did not flag).

5.3 The "70 → 100" framing (revisited at v0.10)

Before v0.9, Surface answered: "given that you have specified the boundaries, does your implementation respect them?" — refinement checking. v0.9 also answered: "have you specified the boundaries?" — the slot pass and the obligation pass.

v0.10 fills in three things v0.9 promised but didn't deliver: the rule catalog is substantive (12 rules, not 6); the derived state pattern is named (closing a 3-round backlog item); and ceremony reduction via defaults + internal_action brings slot-heavy specs back into readable territory. Slots are still mandatory, but actions inherit shared values and internal actions get a sane preset.

Authors who maintain only v0.7-style refinement and waive every new slot are still valid users — but their spec now shows, in source, where the open boundaries are. That visibility is the v0.9/v0.10 deliverable.