WallRiderLangWRL CORE 0.1.2 · FROZEN
LANGUAGE GUIDE

The whole language, in the order it was designed.

The tutorial teaches you to write a world. This guide explains what every part of the language means and why it is shaped that way — including the parts that are designed and frozen as families but not yet writable. Where a construct is not yet writable, it says so in the margin rather than pretending.

What WRL is

WallRiderLang is a spatial actor language. A program is not a sequence of statements; it is a graph of durable identities connected by textured routes and separated by boundaries. The name is literal. Riders are identities in motion along routes. Walls are the boundaries that gate, commit and seal what crosses them.

The reason for that shape is a single design goal: a run must be checkable by re-execution. Not merely logged. Executing a WRL world produces a film, an ordered schema-versioned record of what occurred, and that film is byte-identical regardless of which machine produced it or how the work was scheduled. Everything strange-looking about the language falls out of that requirement.

What a film does and does not establish. Given the same world, the same scenario and a conforming runtime, a film lets anyone re-run the world and compare bytes. That makes a claimed run reproducible, and it makes tampering with the record detectable. It is not a proof that the world is correct, that the observations fed into it were truthful, or that the runtime that produced it was honest — a film says "this is what this world does with these inputs", which is a smaller and much more defensible claim than "this is what happened in the world".
The architectural rule (frozen). WRL denotes the canonical Forge semantic graph. It is never lowered by compiling surface syntax directly to hand-written interaction-calculus text. The only sanctioned path is:
WRL source / canvas canonical semantic graph Forge Semantic IR v1 TRVM facts · films · reductions

Read that pipeline left to right and most of this guide's structure becomes predictable. Part I is the surface and its meaning families. Part II is the canonical graph and the machine that advances it. Part III is the subset you can type today.

Part I · The design

1 · The four reading laws

WRL is meant to be read before it is parsed. Four laws, frozen, govern every piece of notation in the language.

LawWhat it means
Shape says what a thing isBracket shape identifies the kind of object. You know what [x] is before you read x.
Line texture says how it movesRoute style identifies the operational guarantee — deterministic, asynchronous, verified, or fault.
The colon introduces; the slash boundsBoth families cap at three strokes, ordered by permanence: transient · committed · sealed.
Marks for architecture, words for computationProcess notation owns the punctuation. Expression notation defaults to words, so arithmetic never competes with topology for symbols.

The third law is the one that pays off later. :, ::, ::: and /, //, /// are not four unrelated sigils; they are two ladders of increasing permanence, and stroke count is the ordering.

2 · The ten construct kinds

Every WRL construct is exactly one of ten kinds. The set is closed — this is frozen, and a future revision may refine members but may not add an eleventh kind.

KindRoleStatus
Functioncalculates — pure local computationexperimental
Actorpersists — durable identity + owned statecore
Routecommunicates — a directed, textured transition relation or channelcore
Wallauthorizes — gate / commit / seal on propagationcore
Periodorders — the logical-time step under which events settlecore
Fragmentcarries code — a quoted graph as movable dataproposed
Stencilconstructs graphs — a parameterized fragment producerproposed
Derivetransforms typed graphsproposed
Filmproves what occurred — an append-only replayable logcore
Hashidentifies what was built — a content addresscore

The creed, which is how the ten are meant to be memorised:

Functions calculate. Actors persist. Routes communicate. Walls authorize. Periods order. Fragments carry code. Stencils construct graphs. Derives transform typed graphs. Films prove what occurred. Hashes identify what was built.

Six of the ten — Actor, Route, Wall, Period, Film, Hash — are grounded by a running implementation today. The other four are frozen as kinds; their detailed semantics are still draft.

A route is not the same thing as a structural edge. This is worth pinning down early, because the two are easy to conflate and the whole roadmap depends on the difference. A structural edge is what you declare with --sig-->: it is part of the semantic graph, it enters the sem- id, and it settles within the period. A route is the broader family — a directed, textured transition relation between identities. The solid texture -- happens to be realised as a structural edge, which is exactly why it is the only one you can write today. The async texture ~~ cannot be a structural edge: an async message does not settle within the period, so it needs a canonical logical route declaration distinct from the edge declaration. Reading "route" as "edge" makes that requirement look like an oversight rather than the consequence it is.

3 · Containers: [x], (x), {x}

Three container shapes, frozen, closed.

ShapeKindRule
[x]durable identityan actor, region, mailbox, or named artifact — something that survives across periods
(x)statea current cell, mutable by replacement, single-owner
{x}wiringpermitted topology, capabilities, ports — static structure, not current value

The distinction between ( ) and { } is not stylistic. ( ) is what the object is right now; { } is what the object is permitted to be connected to, ever. Configuration lives in parens because it is state that was chosen at construction; ports live in braces because they are structure. In the world surface you write today, both appear on a declaration line and the parser treats them under exactly these rules.

4 · Identity and addressing

SymbolMeaning-roleStatus
#canonical identity / content hashcore
@address / placement / stampcore
?pattern variable introduced by matchingcore
*replication-by-positionimplemented
*wildcard matchreserved
The frozen invariant. Executable identity is a hash. Human aliases are words, and they are never semantic. If two worlds differ only in what you called things, they are two different worlds — but if two worlds differ only in the order you declared identical things, they are the same world.

* is the one symbol whose two meanings are at very different maturities, and the spec is explicit about not letting that slide. Replication-by-position ([relay:r*3]) is implemented as bounded, identity-equivalent surface sugar — see §18. Wildcard matching is reserved: no lowering for it exists.

5 · Routes and the four textures

The reduction relation is defined over exactly four irreducible route textures. All surface sugar canonicalizes down to one of them plus attributes. Reading a WRL diagram, the texture of the line tells you the operational guarantee without reading a single word.

TextureGuaranteeSurface status
--x--> soliddeterministic local transition; settles within the periodsurface-grounded
~~x~~> asyncasynchronous message; appended to a mailbox; observable next periodpartial
==x==> verifiedevidence-backed / committed transition under a named policypartial
!!x!!> faultcrash / cancel / reject / interrupt; engages supervisionpartial

The set of four and their guarantee-roles are frozen. Label, payload and guard grammar, the sugar table, and branch/lane rules are not.

Only -- is surface-grounded today. Freezing a texture's meaning-role is not the same as grounding its construct. You can declare, emit and round-trip a solid route right now. You cannot write ~~, == or !! in a world document — the machinery beneath them exists in varying degrees, but the surface forms do not. See §22 for what each one still needs.

Why async cannot simply be another edge

This is the single most instructive constraint in the language. An async route does not settle within the period. A solid route participates in the within-period reaction cascade and reaches a fixpoint before the period commits; an async message is observable next period by construction. Those are different objects in the canonical graph, and so promoting ~~ requires a canonical logical route declaration that is distinct from the structural edge declaration — not a new edge kind. Adding it as an edge kind would silently claim async messages join the fixpoint, which is false.

The mailbox is the worked example of the distinction the language is careful about. A mailbox declaration exists in the canonical IR, the runtime honours it, and a battery covers it. It is IR/runtime-grounded. There is no ~~ surface form to write and the formatter cannot emit one, so it is not surface-grounded, and it is therefore not a sixth writable role.

TermMeans
IR/runtime-groundeda canonical IR declaration exists, the runtime executes it, and a battery covers it
surface-groundedadditionally: WRL source can declare it, the formatter can emit it, and it round-trips through the canonical bytes

A construct is eligible for promotion into a frozen Core family only when it is surface-grounded. IR grounding alone is necessary and not sufficient.

6 · Walls: gate, commit, seal

Walls are the boundaries a rider crosses, and the slash ladder orders them by permanence.

BoundaryReduction effectStatus
/gaterequire a capability; emit an effect-request node — no ambient I/Oreserved
//commitcanonicalize the fragment so far; assign a content id; freeze itgrounded
///sealcommit, then register the artifact under a content hashpartial

The frozen part is the three-tier ordering and one rule with teeth: effects cross named walls only. There is no ambient authority anywhere in the language — a computation that wants to touch the outside world must emit an effect-request that crosses a declared boundary, which is what makes the film complete rather than merely detailed.

7 · Periods and superdense time

Wall-clock is never replayable state; logical time is. If your world reads a clock, that reading becomes an input fact that the film carries, so the replay observes the same value the live run did. A world that could reach out and ask the host what time it is would not be replayable, so it cannot.

Period, epoch, microstep

Three words for time appear across this site and they are not synonyms. Because once at 3 is spelled with an epoch while the cycle is described in periods, it is worth saying plainly which is which.

WordWhat it countsWhere you meet it
periodone full turn of the six-phase cycle — the settle-and-commit unitthe execution model: §8, the phase table
epochthe index of a period within a particular runrun inputs and clocks: once at 3, [epoch:3], periods 7
microstepordering within one period, during the REACT cascadesuperdense pairs (period t, microstep m)

So a period is a kind of step and an epoch is a number naming one. "Run this world for 7 periods" and "run it for epochs 0…6" describe the same run.

Two counters start in different places, and the difference is not arbitrary. Epochs of a run are numbered from 0: epoch 0 is the first turn of the cycle, before any external claim has been admitted, which is why a world with no scenario at all still has one. Claim batches, however, are addressed from 1[epoch:1] is the earliest epoch at which you may inject a claim. The gap is epoch 0 itself: it is reserved for the world settling from its declared initial configuration, so that "what this world does on its own" and "what this world does when something is done to it" are never mixed into the same frame.

8 · The five memory kinds

ShapeMemory kindLifetime rule
(state)volatile cellmutable by replacement; single-owner
{facts}monotonic knowledgegrow-only; merges by lattice union; never retracts
[archive]durable storepersistent addressable actor; survives restart
:: fragment //code memoryquoted graph as portable data
#hashsealed identityimmutable, content-addressed
No shared mutable cell. This is the frozen invariant that does the most work in the whole language. Shared knowledge is {facts}, merged by monotone union. Shared identity is [archive]. There is no third option. That single-owner discipline is what makes execution deterministic without a runtime conflict resolver — the resolver is not fast, it is absent.
Part II · The machine

9 · The period cycle

Every period advances the whole world through exactly six phases, in this order. This is frozen.

OBSERVEACCEPTMAP COMMITREACTFILM
PhaseWhat happens
OBSERVEcanonicalize incoming claims and insert the distinct ones
ACCEPTcreate missing receipts according to the pinned acceptance policy
MAPturn newly-accepted successful operations into controls
COMMITapply control writes and fault resets to owned cells
REACTrun the deterministic within-period token cascade to fixpoint; latch any current overflow
FILMrecord exactly the entries needed to replay this period
The first three phases never disappear. A world with no claims makes OBSERVE, ACCEPT and MAP degenerate to identity — but they remain in the semantic model. That distinction is what determines which claims were seen, which candidate was accepted, whether a retransmission retries an effect, which controls were committed, and whether a same-period configuration change affects that period's reaction. Collapse them and every one of those questions becomes unanswerable.

Notice the ordering of COMMIT before REACT. Configuration writes land first, then the cascade runs against the world those writes produced. A spinner reconfigured this period is reconfigured for this period's reaction, not the next one. That is a decision, not an accident, and it is why the phase list is ordered rather than merely enumerated.

10 · Two invariants, and what conflicts remain

Two invariants are enforced statically, before anything runs:

  1. Single-owner cells. No shared mutable cell exists anywhere.
  2. Disjoint deterministic guards. At most one deterministic rule is enabled per actor-state. Genuine choice must be written as an explicit scored branch, so a nondeterministic decision is always visible in the source.

Conflicts are narrowed, not dissolved

It is tempting to claim that single ownership makes conflict impossible. It does not, and the spec says so explicitly. Ownership removes generic write-write races; append and fact-union structures merge deterministically. But a real distributed world still faces conflicts that ownership cannot touch, and each of those is resolved by an explicit, policy-pinned law:

QuestionPinned law
Recognition — did we see this claim before?distinct-CandidateKey count
Acceptance — which candidate wins?MIN CandidateKey / first receipt
Application — in what order do accepted events apply?canonical event order
Fault — reset vs. new overflow in the same periodCOMMIT clears, then REACT ORs
Capacity — partial failureatomic latch; there is no partial
Canonical ordering is policy-pinned, not a fixed formula. Events and accepted operations are ordered by a total canonical key whose schema and policy identity are part of the semantic artifact. Worker arrival order is never semantic. What is frozen is that such a key exists and is pinned by policy; the specific formula belongs to the profile and may differ between profiles.

11 · What a run leaves behind

"Film" is not one undifferentiated object. Three artifacts are frozen distinct:

ArtifactRole
WorldFrameauthoritative observable state, sufficient for future behaviour — the physical snapshot
EventLedgeraccepted events, receipts, effects, outcomes — the claim-aware layer
BuildFilmcompiler and build provenance proposed

A replay package is frozen in this shape:

ReplayBundle {
  initial_artifact,
  initial_state,
  event_ledger,
  frames,
  policy_ids
}

The byte layouts are a backend concern and are not frozen. The three-way distinction and the bundle shape are.

12 · Canonicalization and content identity

Meaning is normalized before it is addressed. Three rules follow:

Concretely, the compiler's first job is to produce a canonical graph: declarations sorted identity-first, edges sorted, configuration normalized to its typed form, empty port groups omitted rather than emitted as empty. That canonical graph is serialized to JSON with sorted keys and no incidental whitespace, and hashed with SHA-256. The result is the SemanticArtifactID.

For the starter world shown at the top of this guide, that value is:

SemanticArtifactID  sem-67e954cfe3115166b49388366df3f062a46572ba2baf53380f1520f4050b60ae

The playground computes exactly that value in your browser, from a faithful port of the same canonicalizer — which is why you can watch an edit move the id, or fail to.

Two worlds are used throughout this site, and it is worth keeping them apart. The starter world above — one pulser, one relay, one spinner, one orb — is the teaching example, and the world the tutorial builds. The pinned conformance fixture is a larger six-object world carrying a second pulser and a door; it is what the toolchain's test batteries assert against, so its id is frozen across every implementation:

the pinned fixture  sem-8ae91fe9cbc5fd086ce4356d587c403211e5c7b2b3ebdd316496367429ecfe4a

Both are loadable from the playground's example buttons, and both are asserted by test/conformance.mjs on every change.

13 · The identity ladder

Six content-addressed prefixes, each naming a different question. They are deliberately distinct: conflating any two of them would let a change to one thing silently invalidate another.

PrefixNamesMoves when…
sem-SemanticArtifactID — the world's meaningthe canonical graph changes
bknd-BackendArtifactID — meaning + lowering profilethe semantic id moves, or the lowering profile does
scen-ScenarioDigest — the run inputsperiods or claims change
replay-ReplayBundleID — a specific run of a specific worldeither of the two above moves
bundle-ForgeBundleID — a self-contained exported projectthe exported bytes change
env-an evaluation environmentits splits change
The split that matters most. A world and a run of that world have separate identities. Two backends can lower the same sem- to two different bknd- values and still produce byte-identical films — which is the whole point of having a semantic layer at all.
Part III · The surface you can write today

14 · The world document

A world document is one profile line, then declarations, then edges. Comments start with ; and run to end of line.

; every world names the profile it conforms to
profile forge.world.core.v1

; declarations: [role:id](config){ports}
[pulser:p0](every 2){sig_out}
[relay:r0]{sig_in, sig_out}
[spinner:sp](w=16, n=8, rotor=quarter_turn_z, configurable){sig_in, socket}
[orb:ob]{pose}

; edges: [src] --kind--> [dst]
[p0] --sig--> [r0]
[r0] --sig--> [sp]
[sp] --socket--> [ob]

That is the entire grammar of the current core surface. There is one profile, five roles, two edge kinds, one configuration group per role, and one port group per declaration. The restraint is deliberate: every construct in that list is surface-grounded, meaning it round-trips through the canonical bytes and its identity behaviour is covered by a battery.

# is not a comment. In the core surface the comment marker is ; only. # belongs to the identity family and is preserved. Writing # note where you meant a comment is a parse error, not a silently-ignored line.

15 · The five roles

RoleDoesPorts (out / in)Config
pulseremits a signal on a clocksig_out / —a clock
relayforwards a signalsig_out / sig_innone
doorconsumes a signal— / sig_innone
spinnerholds a rotor; drives a socketsocket / sig_inw, n, rotor, configurable
orbcarries a pose— / posenone

A role's ports are derived from the registry, not from what you type. The {…} group on a declaration is checked against the frozen signature for that role: name the wrong ports, or name a subset, and you get WRL_PORT_SIGNATURE. The braces are an assertion about structure, not a definition of it.

In the canonical artifact, empty port groups are omitted entirely. A door carries {"in":["sig_in"]} with no "out" key at all — not an empty array. This is the kind of detail that a re-implementation gets wrong and a content hash catches immediately.

Clocks

You writeCanonical formMeaning
every 2["periodic", 2, 0]fires every 2 periods, no phase offset
every 3, phase 1["periodic", 3, 1]fires every 3 periods, offset by 1
once at 1["once", 1]fires exactly once, at period 1

16 · Edges, ports and wiring

Two edge kinds exist. Each one is a fixed pair of ports, and the pair is what makes the edge legal or illegal.

You writeCanonical kindSource portDestination port
--sig-->SignalWiresig_outsig_in
--socket-->SocketControlsocketpose

Validation is therefore purely mechanical. An edge is legal when the source role owns the source port and the destination role owns the destination port. Wire a pulser into a pulser and the destination has no sig_in, so you get WRL_ILLEGAL_PORT_PAIR. Wire a spinner's socket into a relay and the relay has no pose, same error.

One controller per input port. Two edges landing on the same input port is WRL_CONTROLLER_CONFLICT. This is the single-owner invariant from §8 showing up as a topology rule: an input port is an owned cell, and owned cells have exactly one writer. Fan-out is fine and common; fan-in is a structural error.

Where the error is caught

A useful mental model, because it explains error messages that otherwise look misplaced: an operation enforces only its own precondition; the seal judges structural legality. Removing an object does not cascade to its edges, because removal's precondition is only that the object exists. The dangling edge it leaves behind is caught when the world is sealed, as WRL_UNKNOWN_ENDPOINT. An honest delete is therefore two operations — unwire, then remove — and the design prefers making you say that to silently doing more than you asked.

17 · Numbers

There is no floating point anywhere in WRL. Not in rotors, not in poses, not in configuration. A float's result depends on evaluation order and hardware, and a language whose entire premise is byte-identical films cannot contain one.

A spinner's rotor is four integer quaternion lanes in a fixed-point Q-format that the spinner itself declares:

FieldMeans
wtotal bit width of a lane
nnumber of fractional bits; the unit value is 1 << n
rotorfour integer lanes, written a.b.c.d, or a named rotor
configurablewhether the rotor may be rewritten at run time

So at n=8 the unit is 256 and the identity rotor is 256.0.0.0. A quarter turn about z needs u/√2 in two lanes, which is not an integer — so the language does not compute it in floating point and round. It computes the exactly rounded integer with integer arithmetic only:

; round(u / sqrt2) with integers only
u       = 1 << n
two_uu  = 2 * u * u
q0      = isqrt(two_uu) / 2
result  = q0 + 1  if  two_uu > 4*q0*q0 + 4*q0 + 1  else  q0
nunitquarter-turn lane
41611
8256181
166553646341

Those values are reproducible on any host with integer arithmetic, which is exactly the requirement. Named rotors that involve rounding carry a provenance policy id recording how they were rounded — provenance only; it never enters the artifact bytes.

18 · Sugar

Sugar is a source-to-source pre-pass that runs in front of the untouched canonical parser. It is not a second compiler, and it has no path to the seal of its own.

SugaredExpands toKind
every 2mode=periodic, period=2, phase=0value
once at 1mode=once, epoch=1value
rotor=quarter_turn_zrotor=181.0.0.181 at n=8value
[relay:r*3]r0, r1, r2structural
[p0] --sig--> {r0, r1}two separate edgesstructural
The law is: no sugar-specific identity. A sugared spelling and its explicit twin desugar to the same canonical bytes and therefore seal to the same sem- id. Sugar introduces no identity of its own and no privileged path to the seal.
That is not the claim that editing sugar cannot move an id. sp*3sp*4 is a different program and moves the identity, exactly as the explicit spelling would. The looser phrasing is false and the spec is careful to say so.

Two properties are required of any sugar, and both are gated by battery:

  1. Bounded expansion. A one-to-many form must reject an absurd count with a typed diagnostic before allocating the expansion. sp*1000000000 is a diagnostic, not an out-of-memory event. Replication and fan-out are bounded at 1024, total expansion at 65536 lines, and a count may not exceed 9 digits.
  2. Original-source mapping. An expansion must preserve the authored spans, so diagnostics, completion, semantic diff and editor operations all refer to what you wrote rather than to generated text.

Generated names are judged by the ordinary seal. A collision between a generated name and an explicit one is a normal WRL_DUPLICATE_ID, not a special sugar rule.

Status: implemented, battery green, identity-equivalent — not closure-proven, not frozen.

19 · Worlds versus runs

A world and a run of that world are different documents. This is normative.

DocumentCarriesEnters sem-?
World documentprofile, objects, edges, static config, wiringyes
ScenarioV1periods, [epoch:N] claims, run inputsno

Three consequences are frozen:

  1. Run inputs are not world content. Changing how long you run a world, or what claims you feed it, does not move the SemanticArtifactID. One world, many scenarios.
  2. A world formatter emits a world document — and must exclude scenario syntax both semantically (reparsing yields no run inputs) and lexically (the emitted text does not contain scenario syntax at all). The lexical half is load-bearing: a formatter emitting a literal periods 0 would satisfy the semantic half while still writing scenario syntax into a world document.
  3. Round-trip laws split in two. The world round-trip preserves the complete canonical world projection; the identity round-trip preserves the canonical bytes and the sem- id. Neither subsumes the other.
The world projection is defined by exclusion — every canonical field except the run inputs — and never as a fixed tuple such as (profile, nodes, edges). A fixed tuple silently stops covering any field a later slice adds.

The two parser mouths

Entry pointAcceptsStatus
parse_wrl_core(text)world source only; rejects run inputs with a typed WRL_WORLD_SOURCE_HAS_SCENARIOnormative
parse_wrl_legacy_document(text)a pre-boundary combined documentexplicit compatibility path

Parameterizing the parser is sanctioned only as a migration bridge, and only through an unmistakable API — never a boolean flag on one function. The legacy path's destination is to split a combined document into a world plus a scenario, not to keep parsing it forever.

20 · Diagnostics

Every rejection is a typed code, never a raw exception and never a free-text string. A tool downstream can branch on the code; a human reads the detail. The full catalogue lives in the reference; the ones you will meet first:

CodeMeans
WRL_DUPLICATE_IDa second object claims an id already declared
WRL_UNKNOWN_ENDPOINTan edge names an object that was never declared
WRL_ILLEGAL_PORT_PAIRan edge asks for a port the role does not have
WRL_CONTROLLER_CONFLICTtwo controllers reach the same input port
WRL_PORT_SIGNATUREa {ports} group does not match the frozen signature
WRL_WORLD_SOURCE_HAS_SCENARIOrun inputs appeared in world source
WRL_SUGAR_MALFORMEDa sugared spelling could not be expanded
WRL_UNSUPPORTED_FEATUREthe construct is outside frozen Semantic IR v1

Two disciplines make these worth relying on. First, a rejected draft stays editable — an invalid candidate never commits, but it also never destroys what you were editing. Second, a failure to parse leaves the previous sealed world runnable. You cannot break a working world by typing badly into an editor.

Part IV · Status

21 · Conformance families

These observable properties are frozen as families of guarantee. Their exact test matrices remain draft.

FamilyGuarantee
Formatting invariancepresentation never changes the hash
Replay exactnessa live run and its replay share all observables
Build invariancesame inputs → identical film and hashes across hosts
Merge lawsfact union is commutative, associative, idempotent
Boundary safetyundeclared effects cannot cross walls
Scheduler invarianceworker ordering never changes the committed film
World round-tripa format→parse cycle preserves the complete canonical world projection
Identity round-tripa format→parse cycle preserves the canonical bytes and the sem- id
Document separationa world document excludes run inputs both semantically and lexically

The determinism property, stated precisely:

Given the same initial configuration and the same sequence of external observations — the signed facts crossing effect walls — the committed film is byte-identical across any hardware scheduling.

22 · The road to Core 0.2

The promotion order below is steered, not merely preferred. Each step supplies something the next one needs, so reordering them produces constructs that cannot be grounded honestly.

#StepGate it must pass
1L-0 closureround-trip and document-boundary laws restated and green — complete
2~~ async routeneeds a canonical logical route declaration distinct from the structural edge declaration
3== verified routesee below — it is not almost free
4# references and & composition
5//commit and ///seal
6!! fault routemay only follow a minimal supervision floor actually existing
7/gate capability gatelast

== is not "almost free"

It is tempting to read the verified route as nearly grounded, because the acceptance core already accepts claims. That confuses two different things: the declaration == would introduce is authorization structure, while the frozen texture == denotes an evidence-backed transition.

== is grounded only when acceptance enforces all four of: the claimant, the target, the operation family, and a named policy. Anything less is a route that looks verified and is not.

The layering that comes with it is approved: the world document declares a verified channel and its schema; the scenario carries the claim instances; receipts prove acceptance through that channel. One explicit constraint attaches — a principal-shaped role such as [worker:w1] must not be introduced as part of that work. How principals exist in the role system is a separate question requiring its own sanction, and smuggling one in would freeze a role-system decision nobody ruled on.