Semantic Membrane
A composed subsystem exposes exactly the state that affects externally observable future behaviour — and no more.
- Standing
- PROPOSED CHECKABLE RUNNABLE EXECUTED STAGED PUBLISHED REPRODUCED
- Last checked
- never run
- Source
- none — this record cites no check
- Limit
- PROPOSED. The phrase appears nowhere in the tree, there is no check, and no system here is known to implement one. It establishes nothing.
- Next rung
in_tree— any check that could distinguish a membrane from a boundary that merely happens not to leak today.
Why this page says PROPOSED — the derivation, not the word
- ✗ a witness is named
- ✗ its evidence kind is one the ledger already uses
- ✗ the witness path resolves in this tree
- ✗ its rung is in_tree or above
- ✗ a run is recorded for these exact bytes
- ✓ no claim is cited that could be REFUTED
- ✗ a counterexample is shipped (required once WITNESSED)
- ✗ not staged on this site, so it cannot run from the page
WITNESSED requires every line above to hold. The label is computed from them by build.mjs and cannot be typed into the registry — the build refuses a record that carries it.
Intent
Shared Observable says what must cross a composition boundary: every variable that determines a future. This pattern is its other half: what must not cross. Exposing internal, behaviour-irrelevant state makes equivalent subsystems look different and breaks convergence. The membrane is adequacy quotiented by equivariance.
Technical register
Nowhere named in the tree — PROPOSED. Its nearest relative is the frontier package's adjudication of the observable-completeness law: 'as stated, too strong alone: carrying byte-level variables breaks convergence'; it survives only as the ADEQUACY/EQUIVARIANCE pair (invariant-r10/package-v2.8/v1-provenance/03_CANDIDATE_INVARIANTS.md). Parnas's information hiding is the ancestor.
Problem
A subsystem that exposes everything is easy to write and impossible to compose: every caller couples to internals, every refactor is an interface change, and two implementations that behave identically are told apart by noise. A subsystem that exposes too little hides state that determines futures — Invisible State, the opposite failure.
Solution
State the observable (Shared Observable). State the equivalence on internal states under which futures are identical. Expose the quotient, not the representative. Write a witness that constructs two internal states in the same class and checks that every exposed byte agrees.
Real-world analogy
A restaurant's menu is a membrane: what you can order is exposed, the kitchen's shelf layout is not, and two kitchens with different layouts and the same menu are the same restaurant to a diner.
Structure — on the surface
An illustration on a compute surface: loci above, carriers below. Press Play or Step; the takeaways collect as you go. Nothing here is evidence — the witness section is.
The chapter in WRL — and the chain so far
Chapter 8 of 32 — the fragment _patterns/wrl/chain/semantic-membrane.wrl, sealed alone by wrl.js
; SEMANTIC MEMBRANE — one rotor, two projections: the membrane exposes the pose and nothing of the rotor's
; representation. Fan-out from a socket is unrestricted. sm_in is the entry.
[relay:sm_in]{sig_in, sig_out}
[spinner:sm_inside](w=16, n=8, rotor=quarter_turn_z){sig_in, socket}
[orb:sm_outside_a]{pose}
[orb:sm_outside_b]{pose}
[sm_in] --sig--> [sm_inside]
[sm_inside] --socket--> {[sm_outside_a], [sm_outside_b]}Its test bench _patterns/wrl/chain/semantic-membrane.bench.wrl — drives the entry for this chapter's own film; never part of the chain
; TEST BENCH — drives this chapter's entry alone; the chain replaces it with a wire from an earlier chapter
[pulser:sm_bench](every 1){sig_out}
[sm_bench] --sig--> [sm_in]module + bench seal to → sem-0a213fb326446d64221574567087597936629d334cdb5dcca000bc2ba1d77019
Reduced by the reference reducer (pure Python); parity with the other reducer not run for this world.
The Film, epoch by epoch (4)
epoch 1 · sha256:02b0a6ffaa59f75394a43e0197f3f7b2679b9c55acb0c186d3e80e3e7483ee4a
FILM v0.7 t=1 spinner:sm_inside:policy=forge_motor_widemac_tz_sat_v1,quat4,w=16,n=8,rotor=00b5,0000,0000,00b5,socket=sm_outside_a,config=fixed orb:sm_outside_a:policy=forge_motor_widemac_tz_sat_v1,quat4,w=16,n=8,pose=0100,0000,0000,0000,controller=sm_inside,fault=0 orb:sm_outside_b:policy=forge_motor_widemac_tz_sat_v1,quat4,w=16,n=8,pose=0100,0000,0000,0000,controller=sm_inside,fault=0 pulser:sm_bench:mode=periodic,p=1,phase=0,armed=0,done=0,nf=1 relay:sm_in:cur_out=0,next_out=1 wire:w__sm_bench__sm_in:cur=1,nxt=1 wire:w__sm_in__sm_inside:cur=0,nxt=0 admit:policy=admit_candidate_min_firstreceipt_v1,fact_capacity_fault=0,receipt_capacity_fault=0,capacity_fault=0
epoch 2 · sha256:276446debe7c100b4a17673407641984bc1aa74d0b2e4928a82801cbbe6fea7a
FILM v0.7 t=2 spinner:sm_inside:policy=forge_motor_widemac_tz_sat_v1,quat4,w=16,n=8,rotor=00b5,0000,0000,00b5,socket=sm_outside_a,config=fixed orb:sm_outside_a:policy=forge_motor_widemac_tz_sat_v1,quat4,w=16,n=8,pose=0100,0000,0000,0000,controller=sm_inside,fault=0 orb:sm_outside_b:policy=forge_motor_widemac_tz_sat_v1,quat4,w=16,n=8,pose=0100,0000,0000,0000,controller=sm_inside,fault=0 pulser:sm_bench:mode=periodic,p=1,phase=0,armed=0,done=0,nf=1 relay:sm_in:cur_out=1,next_out=1 wire:w__sm_bench__sm_in:cur=1,nxt=1 wire:w__sm_in__sm_inside:cur=0,nxt=1 admit:policy=admit_candidate_min_firstreceipt_v1,fact_capacity_fault=0,receipt_capacity_fault=0,capacity_fault=0
epoch 3 · sha256:28badb9f28ccaf044477972bcc99e3a6625a462963ff63f6c819a2b743bbf6ff
FILM v0.7 t=3 spinner:sm_inside:policy=forge_motor_widemac_tz_sat_v1,quat4,w=16,n=8,rotor=00b5,0000,0000,00b5,socket=sm_outside_a,config=fixed orb:sm_outside_a:policy=forge_motor_widemac_tz_sat_v1,quat4,w=16,n=8,pose=00b5,0000,0000,00b5,controller=sm_inside,fault=0 orb:sm_outside_b:policy=forge_motor_widemac_tz_sat_v1,quat4,w=16,n=8,pose=00b5,0000,0000,00b5,controller=sm_inside,fault=0 pulser:sm_bench:mode=periodic,p=1,phase=0,armed=0,done=0,nf=1 relay:sm_in:cur_out=1,next_out=1 wire:w__sm_bench__sm_in:cur=1,nxt=1 wire:w__sm_in__sm_inside:cur=1,nxt=1 admit:policy=admit_candidate_min_firstreceipt_v1,fact_capacity_fault=0,receipt_capacity_fault=0,capacity_fault=0
epoch 4 · sha256:12c22dc86f6477040d4d7a5dcad8e6b205f1610645eea1df83a4ae0b0df87a48
FILM v0.7 t=4 spinner:sm_inside:policy=forge_motor_widemac_tz_sat_v1,quat4,w=16,n=8,rotor=00b5,0000,0000,00b5,socket=sm_outside_a,config=fixed orb:sm_outside_a:policy=forge_motor_widemac_tz_sat_v1,quat4,w=16,n=8,pose=0000,0000,0000,00ff,controller=sm_inside,fault=0 orb:sm_outside_b:policy=forge_motor_widemac_tz_sat_v1,quat4,w=16,n=8,pose=0000,0000,0000,00ff,controller=sm_inside,fault=0 pulser:sm_bench:mode=periodic,p=1,phase=0,armed=0,done=0,nf=1 relay:sm_in:cur_out=1,next_out=1 wire:w__sm_bench__sm_in:cur=1,nxt=1 wire:w__sm_in__sm_inside:cur=1,nxt=1 admit:policy=admit_candidate_min_firstreceipt_v1,fact_capacity_fault=0,receipt_capacity_fault=0,capacity_fault=0
Composes with the 7 chapters before it
The chain through this chapter — every earlier fragment, this one, and the links — seals to sem-8dbfe20bce2ff725a57c66b692d488f5f051e2b9d8b607d9d4dff0945e4c7ccf: 24 objects, 23 edges (was 20 / 19; every earlier object and edge is still present — checked, or the build refuses).
Links only the chain carries
[rj_r] --sig--> [sm_in]
How to read this board
Five kinds of object, two kinds of wire, and one band per Part of the book. Signal flows left to right: it starts at a clock, travels through relays, and ends at a door — or turns a spinner, which drives an orb. Nothing below is the book's own vocabulary; each line is quoted from where the definition lives.
| shape | is | and so |
|---|---|---|
| a clock; the only source of signal | Every signal on the board starts at one of these. Nothing else can make one. | |
| a pass-through, so signal can travel | One arrives, any number leave — a relay that fans out is the board's router. | |
| a sink; signal arrives and stops | It latches what reached it and passes nothing on. A door is where a path ends. | |
| rotation: takes signal, drives a pose | The only object on the board that holds a value a claim can rewrite — and only if its config says configurable. | |
| the thing that gets moved | It is driven, never driving: an orb is what you watch to see whether anything happened. | |
| not a WRL role — the book's own drawing of the receipts in the epoch's Film | It counts what the run admitted, and turns red on a Rejected outcome. | |
| SignalWire | signal: a sig_out to a sig_in | Legal from a Pulser or Relay, into a Relay, Door or Spinner. This is how the board moves. |
| SocketControl | control: a socket to a pose | Legal only from a Spinner into an Orb. At most one may land on any input port — fan-in is a typed refusal. |
Hover any object for what it is, which chapter put it there, and every field of its line in that epoch's Film — split into what it is doing now and how it was built. Click to pin the readout, then click a wired name to follow the signal. The field definitions come from TRVM/forge/film.py (the emitter), TRVM/forge/forge_state.py (nf, derived from the decoded counter and never from t), TRVM/forge/lower_e2a.py (the commit/react law), TRVM/FORGE_SEMANTIC_IR_v1_MEASURE.md §1.3; the shapes from WRL/learn.html and WRL/docs/spec/README.md. The build refuses if a Film emits a field this key does not explain.
The board so far: one band per Part, signal flowing left to right; relays that fan out are routers, doors are switches, pulsers are clock domains. Hover an object — or click the board and walk it with the arrow keys — for its role, its Part and what it is wired to. This board is the chain’s sealed shape; no Film drives it, so it has no state to report, and the whole board in the conclusion is where every object’s state is read epoch by epoch. Wheel zooms · drag pans · double-click fits.
Syntax — quoted from the tree at build time
Where the tree says the naked law is too strong (frontier package X-1) invariant-r10/package-v2.8/v1-provenance/03_CANDIDATE_INVARIANTS.md:75
- **X‑1 "Any shared observable must carry every state variable that determines future behavior" as stated.** Too strong alone (Model 5 P2 variant): carrying byte‑level variables breaks convergence. Survives only as the ADEQUACY/EQUIVARIANCE pair. *Demoted to P1 and renamed to its literature name (sufficient statistic / Nerode quotient).*
Forces
Deciding what is behaviour-relevant requires a model of the futures, which is exactly what a subsystem author does not want to commit to. Equivariance — the relation under which two internal states count as the same — has to be stated and, ideally, checked. The membrane is a claim about a quotient, and quotients are where proofs get hard.
Applicability
Module and service boundaries, agent-to-agent interfaces, world serializations — anywhere two implementations must be interchangeable behind one boundary.
Transformations
- refactoring internals within an equivalence class
- widening the membrane when a new variable is shown to determine a future
- exposing a representative where a quotient was meant
- hiding a variable that determines a future (Invisible State)
A refusing transformation is not one that is discouraged: it is one that, applied, makes the invariant above false. The word is the tree's, and it is the same word the join uses.
Consequences
Composition stops depending on internals and starts depending on declared behaviour. The honest status: this is the book proposing a name for one half of a law the tree has already adjudicated; nothing in the tree witnesses the membrane by that name.
Failure mode it answers
Invisible State — Allowing state that affects future behaviour to remain outside the shared observable. Paid for at: TRVM/LAWS.md:80 (Law 6 witnesses: rotor, receipt, once-latch)
Witness
No witness. This pattern is PROPOSED — the tree has no check for its invariant.
Counterexample
No counterexample shipped (required only when WITNESSED).
What to take away
- from the animationExposing y determined the futures; exposing x too made equivalent subsystems look different.
- from the syntaxThe frontier package keeps the law only as an ADEQUACY / EQUIVARIANCE pair — this pattern is the second word.
- from the literatureParnas 1972: a module hides a design decision. The membrane hides what does not determine a future.
- from the witnessPROPOSED: no witness, no counterexample, and the label derives to say so.
Prior art — and what is not claimed
| work | relation | what it shares | where it differs |
|---|---|---|---|
| Parnas, information hiding (1972) | antecedent | a boundary chosen so that what crosses it is the only thing that matters | Parnas hides implementation decisions; a membrane is asked to hold under composition, not only under change |
Novelty not claimed. The phrase 'semantic membrane' appears nowhere in the tree. It is PROPOSED by the book and has no witness; if it turns out to be Parnas with a new coat, that is the expected outcome, not a surprise.
Relations with other patterns
Shared Observable WITNESSED