Every table, in one place.
This page is the lookup surface for WRL Core 0.1.2 — the exact vocabularies, signatures, bounds, codes and pinned ids that the canonicalizer enforces. Prose lives in the guide; the normative text lives in the spec.
Grammar
The complete core world surface. Whitespace outside tokens is insignificant.
Comments start with ; and run to end of line.
document ::= profile-line ( declaration | edge | comment | blank )*
profile-line ::= "profile" WS profile-id
declaration ::= "[" role ":" id "]" [ config ] [ ports ]
edge ::= "[" [ role ":" ] id "]" "--" edge-tag "-->" "[" [ role ":" ] id "]"
config ::= "(" [ config-item ( "," config-item )* ] ")"
ports ::= "{" [ port ( "," port )* ] "}"
config-item ::= key "=" value | clock-sugar | "configurable"
role ::= "pulser" | "relay" | "door" | "spinner" | "orb"
edge-tag ::= "sig" | "socket"
id ::= WORD ; [A-Za-z0-9_]+, and MUST NOT contain "__"
comment ::= ";" ANY*
# is not a comment marker.
In the core surface the only comment marker is ;.
# belongs to the identity family and is preserved by
the parser rather than discarded.[A-Za-z0-9_]+ is still rejected if it contains
__ — [relay:a__b] fails
with WRL_UNSUPPORTED_FEATURE. The sequence is
reserved for compiler-generated names, so that a lowered identifier can never
collide with one you wrote.{ports} group naming the same port twice is a typed
rejection (WRL_PORT_SIGNATURE), and a
(config) group setting the same key twice is
WRL_DUPLICATE_CONFIG_KEY. Neither is last-one-wins,
because a repeated key is far more often a mistake than an intention, and
silently keeping one of them would make the id depend on which.Line regexes, as implemented
| Line | Pattern |
|---|---|
| declaration | ^\[(\w+):(\w+)\]\s*(\([^)]*\))?\s*(\{[^}]*\})?$ |
| edge | ^\[(?:\w+:)?(\w+)\]\s*--(\w+)-->\s*\[(?:\w+:)?(\w+)\]$ |
| epoch claim scenario only | ^\[epoch:(\d+)\]\s*(.*)$ |
The role prefix is optional on an edge endpoint and, when present, is
not part of the identity — [relay:r0] and
[r0] refer to the same object on an edge line, and
seal identically.
[door:r0]
when r0 was declared a relay is
WRL_ROLE_PREFIX_MISMATCH, not a shrug. The prefix
never affects the id; it exists so that a reader can see the shape of an edge
without scrolling, and it would be worth nothing if it could lie.profile <id>
— comments and blank lines may precede it, nothing else may. Omitting it is
WRL_MISSING_PROFILE, repeating it is
WRL_DUPLICATE_PROFILE, and writing it with trailing
tokens or no id at all is WRL_MALFORMED_PROFILE.
A profile-only document is legal: it is the empty world, and it seals.Role registry
| Surface token | Canonical role | State schema ref | Surface status |
|---|---|---|---|
pulser | Pulser | state.pulser.v1 | grounded |
relay | Relay | state.relay.v1 | grounded |
door | Door | state.door.v1 | grounded |
spinner | Spinner | state.spinner.v1 | grounded |
orb | Orb | state.orb.v1 | grounded |
| — none — | Mailbox | state.mailbox.v1 | IR-only |
The state schema reference is derived, never written:
state.<role lowercased>.v1.
Port signatures
Frozen per role. The {…} group on a declaration is
checked against this table, not defined by it.
| Role | out | in |
|---|---|---|
Pulser | sig_out | — |
Relay | sig_out | sig_in |
Door | — | sig_in |
Spinner | socket | sig_in |
Orb | — | pose |
Mailbox | — | — |
{"in":["sig_in"]} with
no "out" key. Emitting
"out":[] produces different bytes and therefore a
different sem- id.Edge kinds
| Surface tag | Canonical kind | Source port | Destination port |
|---|---|---|---|
--sig--> | SignalWire | sig_out | sig_in |
--socket--> | SocketControl | socket | pose |
Legal source roles and destination roles fall out of the port table:
| Kind | Legal sources | Legal destinations |
|---|---|---|
SignalWire | Pulser, Relay | Relay, Door, Spinner |
SocketControl | Spinner | Orb |
WRL_CONTROLLER_CONFLICT.Configuration schema
static_config is
construction-time, not run-time. Everything in this section is read once,
when the world is built, and is part of the
SemanticArtifactID. It seeds runtime cells —
a Spinner's declared rotor is the initial value of
the cell the runtime later writes — but it is not those cells, and it does not
track them. The name is exact: the configuration is static because a running
world never writes back into its own document. Runtime values live in state
(addressed by state_schema_ref, whose contents are
outside the document) and are observable in the film; the two are related only
at period zero, by seeding.| Role | Surface keys | Canonical static_config keys |
|---|---|---|
Pulser | mode, period, phase, epoch | clock |
Relay | — | — |
Door | — | — |
Spinner | w, n, rotor, configurable | w, n, rotor, configurable |
Orb | — | — |
Mailbox IR-only | — | w, cap |
The Pulser is the one role whose surface keys and canonical keys differ: four
surface fields collapse into a single typed clock
tuple.
Spinner fields
| Field | Type | Meaning |
|---|---|---|
w | integer | total bit width of one rotor lane |
n | integer, 0 ≤ n ≤ w | fractional bits; unit = 1 << n |
rotor | exactly 4 integers, each 0 ≤ lane < 1<<w | quaternion lanes, written a.b.c.d or a name |
configurable | boolean | whether the rotor may be rewritten at run time |
n is
≤, not <. The
validator accepts n = w, and this table said
n < w until it was checked against the frozen
implementation. The looser bound is worth understanding rather than tightening:
at n = w the geometry is still well-formed, but the
unit 1 << n equals
2w and so falls outside the legal lane
range — every lane is representable, and the value one is not. Such a
world seals fine and is arithmetically degenerate. If you want a rotor of unit
magnitude you need n < w; the validator enforces
well-formedness, not usefulness.Rotor lanes are written with dots in the core surface
(181.0.0.181). Because the dot is the lane
separator, a rotor cannot carry a decimal fraction —
rotor=181.5.0.0 is the four-lane rotor
(181, 5, 0, 0), not a fractional value. The bootstrap surface used
commas; that spelling is a legacy path.
Clock vocabulary
| Sugar | Explicit surface | Canonical clock |
|---|---|---|
every K | mode=periodic, period=K, phase=0 | ["periodic", K, 0] |
every K, phase P | mode=periodic, period=K, phase=P | ["periodic", K, P] |
once at E | mode=once, epoch=E | ["once", E] |
A clock outside its legal range is
WRL_CLOCK_RANGE: period
must be at least 1, phase must be less than
period, and epoch must be
non-negative.
Rotor vocabulary
Named rotors split into two classes, and the distinction is recorded in build provenance.
| Name | Lanes at fractional width n | Class |
|---|---|---|
identity | [u, 0, 0, 0] | exact |
reverse_x | [0, u, 0, 0] | exact |
reverse_y | [0, 0, u, 0] | exact |
reverse_z | [0, 0, 0, u] | exact |
quarter_turn_z | [q, 0, 0, q] where q = round(u/√2) | rounded |
where u = 1 << n. Any other name is
WRL_UNSUPPORTED_FEATURE.
The exact-integer projection
No floating point is used anywhere. round(u/√2) is
computed with integer arithmetic only:
u = 1 << n
two_uu = 2 * u * u
q0 = isqrt(two_uu) / 2
q = q0 + 1 when two_uu > 4*q0*q0 + 4*q0 + 1
= q0 otherwise
n | unit u | q |
|---|---|---|
| 4 | 16 | 11 |
| 8 | 256 | 181 |
| 16 | 65536 | 46341 |
A rounded named rotor carries the provenance policy
forge_named_rotor_rne_sym_v1. Exact named rotors carry
none. Provenance never enters the artifact bytes — it records how a value
was produced, not what the value is.
Sugar forms and bounds
Sugar version sugar.v2. A source-to-source pre-pass
in front of the untouched canonical parser.
| Form | Kind | Expands to |
|---|---|---|
every K / once at E | value | explicit mode=… fields |
rotor=<name> | value | four explicit integer lanes |
[role:base*K] | structural | base0 … base(K-1), zero-based |
base*K in an edge endpoint | structural | positional pairing across both sides |
[src] --tag--> {a, b, c} | structural | one edge per listed destination |
| Bound | Value | Violation |
|---|---|---|
| replication base index | 0 | — |
| replication count max | 1024 | WRL_NUMERIC_RANGE |
| fan-out count max | 1024 | WRL_NUMERIC_RANGE |
| total expansion max | 65536 lines | WRL_NUMERIC_RANGE |
| count literal digits max | 9 | WRL_NUMERIC_RANGE |
Three decisions worth knowing: replication members are zero-based; replicated edges pair positionally and require equal counts on both sides; an inline comment on a replicated line attaches to the first emitted line.
sem- id. That is not the claim that
editing sugar cannot move an id — sp*3 →
sp*4 is a different program and moves it.Canonical artifact
The canonicalizer produces this record, serializes it as JSON with
sorted keys and separators "," /
":" and no whitespace, then takes SHA-256 of the
UTF-8 bytes.
{
"ir_version": "1.0",
"profile_id": "forge.world.core.v1",
"objects": [
{ "object_id", "role", "ports", "state_schema_ref", "static_config" }, …
],
"edges": [ { "src", "dst", "kind" }, … ],
"schemas": {
"runtime_state_schema": "RuntimeStateV1",
"epoch_input_schema": "EpochInputV1",
"observable_schema": "EpochResultV1"
},
"semantic_policies": {
"rulepack_id": "forge.world.core.rules.v1",
"admit_policy_id": "admit_candidate_min_firstreceipt_v1",
"film_schema_id": "film.v0.7",
"numeric_policy_ids": ["POLICY_FORGE"]
}
}
Canonical ordering
| Collection | Sort key |
|---|---|
| objects | identity-first: (object_id, role) |
| edges | natural tuple order over (src, kind, dst) |
| JSON keys | lexicographic, at every depth |
Because objects sort identity-first, the order you declare things in is
inert: shuffling declaration lines cannot move the
sem- id.
Pinned policy ids
| Constant | Value |
|---|---|
| IR version | 1.0 (mailbox profile: 1.1) |
| Profile | forge.world.core.v1 |
| Rulepack | forge.world.core.rules.v1 |
| Admit policy | admit_candidate_min_firstreceipt_v1 |
| Admit policy (mailbox) | admit_mailbox_deliver_all_v1 |
| Film schema | film.v0.7 (mailbox: film.v0.7.mailbox.v1) |
| Numeric policies | ["POLICY_FORGE"] |
| Sugar version | sugar.v2 |
| Named-rotor rounding policy | forge_named_rotor_rne_sym_v1 |
| Mailbox width max | 32 |
WRL_UNSEALED_POLICY). Policies are part of the
semantic artifact; an unset one would let two genuinely different worlds hash to
the same value.Identity ladder
| Prefix | Names | Hash of |
|---|---|---|
sem- | SemanticArtifactID | canonical IR + semantic policies |
bknd- | BackendArtifactID | the semantic id + the lowering profile |
scen- | ScenarioDigest | the digest domain of the run inputs |
replay- | ReplayBundleID | world + scenario together |
bundle- | ForgeBundleID | a self-contained exported project's canonical bytes |
env- | evaluation environment | its splits, canonicalized as sorted sets |
Every id is <prefix>-<64 lowercase hex>,
SHA-256 over the canonical bytes of the thing named. Nothing else may occupy
those namespaces.
The two sem- values used across this site — both
asserted by test/conformance.mjs, so a build that
disagrees with either is a failing build:
| World | SemanticArtifactID |
|---|---|
| the starter world pulser, relay, spinner, orb — the teaching example |
sem-67e954cfe3115166b49388366df3f062a46572ba2baf53380f1520f4050b60ae |
| the pinned conformance fixture six objects; what the test batteries assert against |
sem-8ae91fe9cbc5fd086ce4356d587c403211e5c7b2b3ebdd316496367429ecfe4a |
What moves an id, and what does not
| Change | sem- |
|---|---|
| comments, blank lines, indentation, alignment | inert |
| declaration order | inert |
| edge order | inert |
| sugared vs. explicit spelling of the same value | inert |
| presentation: x/y position, colour, curve | inert |
periods or [epoch:N] claims | inert — they are run inputs |
| renaming an object | moves |
| adding or removing an object or edge | moves |
| reconnecting an edge | moves |
| any rotor, clock or width value | moves |
| the profile or any pinned policy id | moves |
Diagnostic codes
Every rejection is one of these typed codes. Downstream tools branch on the code; the detail string is for humans.
This is the full Forge toolchain catalog, not the list a single stage
emits. The Browser column says whether
the playground can raise the code at all: the
browser spine stops at the seal, so codes belonging to backend lowering or to
sealed-record round-tripping are listed for completeness and will never appear
there. The subset is available programmatically as
W.BROWSER_CODE_IDS, and
test/conformance.mjs checks that every code in it
has a description and that the two lists have not drifted apart.
| Code | Means | Browser |
|---|---|---|
WRL_DUPLICATE_ID | a second object claims an id already declared | yes |
WRL_UNKNOWN_ENDPOINT | an edge names an object that was never declared | yes |
WRL_ILLEGAL_PORT_PAIR | an edge asks for a port the role does not have | yes |
WRL_CONTROLLER_CONFLICT | two controllers reach the same input port | yes |
WRL_CLOCK_RANGE | a pulser clock is outside its legal range | yes |
WRL_NUMERIC_RANGE | a numeric field is outside its legal range, or is not a complete integer literal | yes |
WRL_EPOCH_RANGE | an epoch index is outside the declared run | yes |
WRL_UNSUPPORTED_FEATURE | the construct is outside frozen Semantic IR v1 | yes |
WRL_MALFORMED_ARTIFACT | the artifact record has the wrong shape | yes |
WRL_PORT_SIGNATURE | a {ports} group does not match the frozen signature, or repeats a port | yes |
WRL_WORLD_SOURCE_HAS_SCENARIO | run inputs appeared in world source | yes |
WRL_SUGAR_MALFORMED | a sugared spelling could not be expanded | yes |
WRL_MISSING_PROFILE | world source did not open with a profile line | yes |
WRL_DUPLICATE_PROFILE | world source declares the profile more than once | yes |
WRL_MALFORMED_PROFILE | the profile line is not exactly profile <id> | yes |
WRL_UNKNOWN_CONFIG_KEY | a declaration carries a key the role does not define | yes |
WRL_DUPLICATE_CONFIG_KEY | a declaration sets the same key twice | yes |
WRL_ROLE_PREFIX_MISMATCH | an edge asserts a role the object does not have | yes |
WRL_UNSEALED_POLICY | a semantic policy id is null or empty | no — sealing wrapper |
WRL_BAD_LOWERING_PROFILE | a backend lowering profile is half-specified | no — backend lowering |
WRL_SEALED_IMMUTABLE | something tried to write to a sealed object | no — sealed records |
WRL_UNKNOWN_ARTIFACT_FIELD | a sealed record carries an unknown field | no — sealed records |
A diagnostic carries a code, a human detail, and — where the failure is lexical — a line number in the authored source, mapped back through any sugar expansion so it refers to what you wrote rather than to generated text. When the fault lies inside an expansion, the diagnostic also reports which member of the expansion it was.
Parser entry points
| Entry point | Accepts | Status |
|---|---|---|
parse_wrl_core(text) | world source only; rejects run inputs with WRL_WORLD_SOURCE_HAS_SCENARIO | normative |
parse_wrl_legacy_document(text) | a pre-boundary combined document | migration bridge |
split_legacy_document(text) | a combined document | splits it into world + scenario |
Two forbidden tokens mark a world document as containing run inputs: a line
beginning periods , and a line containing
[epoch:.
Status: three axes, not one tier
An earlier revision of this site described every construct with a single "tier". That word was doing three unrelated jobs at once, and it hid the exact thing a reader most needs to know. Frozen meaning and writable syntax are independent. The period cycle is completely settled and you cannot type it; surface sugar is fully writable and deliberately not frozen. A single scale cannot say both, so this site uses three.
| Axis | Question it answers | Values |
|---|---|---|
| Meaning status | Is what this means settled, and may it change under me? | settled frozen in Core 0.1.2 · drafted designed, may change shape · sketched named only |
| Grounding | Is there something underneath that actually executes it? | runtime lowers and runs · IR-only exists in the IR, no surface · none nothing lowers it |
| Writable now | Can I type this into a world document today and have it parse? | yes · no |
Where each construct sits today
| Construct | Meaning | Grounding | Writable now | Note |
|---|---|---|---|---|
| Ten construct kinds (closed set) | settled | — | — | §1 — a taxonomy, not a syntax |
| Four reading laws | settled | — | — | §2 |
Containers [ ] ( ) { } | settled | runtime | yes | §3 |
# @ ? | settled | IR-only | no | §4 — meaning fixed, no world-source spelling |
* replication-by-position | drafted | runtime | yes | bounded surface sugar; expands before parsing |
* wildcard match | sketched | none | no | reserved; no lowering exists |
Route texture -- solid | settled | runtime | yes | the only surface-grounded texture: declarable, emittable, round-trips |
Route texture ~~ async | settled | IR-only | no | needs a logical route declaration distinct from the structural edge |
Route texture == verified | settled | IR-only | no | acceptance machinery exists; the construct does not |
Route texture !! fault | settled | IR-only | no | fault state exists; route and supervision do not |
| Periods and superdense time | settled | runtime | no | §6 — the model runs; you do not spell it |
| Five memory kinds | settled | runtime | no | §7 |
| Period cycle, six phases | settled | runtime | no | §8 — the clearest case of settled-but-unwritable |
| WorldFrame / EventLedger | settled | runtime | no | §8b |
| BuildFilm | sketched | none | no | build provenance — draft §36 |
| Fact union | settled | runtime | no | union law only; settlement above it is sketched |
//commit | settled | runtime | no | the COMMIT phase is real; the marker is not world syntax |
///seal | settled | IR-only | no | sealing is grounded; the artifact registry is sketched |
/gate | drafted | none | no | no capability-gate node kind yet — draft §20 |
| Canonicalization & content identity | settled | runtime | yes | §11 — you invoke it by writing any world |
| Document boundary | settled | runtime | yes | §15, new in 0.1.2 — enforced as a typed rejection |
| Five surface roles | settled | runtime | yes | Pulser · Relay · Door · Spinner · Orb |
Surface sugar (sugar.v2) | drafted | runtime | yes | battery green and identity-equivalent, deliberately not frozen |
| Mailbox role | settled | IR-only | no | not a sixth surface role; the formatter refuses to emit it |
| Expression notation, types, generics, numerics | drafted | none | no | designed in full — draft §10–§17 |
| Effects, capabilities, entropy | drafted | none | no | draft §23 |
| Supervision error ladder | drafted | none | no | draft §25 |
| Streams and backpressure | drafted | none | no | draft §26 |
| Actor behavior blocks | drafted | none | no | a projection, not a second semantics — draft §21 |
| Evolution and migration | drafted | none | no | draft §27 |
| Podium / ranking | drafted | none | no | draft §20.7 |
| Static-check catalog | drafted | none | no | eighteen rejections — draft §40 |
| Execution profiles | drafted | none | no | draft §41 |
| Fragments, stencils, derives, reflection | sketched | none | no | settled as kinds only — draft §28–§34 |
| Modules and builds | sketched | none | no | draft §35–§36 |
| Foreign functions | sketched | none | no | draft §38 |
| Distributed settlement above fact-union | sketched | none | no | receipts are recognized evidence, never blindly merged |
Counting the yes rows is the honest summary of the language as a writable artifact: containers, five roles, two edge kinds, the solid route texture, the sugar layer, the document boundary and the canonicalization that gives you an id. Everything else on this site is meaning you can rely on and syntax you cannot yet write.
Promotion capabilities
A capability is one named thing the toolchain does not do yet. It is the unit in which the future arrives.
This table is the registry, and it is machine-read. Every
data-requires annotation in the published HTML must
name a capability listed here; the conformance suite fails on an unknown name, on
a capability missing either classification, and on a registry entry that nothing
cites. A capability cannot be invented in a footnote, and it cannot be quietly
abandoned.
Each row carries two independent classifications, and the difference between them is the difference between a design and a program:
| Axis | Values | Answers |
|---|---|---|
| Meaning | settled drafted sketched | how firm the definition is — whether it is frozen, written down in full, or argued for |
| Toolchain | shipped partial unshipped | how much of it the implementation actually does. A partial row must name the pipeline stages the input completes, and the stage that refuses it, from desugar · parse · validate · canonicalize · serialize · seal · execute |
The two textures below are why the second axis exists. Writing
[p0] ~~sig~~> [r0] does not produce a syntax
error. The parser recognizes the reserved texture — it does not fall
through to "unrecognized notation" — so what comes back is located on line 4 and
says why: these are transition classes, not IR v1 edges. That is more than
"unshipped" and much less than "shipped".
tokenize as the stage completed — and that was also
untrue, in the opposite direction: there is no tokenizer.
parseWrlCore splits the source on newlines, strips
comments, and dispatches on regular expressions. Naming a stage the
implementation does not have is not a smaller error than naming one it has not
reached.
The stage names below are now taken from functions that exist. The input completes
desugar — desugarCore
runs, rewrites the surrounding sugar, and passes the texture line through
untouched — and is refused by parseWrlCore. So the
row reads desugar; refused at parse, and both halves name something you
can call.profile line, so they do not seal today and would go
on not sealing after the capability landed, for a reason having nothing to do
with the capability. Nothing would have gone red.
What is mechanical is this: shipping a capability means editing its Toolchain cell to shipped, and the moment that cell changes the suite fails for every block still citing it, by file and block number. The trip-wire is on the row, where a person must act, not on the snippet, where nothing would have happened. Turning a fragment into a positive test additionally needs a fixture context to embed it in — that does not exist yet, and is named here rather than implied.
| Capability | Meaning | Toolchain | What has to ship | Step | Specified in |
|---|---|---|---|---|---|
typed-ports | drafted | unshipped | ports carry a type, messages carry a schema | 1 | draft §11 |
async-route | settled | partial desugar; refused at parse | ~~ as a logical route declaration, plus a writable mailbox | 2 | draft §21 |
profile-mechanism | sketched | unshipped | ProfileSchemaV1 — the machinery a profile is written in: relation kinds, attribute types, units, bounded resources, finite resolution tables. Declarative only, so it needs no expression notation | 3 | Core Part II §D6.1 |
attributed-relations | sketched | unshipped | typed attributes and units on a relation | 4 | Core Part II §D8 |
resolved-terminals | sketched | unshipped | many drivers on one terminal, settled by a named resolution function | 4 | Core Part II §D8 |
behaviours | drafted | unshipped | user-written behaviour blocks canonicalizing to drawn routes | 5 | draft §26 |
collections | drafted | unshipped | Set vs FactSet, the four symbol kinds | 5 | draft §16 |
expression-notation | drafted | unshipped | values, data types, functions, pattern matching | 5 | draft §10–§13 |
generics-traits | drafted | unshipped | parametric generics, traits, hash-pinned coherence | 5 | draft §14 |
numerics | drafted | unshipped | the numeric tower with determinism classes | 5 | draft §15 |
resources | drafted | unshipped | affine handles, borrow and move | 5 | draft §17 |
merge-routes | drafted | unshipped | <~merge~> over a declared join-semilattice | 6 | draft §22 |
verified-route | settled | partial desugar; refused at parse | == with checker identity, policy version and evidence | 6 | draft §23 |
supervision | drafted | unshipped | the supervision floor, caret ownership and !! | 7 | draft §25 |
dynamic-topology | sketched | unshipped | the eight topology operations and their obligations | 8 | Core Part II §D9 |
acausal-relations | sketched | unshipped | undirected conserved-quantity connections settled by a solver wall | 9 | Core Part II §D8 |
effect-walls | drafted | unshipped | capability gates, effect rows, seeded entropy | 9 | draft §20, §24 |
migration | drafted | unshipped | live-state migration as a verified, evidence-carrying route | 9 | draft §27 |
podium | drafted | unshipped | the ranking boundary with a mandatory stable tie-breaker | 9 | draft §20.7 |
derives | sketched | unshipped | stratified monotone graph functions with checkers | 10 | draft §32 |
ffi | sketched | unshipped | foreign functions admitted only through a boundary | 10 | draft §38 |
metaprogramming | sketched | unshipped | phases, fragments, stencils and the six laws | 10 | draft §28–§31 |
modules | sketched | unshipped | content-addressed modules and the no-build property | 10 | draft §35–§36 |
reflection | sketched | unshipped | compile-time reflection free, runtime reflection gated | 10 | draft §34 |
testing | sketched | unshipped | tests and properties as first-class graph specifications | 10 | draft §37 |
domain-profiles | drafted | unshipped | a complete production package — mobility, electrical, logistics, robotics — pinning roles, ports, units, laws and film schemas, written using the step-3 mechanism | 11 | draft §41 |
The Step column is the position in the dependency ladder. Steps are a partial order, not a schedule: several capabilities share a step because nothing among them blocks the others.
data-not-current, which asserts only that the
toolchain refuses it — deliberately not which diagnostic comes back first,
because the first complaint about a future construct is usually a missing
profile rather than the construct itself. Alongside it,
data-requires names the capabilities the block is
waiting on. The day one of them ships, the blocks that depend on it start
parsing, data-not-current goes red, and the
documentation has to be updated before the build is green again.Browser API
wrl.js is an ES module: a faithful browser port of
the identity spine, verified against the reference implementation's canonical
bytes. It is what the playground runs, which is why
the ids it shows are real.
import * as W from "./wrl.js";
const r = await W.sealWorld(source);
// { ok: true, source, desugared, origins, graph, artifact, bytes,
// semanticId: "sem-…", sugared }
// { ok: false, code, message, line, locator, fieldPath }
| Export | Does |
|---|---|
sealWorld(src) | the whole pipeline: desugar → parse → validate → canonicalize → serialize → hash |
desugarCore(src) | the source-to-source pre-pass alone |
desugarCoreMapped(src) | as above, plus authored-line origins for every emitted line |
parseWrlCore(src) | strict world parser; rejects run inputs |
parseWrlLegacyDocument(src) | combined-document migration bridge |
splitLegacyDocument(src) | splits a combined document into world + scenario |
validateGraph(g) | the structural laws, as typed codes |
canonicalizeGraph(g) | sorts and normalizes into canonical form |
graphToIr(g) | the canonical artifact record |
serializeArtifact(a) | canonical JSON bytes, sorted keys, no whitespace |
semanticArtifactId(a) | "sem-" + sha256(bytes) |
formatCore(g) | emits a canonical world document — no scenario syntax, ever |
objectPorts(role) | the frozen port projection, empty groups omitted |
namedRotor(name, n) | four exact integer lanes |
namedRotorPolicy(name) | the rounding provenance id, or null when exact |
roundUOverSqrt2(n) | the integer quarter-turn projection |
selfCheck() | re-seals the pinned demo world and asserts the frozen id |
Errors are thrown as WrlError carrying
code, detail,
line, locator and
fieldPath.
sealWorld catches them and returns them as data.