Ctrl K
ComunidadGuías…

CHANGELOG.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Changelog

All notable changes to revl are recorded here. Versions follow the IR contract:
a major version is an IR-breaking cut, a minor version adds without breaking.

## 0.3.0rc1 (unreleased) - the 0.3.0 release candidate

0.3.0rc1 is the release candidate for revl 0.3.0. It is a beta: unreleased, and
open to change before 0.3.0. It is the minimal clean, self-consistent six-tier
cut plus the live-systems demo: self-host front end, cross-tier execution,
six-backend conformance, and per-tool-call agent effects on all six tiers. It
also folds in the full agent story and the standing correctness debt.

### The language

- Self-hosted front end. `selfhost/lexer.rvl` and `selfhost/parser.rvl` compile
  at ir_version 3 and are cross-checked against the reference implementations as
  a differential oracle: two independent implementations of one grammar forced
  to agree, so a disagreement is a real defect in one of them.
- Six-backend conformance (py, ts, rust, go, java, wasm). The autogenerated
  conformance matrix is published and green; the compiler emits itself with no
  divergence on py, ts, and java.
- Typing frontier narrowed: match-arm checking in check-position, generics
  instantiation, `type X = Y` alias resolution matching TypeScript, and six
  accept-but-won't-compile holes each verified against `javac` and `cargo`
  and closed. This is not a claim that none remain; the open ones are listed
  under Known issues.
- **Declared resource dimensions (issue #1938, fixed by #2149).** A composition can now declare its
  own capability's resource parameters:
  `capability mail.send(account: discrete, folder: path)`. The parameter is
  bound from the call arguments and then appears in the approval ticket's
  spelling and in the audit token, so `revl audit` records which mailbox is
  sending instead of the fact living only in a gate's own spelling. The kind
  vocabulary stays closed (`path`/`discrete`/`ceiling`, the three orders the
  core vocabulary already used) and the registry stays closed against
  UNDECLARED names, so a typo is still refused at parse. A composition that
  declares no dimension is byte-identical everywhere; `INTERCHANGE_VERSION`
  stays `1.0` (the declaration is an IR member, not an interchange member).
  See docs/design/294-parameterized-capabilities.md.
- `try e`: Result propagation in a fn body (#1967). Expression-bodied top-level
  fns, template scope in block-bodied match arms, and `Float.to_str` let eight
  realistic components compile on the first draft (#633, #570, #703).
- The `Stream[T]` reactive surface across the tiers: `every ... in` iteration,
  `on ... as` typed-event handlers, the map/filter/take combinator chain,
  backpressure policies and the block drain window, provider-declared replay
  with its last-n backlog, and the required `Stream[T]` coeffect. A tier that
  cannot lower a form refuses it by name (#507, #636, #679, #747, #792, #857,
  #982, #1042, #1060, #1066, #1076, #1105, #1179, #1523).
- Endpoints: a `route` clause with derived artifacts, an opaque `Principal` with
  an admission refusal for forged authority, and the `host` row bound to the
  Cordis server (#775, #782, #787). The stdlib gains typed HTTP contracts
  (`Request`/`Response`, `Handled`/`NotHandled`), the canonical request-framing
  primitive, HS256 JWT verification, and context-scoped templates with per-hole
  escaping (#745, #881, #1556, #861, #793).
- Frontend assets: typed, jailed, content-pinned asset handles, the
  insertion-site source map chained into the bundler's, run-time reads of pinned
  assets, and a reactive data channel declared in revl and projected to the
  frontend (#1043, #1057, #1064, #1092, #976). `revl dev` runs the scoped WebUI
  host and the Vite frontend as one command (#833, #984).
- Persistence: a driver-independent typed-model store with store-owned key
  assignment, a memory driver and a sqlite driver (#767, #778, #806). `revl
  gen-types` turns a typed model document into revl types and checks its digest
  at compile (#1958).
- A predictable service lifecycle contract (startup, readiness, cancellation,
  disposal, hot replacement), with native conformance coverage (#760).
- `extern local`: a durable write recorded without being a crossing (#2177).
- Declared intent bounds an operation, not its emit steps. The
  intent-versus-action refinement kernel, the explicitly-related object and
  set-valued scope, the stating slot for a value-returning crossing, and the
  comparison of a standing grant as a declaration at the class-(c) gate (#855,
  #971, #1007, #1031, #1058, #1061, #1073).
- Retention: the `Retained[T, <policy>]` qualifier, a signed erasure receipt
  (`revl retention-receipt`), and a refusal of a past-deadline value that a
  provider body persists (#988, #1018, #1177, #1002).
- Cross-tier divergences closed in `Int.MIN` arithmetic, Float division and
  remainder, Str ordering and character access, `${...}` rendering, list bounds,
  closures, and numeric parsing, plus short-circuit `&&`/`||` on wasm (#1086,
  #1118, #1082, #1106, #1094, #1088, #1138, #1039). Wasm refuses `Int / Int` by
  name instead of lowering it to a signed divide (#2235).
- Refusals added: an undeclared nominal type is `T-UNRESOLVED` rather than a
  mismatch (#863, #902); a statically out-of-range list index (#951); a
  non-finite Float in `json_stringify` (#945); an ADT case that collides with
  another module's name (#1146); an `extern fn` and a `fn` of one name (#1880);
  two component names that differ only in case or underscores (#2272); a method
  call on a record in a component body (#1687); a capability token that cannot
  match, which is now a parse error so a deny rule cannot go silently inert
  (#1992); a null-ambiguous `Opt` at the JSON boundary (#1270). `pub` names are
  module-scoped (#2005) and local bindings shadow outer declarations in the
  resolver (#1990).
- `revl grammar` exports a source grammar derived from the parser, `revl_grammar
  {prompt: true}` serves the complete prompt grammar, and `revl idiom` serves
  the minimal correct example of each construct (#1663, #2175, #1761, #2283,
  #2298). `revl test` gains `--list`, `--filter` and `-v`/`--report` (#866,
  #882). `revl explain` covers every diagnostic code with a `fix` and a
  `guarantee` (#2048). JSON diagnostics name the declaring file relative to the
  invocation and `--json-diagnostics` is registered on all six verbs that read
  it (#2072, #2226, #2030).
- The tree-sitter grammar covers syntax 2.0 and its conformance gate is green
  (#639).
- Self-host: the self-hosted emitters caught up with the reference and the last
  three tier emitters are wired into the native compile driver (#1032).
  `emit_go.rvl` has zero go divergences, `emit_py.rvl` zero py refusals and
  divergences, `emit_rust.rvl` is driven natively and held to the reference's
  bytes, and the front end gained the type layer (type-spelling algebra,
  expression types, provide-method and component-body types), and the self-host
  admission gate enforces the fn-body binding discipline (#1624, #1645, #1143,
  #534, #1154, #1160, #981). The native IR producer carries tests, fault tests
  and an extern's host refs (#2182, #2162, #2145).
- The formal stack landed together (G4 deferred and approval, G5, G6, G1, A1,
  declaration rules), with differential-oracle rows for G9, G-RETAIN,
  G-COUNCIL-SPLIT and the witnessed-extern `undo` rule (#1853, #2081, #2082,
  #2053, #2122).
- Java: an annotated empty list is declared as its element type, not as a raw
  `java.util.List`, so a loop over one (as in `dedent` in `stdlib/str.rvl`)
  compiles under javac (issue #2296, fixed by #2302).
- The self-host native driver links a used module's externs. It now builds the
  same extern closure as `compile_files`, so a module that uses `stdlib/json.rvl`
  keeps its json extern bodies on py and ts (issue #2181, fixed by #2305).
- Go: an `Int32` `+`, `-` or `*` in a component method body traps on overflow,
  and so does unary minus, as a top-level `fn` already did (issue #2262, fixed
  by #2312).
- Service names that differ only in case, and hot-swap names that fold onto a
  running component, are refused on every tier (#2309, closes #2275, #2276).
- A call in a fn body whose callee is a local binding takes its arity and types
  from that binding, not from a same-named private fn in another file (#2319,
  closes #2311).

- Self-host refusals match the reference. Statement-level parse errors are
  refused (#2395, closes #2359), as are the if, match arm, fn and tuple type
  forms (#2398, closes #2396) and block arms the reference cannot lift. Test and
  prop-test bodies are checked too (#2400, closes #2399).
- Self-host name resolution: a `use` resolves as the reference does, and an
  unexported name is refused (#2369, closes #2363). An imported service's record
  types are carried into the native link (#2327, closes #2308), and applied
  generic records compare by type argument (#2404, closes #2403).
- Self-host reference refusals are named as the reference names them:
  UNSUPPORTED on java and wasm (#2388, closes #2383), and on rust and ts (#2377,
  closes #2316, #2353, #2367). Reserved ts service keys and namespaced keys are
  named on py, rust and java (#2392, closes #2389, #2390), and ts mangles
  namespaced host keys as the reference does (#2387, closes #2384).
- Arithmetic in a component method body now executes on py, go, rust and java
  (#2376, closes #2198).
- A rowless running component is named on the manifest wire (#2375, closes
  #2289, #2334, #2351).
- `str_char` covers every code point through a new `Int.to_char` builtin, so
  `str_char(13)` no longer returns an empty string (#2295, closes #2285).
- The ts tier keeps string index scans linear when the loop reads other strings
  (#2320, closes #2313).
- The grammar summary names `capability` and `grant` (#2370, closes #2280), and
  `Secret[T]` has a secret-value idiom served by `revl idiom` (#2331).
- The ts tier renders a structural record type in a signature, so a block match
  arm that captures a record no longer emits an unclosed parameter type, and a
  list of a union is parenthesised (`(bigint | undefined)[]`). The self-host ts
  emitter matches byte for byte (#2300, closes #2297).
- The java tier boxes `Int32` and spells `Any` in v3 type arguments, so
  `List[Int32]` and `List[Any]` compile, and a generic record declares and
  applies its type parameters (#2426, closes #2303). Int and Int32 overflow on
  java now fail with `revl: Int overflow` and `revl: Int32 overflow`, as
  docs/arithmetic.md states for the other hosted tiers (#2425, closes #2381).
- The go tier passes a component `fail` message to `fmt.Errorf` as an argument,
  so a `%` in the message is returned verbatim instead of read as a format verb
  (#2427, closes #2379).
- A function can state a spec with an `ensures` clause over its parameters and
  the returned `result`; it expands to a `prop test`, so the type-derived
  generator, the shrinker and the minimal counterexample all apply, and
  `revl audit --spec-results` lists each spec with the result of its last
  recorded check (#2705, docs/function-specs.md).

### The agent story

- Per-tool-call agent effects (H1) end to end on all six tiers, with residue
  enumeration.
- Witnessed-inverse externs: an extern whose checked inverse is another host
  extern, so the reversible/irreversible boundary moves from fixed-by-the-world
  to moved-by-engineering. The six-tier teardown replays inverses on unload and
  abort, and `compensate` adds typed best-effort compensation on the audit
  surface, distinct from the proof surface.
- Session commit protocol: deferred emissions enqueue and flush at a two-step
  commit, and abort drops the queue and replays the witnessed inverses to prove
  a clean world.
- The approval gate (auto-approve unless irreversible): a call's action class is
  the worst class over its whole reach. Class (a) revertible auto-approves
  silently, class (b) deferrable enumerates at commit, class (c) immediate
  prompts per call with an exact-hash single-use ticket. Standing grants let an
  operator mint a TTL or uses-scoped approval once; revocation retires it.
- Crash recovery: the WAL is the gate's authority. Recovery replays inverses,
  re-prompts a class (c) crossing rather than re-firing it, and refuses to
  resume a policy-recorded snapshot into a policy-less session.
- **An agent-authored source that wires a service whose `emission` names no
  token is now refused: by `revl_load` and `revl_swap`, not only by
  `revl_admit`.** A method that spells `emission` bare declares an effect and
  declines to say what it reaches, so nothing in the composition states that it
  stops short of the admission kernel, and the kernel-boundary fold can no
  longer read it as provably disjoint from the kernel. This is the arm issue
  #1265 sequenced behind the composition half (PR #1292) and issue #2105 took:
  the refusal asks the declarations, not the token namespace, so a candidate
  that composes only pure services is unaffected. The repair on the operator's
  side is one word: write `emission[<token>]`, naming the boundary the body
  crosses, and every shipped service already does: `stdlib/server.rvl`'s
  per-row `Server` included, whose synthesized externs now carry the shim's own
  boundary token rather than the row's label. First-party compiles are
  unchanged; only the untrusted-author profile the agent verbs ride is
  tightened.
- Model placement as a checked route condition: `model role`, `route model`, an
  origin ceiling on the role, the role's device profile and candidate set, and
  `prefer resident` as a per-arm opt-in to residency-aware ranking (#1220,
  #1243, #1423, #2144, #2159). A model council with role-bound members and typed
  disagreement gives its refusal its own guarantee code, and its answer type
  keeps a disagreement from being ignored (#1257, #1302, #1389, #1392).
- Model decisions leave evidence: a signed `ModelDecision` record with a
  fail-closed verifier, sealed at the crossing and replayable from the artifact
  (#1239, #1286). A validated emission's response type compiles into a decoding
  grammar, and providers apply constrained decoding through runtime adapters for
  the common hosted-model wire formats (#1262, #1326, #1524, #1531). Five tiers
  refuse a `validated` emission instead of dropping it (#1391, #1413).
- Models are scheduled onto declared devices: the conductor picks one candidate
  per routed model action before anything spawns, hands each host's schedule to
  its child and enforces it there, provisions each role once, and asks the
  servers what a host holds at plan time. When no candidate fits, the placement
  is refused (#1468, #1478, #1568, #2106, #2180).
- Promotion from recorded evidence: shadow agreement accumulates over the
  decision records and gates a promotion, a landed promotion changes which model
  answers, and a promotion is decided from signed execution receipts rather than
  a test (#1250, #1297, #1309, #1439, #2104, #2174, #1305, #1363).
- Self-evolution pieces: an evolution controller with one lifecycle and one
  verdict, a reward folded from repository counters, held-out scoring on a draw
  the candidate could not read, a curriculum derived from repository artifacts,
  and a declared evolvable-layer state with a rollback that reports what it
  compensated (#1241, #1231, #1258, #1424, #1448, #1230, #1232, #1256). The eval
  honesty protocol (EVAL-1) is frozen and checked (#493, #583).
- Computer use: a reversibility classification, UI transaction phases with a
  five-way revert split and an operator confirmation gate, taint classes derived
  instead of asked, and a transaction unit that settles what it registered when
  a call fails on py, ts, go, rust and java (#1242, #1287, #1284, #1320, #1412,
  #1969, #1971, #1973, #1977, #1978).
- Quorum approval: multi-party approval with a durable decision graph, operator
  verbs for escalate, revoke and override, an admission receipt, and a vote
  bound to a credential with a lifetime instead of a name (#865, #974, #994,
  #1019, #1035). A policy clause can mark a capability never-standing, enforced
  fail-closed (#2010). A distilled auto-approve rule keeps its budget and review
  bind across generations and forks (#983, #995, #998, #999). Delegation hands a
  scoped, revocable resource between components, bounded at depth one (#456,
  #589).
- MCP: `revl mcp proxy` gates an existing MCP server with no `.rvl` written,
  `revl serve --http` and the MCP HTTP transport answer per-request operators
  with SSE streams, and tools are disclosed in tiers with a `revl_verbs` index
  (#1535, #554, #1557, #1505, #1746). Every mutating response carries its exact
  undo, `step_back` reverts the last change, and speculation is the default with
  one explicit commit (#1721, #1741). `revl_state` reports the six agent-loop
  axes, `revl_counterfactual` replays a `revl_act` log under a what-if, and
  `revl_swap` and `revl_change` carry a blast radius (#1759, #1763, #1874).
  Every verb is callable by a function-calling model, and `revl_source`
  enumerates the packaged stdlib (#2076, #2179). A swap or load that does not
  succeed leaves the running composition serving (#1445, #1447).
- `fillSpec` v2 and scaffold: a crossing is a permission with its call-site
  form, each hole names the grammar category of its fill, a hole whose crossings
  span two capabilities is split, and a pure Unit method's fill is refused
  (#1655, #1657, #1671, #1662, #1865).
- Replay and simulation: `revl replay` with replay-mode readiness,
  counterfactual incident replay under an alternate policy, and `revl simulate`
  policy-diff over a recorded WAL (#635, #849, #852). `revl goal` audits
  termination contracts and reports blind spots (#452, #520, #593). `revl
  analyze` searches a Petri net of the composition for a reachable dead state
  (#399).
- A compositional blast-radius benchmark scores an agent on the six axes
  `revl_state` reports (#1737, #1764).

- A cold `revl_change` withdraw is planned against the carried composition
  (#2406, closes #2225).
- `revl_undo` still re-admits the target generation by a cold start, and now
  says so: the undo dossier lists in `stateDropped.components` each running
  component whose live state the rollback drops and the components the target
  withdraws, with a note, and a forward call whose undo is `revl_undo` carries
  an `undoNote` that says the same (#2422, closes #2346).
- A refusal made while a proposal is held names the held proposal. When the
  running composition has a name that the held proposal removed, the message
  lists what the proposal removed and how to proceed, and every such refusal
  carries the `proposal` block (#2428, closes #2230).

### Placement and interop

- Per-component tier placement: a hot component compiles to rust or go while the
  rest of the composition stays on py or ts, composed over the existing
  cross-process seam with G2/G3/G4 checked over the whole manifest.
- The extern config coeffect: a document-global extern reads static config
  resolved at plug time instead of shuttling identity through environment
  variables, on py, ts, go, java, and rust. Config is static data, not a
  capability channel, and a config field type is restricted to data heads.
- Embeddable gate: a two-layer gate API (a pure verdict surface plus a session
  facade), fail-closed, that never admits what the reference compiler refuses.
  It ships in three forms. `revl.gate` is the python library facade.
  `crates/revl-gate` is the native rust library, generated from the self-host
  sources by `tools/build_gate_crate.py` and committed so it builds with no
  Python on the machine. `crates/revl-gate-wasm` packages that crate as a
  WASI-P2 component (`revl:gate@1.0.0`) with an EMPTY import list, so the
  verdict is a total deterministic function of its arguments, provable from the
  artifact. Both native forms carry the same asymmetry: they can refuse, and
  their non-refusing arm is `no-objection`, never an admission.
- `crates/revl-lsp`: the language server as a native rust binary (item 336
  slices 1 and 2). It answers `definition` and the signature half of `hover`
  through `revl_gate::symbols` with no interpreter on the path, and forwards the
  reference front end's diagnostics verbatim, adding native refusals rather than
  replacing anything.
- `revl deploy`: a deploy map and descriptor, attested admission, a coordinated
  rollback, a deploy-admit runner with a stdio transport, and a cross-machine
  leg over SSH with a pinned host key (#440, #451, #667, #744, #795, #803,
  #811). The admission-gated deploy verb is exposed over MCP (#890).
- The sandbox isolation ladder: a wasm-cell rung, a microVM rung, a mixed-arch
  container rung, and a seam transport with per-precondition refusals and an
  approval channel across the boundary (#638, #678, #437, #511, #621, #610,
  #817).
- Named instances: placement-aware spawn with a named handle, surfaced into the
  manifest, with a `place` statement and a plan-time gate (#454, #530, #629,
  #748). Ambient admission for a running composition: provision disjointness,
  replacement and hand-off state, route and handoff rows on the native gate wire
  (#599, #645, #1034, #1055, #1107). Composition layers fold a stack into the
  row table, with per-root admission profiles in `compile_files` (#701, #637).
- Attested placement: `requires attested_tee` verifies an enclave against a
  pinned attestation root, result receipts ride the call path, and a component
  certificate accounts for the whole guarantee catalogue (#859, #964, #975,
  #1023, #862, #973). A composition SLO contract with an observed half, a sample
  floor and a declared denominator runs from inside the running generation
  (`revl slo`) (#869, #1008, #1024, #1040).
- A2A: `import_a2a` binds the HTTP+JSON/REST transport, `through a2a` binds the
  1.0.0 wire for the remote row, the four-op Task lifecycle is bound over both
  entry points, and every generated crossing is correlated with its reply
  shape-gated and its returns tainted `Untrusted` (#518, #594, #697, #774, #783,
  #1030, #977, #1084, #630).
- The private peer pool: a declared object with a join admission gate, an
  asymmetric key pair with rotation and revocation, dispatch to a member with a
  one-result delivery ledger, member liveness (`revl pool probe`, `pool status
  --require-live`), multi-file dispatch as one bundle, and promotion of a member
  (#1277, #1290, #1425, #1467, #1541, #2178).
- Runtimes and artifacts: `revl bundle` has a one-file form (#490, #585).
  `revl-lsp` bakes the private runtime into one distributed binary (#435, #738,
  #802). `revl export client --lang ts` pairs with `revl serve --http` (#450,
  #554). The Rust gate gained a manifest-aware `admit_into` and an admission
  surface reachable only behind the refusal gate (#860, #987). Placement runners
  serve only the keys and methods the spec exports and resolve a key in its
  provider's realm (#1606, #1620, #1574). Realm labels are per `(realm, key)`
  (#1549, #2063).

- Placement runners: an unconfirmed dispose is no clean teardown on rust, java
  and ts (#2355). The go runner awaits each dispose in held-mode teardown before
  it reports DOWN (#2338, closes #2336). An unsupported proxy service is fatal on
  the rust runner (#2340, closes #2335).

### Security hardening

An adversarial review swept every shipped security feature across three waves
and found one recurring bug class: an authority-derivation fold that visits one
crossing surface and misses an alternate crossing, so a capability is reached
but not seen. Every instance was closed. Representative fixes:

- Taint (provenance): endorse no longer launders a foreign origin, whether the
  origin is argument-derived or minted inside the endorsing body.
- The untrusted-author admission profile now refuses a host-extern reach through
  the whole transitive module closure, not only a direct import.
- The MCP server no longer treats the driving agent as a trusted host-code
  author. Source that arrives over the transport compiles under the
  untrusted-author profile, so an inline `@py` body can no longer be loaded and
  run. `revl mcp serve --author-trust`, `--provider` and `--grant` are the
  operator's controls, and the trusted mode stamps every class-(c) ticket with
  the unreviewed host bodies a yes would also let run.
- Path arguments to the MCP verbs are jailed to the operator-sanctioned roots.
  They were a filesystem oracle over every path on the machine, and a restore
  plus snapshot round-trip returned an arbitrary file's whole content.
- The host-file and host-ref jails gained a realpath-containment gate at every
  install-origin resolution site (the compiler and the bundle verifier), so a
  path that escapes the compile root cannot forge a first-party origin.
- The approval gate uses one grant-coverage predicate for both auto-approve and
  revocation, follows the spawn seam as well as the service seam, and installs
  the session owner on every call.
- The atomic compare-and-set guards its inverse on the result across all tiers,
  so a lost race cannot delete the winner's entry.
- A witnessed inverse that reaches an emission through a plain function wrapper
  is refused, keeping teardown emission-free.
- The witnessed-fs workspace jail routes every path family through the guard,
  not only the ones that already did. An inverse's SOURCE endpoint is confined
  and restricted to a sidecar the workspace itself produced (a rename removes
  what it names, so an unchecked source stole outside files rather than merely
  overwriting them); the sidecar directories are resolved and refused when a
  symlink is planted under their name; a hardlinked target is refused rather
  than written through; and every mutation runs through directory fds walked
  down from the root with `O_NOFOLLOW`, closing the check-to-syscall window.
  The families are enumerated in the guard and scanned in the `@py` bodies, so
  a fifth cannot be added silently.
- The ts tier's fs host carries the same pass. `backends/typescript/revl_fs_ts.ts`
  had held every one of those escapes untouched while the py fix shipped: an
  unconfined inverse source that stole and destroyed outside files, sidecar
  directories a planted symlink could redirect outside the root, no link-count
  check, and a name-based write a concurrent writer could divert. It now states
  the same `PATH_FAMILIES` enumeration, restricts an inverse's source to a
  sidecar this workspace produced, refuses a symlinked sidecar directory by
  type, refuses a multiply-linked target, writes only through a verified fd, and
  refuses a write whose name has parted from the inode that was written. The
  enumeration is scanned with the TypeScript compiler API, the ts peer of the
  `@py` body scan. One difference is stated rather than papered over: node
  exposes no `*at()` syscall, so the check-to-syscall window is narrowed with an
  `lstat` component walk plus `O_NOFOLLOW` and an fd-identity check, not closed
  the way the directory-fd walk closes it on py.
- The distribution seam refuses a resource crossing on same-tier as well as
  cross-tier process boundaries, and the wire encoder fails closed on any value
  that is not scalar, list, dict, or a declared record or ADT.
- A network (TCP+mTLS) seam refuses replays. The peer allowlist pinned who may
  call and deliberately did not dedup, so an admitted peer's request could be
  captured and re-delivered and the provider dispatched it again. The reason
  recorded for that (a replay ledger needs the per-boot secret a
  cross-composition caller can never hold) was wrong: dedup needs an identity
  to scope the key by, and mutual TLS has already proved one. Freshness is now
  keyed on the identity the handshake proved, read off the peer certificate and
  never off the payload a replayer controls, so it needs no shared secret, and a
  consumer under another conductor is admitted exactly as before. The ledger is
  bounded per identity, and what an eviction costs is stated rather than hidden.
  Seams report `peer-bound` where they earned it.
- The node bridge seals a correlation envelope. It had no `correlation`
  parameter at all, so a placement disarmed a provider's guard entirely rather
  than refuse a caller that could not satisfy it: one node consumer left a py
  provider unguarded. The ts bridge now seals the same HMAC over the same
  canonical bytes, proven against the real guard over a real seam.
- A boundary policy rule now selects a directly emitted extern by the capability
  token it declares. `extern emission[db] fn pg_write` put `pg_write` in a component's
  reach while the register floor, the approval gate and a bound secret all keyed the
  same crossing `db`, so `capability db requires register keyed` selected nothing on a
  composition whose only `db` crossing was a direct emission: an operator wrote a floor
  and silently got less. Reach carries the declared scope now, and the extern's name is
  no longer a second spelling for the same crossing. `revl audit` renders the scope on
  the host-code line, and the full table of which spelling a rule selects is in
  docs/boundary-policy.md.
- Approval expiry is monotonic and irreversible. The session clock is anchored
  to a monotonic source rather than read from the wall clock on every check, and
  a grant that has been observed expired is latched dead, so nothing that moves
  the machine's notion of "now" can hand back an expired grant for its remaining
  uses.
- `revl mcp serve --approval-record-values` now defaults to `withheld`: a
  crossing whose resource target came from a caller argument is not written into
  the durable cross-session approval log unless the operator opts in with
  `bound`. The cost of the default is that such approvals no longer fold into a
  distilled auto-approve rule, and the distiller now says so and names the flag
  when it declines. Author-written literal targets are recorded either way.
- The TypeScript emitter escapes author text that reaches an emitted comment.
  A `config` field's default is rendered into a `/** default: ... */` doc line,
  and the string escaping it went through is the one a string LITERAL needs.
  A comment has no escape syntax at all, only sequences that end it. The doc
  line now goes through a comment escaper that breaks both of those (a line
  terminator, and `*/`), so a default can no longer close the comment and put
  the rest of itself in code position. Emitted string literals, identifiers and
  template literals were already routed through their own escapers and are
  unchanged; no golden bytes move.
- `revl fmt` proves meaning preservation for every file it writes. Its
  equivalence gate had two holes that met in the middle: the IR comparison
  compiled with no module resolution, so every `use`-bearing file skipped it,
  and the fall-back it landed on compared the formatter's own trivia scanner
  with itself, which cannot fail no matter how wrong that scanner is. The
  scanner had drifted from the lexer, so a `use`-bearing file with a
  triple-quoted string, a `0x`/`0b`/`0o` literal, a `_` digit separator, a
  `'...'` string, a `\"` escape or a `}` inside a host body was silently
  rewritten into a different program. The gate now lexes both texts with the
  reference lexer and refuses on any difference, before anything else and
  whatever the file contains; the IR comparison resolves imports for an on-disk
  file so it actually runs; and the scanner calls the lexer's own number,
  string and brace-matching routines instead of a second copy of its rules.
  Across the 888 `.rvl` files in the tree the formatter now changes the
  compiled meaning of none.
- Declared secrets are redacted on every tier: the secret registry covers byte
  secrets, container secrets, Map keys and values, and the escaped rendering of
  a value, with walks bounded by path instead of recursion. Runner log channels
  funnel behind confidential redaction (GHSA-4x4q-296m-9x9x) (#391, #432, #894,
  #905, #911, #912, #916, #918, #920, #923, #924, #925, #926, #931, #835). Bound
  secrets are injected into extern bodies on ts as on py, and rotate after plug
  (#1953, #2047).
- Effect composition is decided per statement (A1), and emission obligations
  resolve across a service-typed arrow parameter (#394, #395). The parser and
  gate bound source and statement nesting so deep input is refused, not crashed,
  and refuse an unknown top-level IR field or schema revision by name at the
  admission boundary (#566, #658, #1452, #489, #578, #607).
- Host acquisitions undo as their release: an acquisition's undo must be its
  release on the bound handle, an extern acquire's site undo its declared
  inverse, and a provide-method host write's undo its inverse with provenance.
  `no_residue` is no longer green when a bracket's undo did not reverse its
  write, and session teardown checks that every host resource was released
  (#1879, #1885, #1961, #1966, #2054, #1869).
- The approval gate hashes host code reached as a function value, discloses a
  declared-untrusted argument on the ticket, carries each capability's crossing
  ceiling, and treats a witnessed call as class (a) only where its inverse is
  registered (#1546, #1991, #1819, #2045). A swap ticket names the candidate's
  host code, and component leases fence load and unload and bound a lease's TTL
  (#1450, #906).
- Taint survives more boundaries: a persisted origin survives the host round
  trip, the IR keeps a service signature's `Untrusted`/`Trusted` qualifiers, a
  routed operation's parameters are stamped as inbound request values, and
  qualifiers are preserved across the manifest boundary (#1993, #1955, #928,
  #660). Authority does not leak across trust boundaries: an agent-authored
  successor inherits no operator authority, a proposal does not inherit a
  standing authority by taking a reviewed component's name, and a replacement's
  reach is clamped to the inherited bound (#661, #1101, #712).
- Seam hardening: a hostile-wire TCK over the sealed seam envelope, a provider
  failure funneled before it reaches the consumer on every tier and thread, the
  consumer-side error channel scrubbed, and a wire `$kind` resolved against the
  declared cases only (#580, #666, #899, #909, #913, #910).
- The witnessed fs gained original write receipts with expected-before guards
  (`revl.fs.write`), identity checks of the preimage and garbage sidecars inside
  restore and unrm, and an early refusal on hosts without dir-fd support (#529,
  #606, #1037, #1052, #1070, #2020).
- The shell classifier refuses a backslash-newline continuation and a `$` or
  backtick inside double quotes (#934, #953). Archive extraction in the unload
  survey is contained, `truc` names are jailed to `trucs/`, and an in-memory
  compile jails assets and refs lexically (#2124, #846, #1777). Network-exposed
  signing is refused without `cryptography` (#1534). A model-routed component is
  accounted for what it can reach, not its token spelling (#2186).
- HTTP faces: requests are framed by a single agreed `Content-Length`, a
  duplicate credential header is visible, and no authority value is decoded from
  the wire (#901, #914, #1505).

### Operations

- E-Stop (item 443): the operator's emergency halt, as a third verdict `halted`
  alongside `committed` and `aborted`. `revl estop` arms an idempotent latch,
  `revl estop --report` reads it back, and `revl run --estop-latch FILE` honours
  it; `revl_estop` and `revl_estop_report` are the MCP forms. The price is
  stated, not hidden: every registered entry is left stranded and every acquired
  handle stays held, and `revl recover --wal` is how the books are settled.
- `revl changelog`: the release note derived from the structural delta between
  two compositions, every line traceable to a differ fact (item 261).
- `truc`, the component manager (`revl truc`, `src/revl/truc/`): eight
  components plus a bootstrap that assembles itself through the gate on every
  invocation.
- E-Stop on every tier: ts, node, java, go, rust and wasm report or honour the
  latch, the py runtime stops every crossing before its host body from any
  thread, and the ts tier carries an in-flight crossing registry and halt
  inventory (#453, #514, #611, #773, #779, #769, #1518).
- Crash recovery: the WAL stays open for the run's life, a torn tail is sealed
  before every append, run-complete is scoped to its own interval, recovery
  requires a settled WAL and records emission outcomes, and a provider's
  emission made while serving a cross-process call folds into the caller's
  crossing (#568, #563, #650, #718, #2221, #1890). Two-phase admission has
  durable stages and forward recovery (#513, #619, #699). Session teardown is
  awaitable and audited, with original-resource settlement (#533, #656).
- The gate/reference census is published as a generated artifact with
  outsider-recomputable identities and a verifier, and the pinned three-host
  framework benchmark is published (#1306, #1421, #1469, #2156, #1415, #2154).
- `revl doctor` resolves the toolchain reproducibly and reports the revl version
  through one definition that attestations also stamp (#790, #2267, #2279).
  `revl mcp serve` re-execs under the runtime venv or announces and refuses the
  runtime verbs (#1710). `revl run --watch` keeps the ambient provisions across
  a reload (#1593). `revl run` names the failing lifecycle stage on every error
  (#768).
- Licensing: AGPL-3.0 for the compiler, gate and tooling, MIT for what ships in
  your program, with a trademark policy (#1237).
- Front-door docs for the release candidate (#2415, closes #2409, #2410, #2411,
  #2412): the quickstart installs from a clone (`pip install -e .`) and no
  longer points at the unrelated `revl` project on PyPI, the self-host numbers
  come from docs/conformance.md, the commands and MCP reference documents
  `revl export openapi`, `slo --seal`, `deploy --bundle` and
  `import openapi --undo`, and public docs no longer name private downstream
  projects.
- Every `--backend` flag and tier alias map reads one tier list in
  `src/revl/tiers.py`, so a tier spelled one way is accepted or refused the same
  way by every command. `revl deploy --backend` is now validated (#2299, closes
  #2205).
- `revl mcp serve --print-config` prints the client config block for the first
  interpreter that imports both revl and cordis, and `revl doctor` gets a
  matching row (#2318, closes #2281).

- The WAL stops its writers on a failed fsync on go, rust, java and wasm
  (#2354). Service compensations are journaled, and unsynced records are cut on
  go, rust and java (#2372, closes #2345).

### Live systems

`revl swap`, the runtime why-oracle, and `revl apply` run from a tagged clean
checkout as scripted exit tests.

### Known issues

Open at this release: the compiler admits a program that the target toolchain
then rejects, or that it handles differently from the reference.

- #2325 (java): generic variants, `Unit` type arguments and `Set`/`Stream`
  heads emit invalid Java.
- #2328 (self-host rust): a type named `Box` is not renamed to `Box_` as the
  reference does.
- #2344: a `@py` host body reaches the runtime through `sys.modules` although
  `import runtime` is refused.

### Internal

Regeneration, CI, test tooling and roadmap-currency work (the light PR runs and
merge-queue CI of #1679, the root-suite sharding, the affected-tests selector,
the census and ledger records, the site and playground wheel refreshes, and the
main-health fixes between them) is not itemised; it changes no behaviour of the
language or its tiers. Recent examples: the env-gate credit guard (#2304), one
loader per backend emitter (#2306), a cached test listing for the affected-tests
selector (#2307), the pre-merge run of every CI-only suite (#2310), a shared
compile of the self-host lowering module across tests (#2314), and a main-red
fix to a paths-ignore control (#2330). Later examples: the proof that
skip gates are set on the pre-merge path (#2393, closes #2210), the pure-read
guard tests in lint (#2365, closes #2333), a selector rule that re-runs the
corpus guards (#2357), the test-listing cache in the tools (#2326), and the
shared emitter loader for test.py, gate.py and run_wasm (#2323).

### All pull requests in this release

Every pull request squash-merged into main from the v2.0.0 point (commit a73dbbfa7, the rewritten form of 04fa2a00b) through origin/main at 631b77a79 is listed here, in ascending order.

106, 114, 149, 154, 157, 199, 201, 205, 206, 208, 209, 212, 214, 215, 216, 219, 220, 221, 222, 227,
229, 230, 231, 232, 235, 243, 246, 251, 265, 273, 288, 289, 292, 302, 306, 308, 321, 333, 334, 351,
366, 376, 378, 379, 380, 382, 386, 391, 394, 395, 396, 398, 400, 409, 411, 412, 413, 451, 453, 454,
456, 459, 460, 462, 472, 473, 474, 481, 484, 487, 488, 489, 490, 491, 492, 493, 494, 496, 497, 498,
499, 500, 501, 502, 503, 504, 505, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519,
520, 521, 522, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 554, 555, 556, 557, 558, 559, 560,
561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 573, 574, 575, 576, 577, 578, 580, 581, 582,
583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 599, 600, 601, 602, 603, 604,
605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 621, 629, 630, 631, 632,
633, 635, 636, 637, 638, 639, 645, 646, 647, 648, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659,
660, 661, 662, 663, 664, 666, 667, 672, 674, 675, 676, 678, 679, 680, 682, 684, 688, 689, 690, 691,
692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 711, 712, 713, 714, 715, 716,
717, 718, 726, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 740, 742, 743, 744, 745, 746,
747, 748, 749, 750, 753, 754, 755, 760, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773,
774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793,
794, 795, 796, 798, 800, 802, 803, 804, 806, 807, 808, 809, 810, 811, 816, 817, 818, 828, 829, 832,
833, 834, 835, 836, 837, 838, 839, 840, 842, 845, 846, 847, 848, 849, 850, 851, 852, 853, 855, 856,
857, 859, 860, 861, 862, 863, 864, 865, 866, 869, 870, 871, 874, 875, 877, 878, 879, 881, 882, 883,
884, 886, 888, 889, 890, 891, 892, 894, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907,
908, 909, 910, 911, 912, 913, 914, 915, 917, 918, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929,
930, 931, 932, 933, 934, 936, 942, 943, 944, 945, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956,
958, 959, 960, 961, 962, 963, 964, 965, 966, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978,
980, 981, 982, 983, 984, 985, 986, 987, 988, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000,
1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1018,
1019, 1020, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1030, 1031, 1032, 1033, 1034, 1035, 1037,
1039, 1040, 1042, 1043, 1044, 1048, 1049, 1050, 1051, 1052, 1053, 1055, 1056, 1057, 1058, 1059,
1060, 1061, 1063, 1064, 1066, 1068, 1069, 1070, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079,
1080, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097,
1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1109, 1110, 1111, 1113, 1114, 1115, 1117,
1118, 1119, 1121, 1122, 1124, 1125, 1126, 1128, 1131, 1133, 1134, 1135, 1137, 1138, 1139, 1140,
1141, 1143, 1144, 1146, 1147, 1149, 1150, 1152, 1154, 1155, 1156, 1159, 1160, 1162, 1163, 1164,
1165, 1168, 1170, 1171, 1173, 1174, 1176, 1177, 1178, 1179, 1180, 1181, 1182, 1183, 1184, 1185,
1199, 1202, 1208, 1210, 1213, 1214, 1216, 1218, 1220, 1226, 1227, 1230, 1231, 1232, 1237, 1238,
1239, 1241, 1242, 1243, 1245, 1247, 1250, 1256, 1257, 1258, 1260, 1262, 1264, 1269, 1270, 1271,
1273, 1275, 1277, 1280, 1281, 1282, 1283, 1284, 1286, 1287, 1290, 1292, 1294, 1295, 1297, 1301,
1304, 1306, 1312, 1313, 1314, 1317, 1322, 1325, 1326, 1329, 1330, 1335, 1346, 1349, 1350, 1351,
1352, 1353, 1354, 1355, 1357, 1360, 1361, 1362, 1363, 1364, 1365, 1372, 1374, 1375, 1378, 1380,
1383, 1384, 1386, 1389, 1390, 1391, 1392, 1395, 1396, 1398, 1401, 1402, 1404, 1405, 1408, 1409,
1411, 1412, 1413, 1414, 1415, 1416, 1417, 1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1428,
1429, 1432, 1436, 1439, 1440, 1441, 1442, 1445, 1447, 1448, 1450, 1452, 1456, 1459, 1466, 1467,
1468, 1469, 1471, 1476, 1478, 1482, 1483, 1485, 1490, 1493, 1495, 1501, 1505, 1514, 1516, 1518,
1523, 1524, 1530, 1531, 1532, 1533, 1534, 1535, 1537, 1538, 1541, 1542, 1544, 1546, 1548, 1549,
1552, 1555, 1556, 1557, 1558, 1563, 1565, 1568, 1570, 1571, 1573, 1574, 1576, 1578, 1579, 1584,
1586, 1590, 1591, 1593, 1594, 1595, 1596, 1597, 1598, 1602, 1604, 1606, 1612, 1615, 1616, 1617,
1618, 1620, 1622, 1623, 1624, 1626, 1628, 1629, 1630, 1635, 1636, 1637, 1638, 1640, 1642, 1645,
1649, 1650, 1651, 1653, 1655, 1657, 1662, 1663, 1665, 1666, 1667, 1668, 1670, 1671, 1673, 1674,
1679, 1687, 1689, 1710, 1711, 1712, 1718, 1719, 1721, 1730, 1731, 1732, 1737, 1741, 1744, 1746,
1748, 1749, 1753, 1758, 1759, 1761, 1763, 1764, 1766, 1767, 1770, 1772, 1773, 1775, 1777, 1778,
1782, 1783, 1785, 1787, 1788, 1789, 1790, 1791, 1794, 1795, 1796, 1797, 1799, 1803, 1804, 1815,
1816, 1819, 1824, 1825, 1827, 1830, 1831, 1833, 1843, 1852, 1853, 1854, 1856, 1858, 1860, 1863,
1865, 1866, 1867, 1868, 1869, 1870, 1871, 1872, 1873, 1874, 1875, 1877, 1878, 1879, 1880, 1882,
1883, 1884, 1885, 1887, 1890, 1891, 1893, 1898, 1906, 1907, 1916, 1917, 1919, 1922, 1925, 1928,
1929, 1930, 1934, 1941, 1943, 1947, 1949, 1951, 1953, 1955, 1956, 1957, 1958, 1959, 1960, 1961,
1962, 1964, 1966, 1967, 1969, 1970, 1971, 1973, 1974, 1975, 1976, 1977, 1978, 1986, 1988, 1989,
1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
2006, 2010, 2011, 2013, 2015, 2017, 2018, 2020, 2021, 2022, 2023, 2024, 2030, 2039, 2040, 2041,
2043, 2045, 2047, 2048, 2049, 2050, 2051, 2052, 2053, 2054, 2055, 2056, 2057, 2058, 2060, 2061,
2062, 2063, 2064, 2065, 2066, 2068, 2069, 2070, 2071, 2072, 2075, 2076, 2078, 2080, 2081, 2082,
2101, 2104, 2106, 2107, 2109, 2112, 2113, 2116, 2119, 2120, 2121, 2122, 2124, 2126, 2128, 2129,
2130, 2133, 2134, 2135, 2136, 2137, 2138, 2139, 2140, 2141, 2142, 2143, 2144, 2145, 2148, 2149, 2152,
2154, 2155, 2156, 2157, 2158, 2159, 2161, 2162, 2163, 2164, 2168, 2169, 2170, 2171, 2172, 2174,
2175, 2176, 2177, 2178, 2179, 2180, 2182, 2185, 2186, 2220, 2221, 2226, 2227, 2228, 2233, 2235,
2236, 2238, 2242, 2243, 2244, 2245, 2247, 2248, 2249, 2251, 2253, 2255, 2256, 2258, 2261, 2265,
2266, 2267, 2268, 2269, 2270, 2271, 2272, 2273, 2274, 2278, 2279, 2282, 2283, 2288, 2290, 2291,
2292, 2293, 2294, 2295, 2298, 2299, 2300, 2301, 2302, 2304, 2305, 2306, 2307, 2309, 2310, 2312,
2314, 2318, 2319, 2320, 2323, 2326, 2327, 2330, 2331, 2338, 2340, 2354, 2355, 2357, 2365, 2369,
2370, 2372, 2375, 2376, 2377, 2387, 2388, 2392, 2393, 2395, 2398, 2400, 2404, 2406, 2415, 2422,
2425, 2426, 2427, 2428

## 2.0.0

The typed-effect core, the six emitters, and the reference IR. See the roadmap
history for the 2.0 line.

## 1.0.0

Initial release.