[ ZR-41 · EXECUTION RESEARCH ] Model

State, Effects, and Compatibility.

A safer-web claim needs explicit conditions and evidence. This proposed model states what ZR-41 would preserve, how denied operations and exhausted budgets behave, and where PHP compatibility ends. It is not a completed proof of a working runtime or browsing protection.

Execution state

Each request i is modelled as a state tuple:

StateXi = ( Pi, Mi, Ki, Qi )
Pi
program position and continuation: the current ZIR operation, the frame stack, and pending unwinding.
Mi
request-owned mutable memory: every value and slot allocated in the request's region.
Ki
capability set: the effects this request may perform, each with type, scope and generation.
Qi
remaining resource budget: a vector of instructions, bytes, open resources and wall time.

Shared immutable data S and the shared services are not part of Xi. S is a constant available to every transition; services are reached only through effects.

Transitions

Execution is a sequence of labelled steps. An action a is one ZIR operation: a pure computation, a memory operation on Mi, or an effect that names a capability.

StepXi —a→ Xi′
MODEL D · Execution transitionsfig. 5
X_i(P, M, K, Q) step acheck K, cost X_i' = (P', M', K, Q - cost(a)) Fault: cap missingerror raised at P, no effect Exhausted: Q - cost(a) < 0abort, then teardown TerminatedM reclaimed, K revoked next step
One step from state X_i under action a. The action either succeeds and produces X_i', faults because a needed capability is missing, exhausts the budget, or reaches termination. Only the first outcome continues; the others are defined, observable endings or errors.

A fault is not a terminal state. It transfers control to the program's error handling, exactly like a thrown exception, so the program may catch it and continue. Exhaustion and termination are terminal.

The isolation condition

IsolationMutableReach(Mi) ∩ MutableReach(Mj) = ∅   for i ≠ j

MutableReach(Mi) is the set of mutable cells reachable from request i's roots (its frames, its region, its reference slots and the object handles stored in them) without passing through an effect. The condition says no mutable cell is reachable from two requests.

Scope. The condition is about request-private memory only. It deliberately excludes shared immutable data, which may be reachable by everyone because it cannot change, and shared services, which are not reachable as memory at all: a request can only send them copied values through a capability. A cache that two requests use is therefore consistent with the condition, while a cached object handle that two requests both mutate is not.

Proposition 1 (preservation, sketch)

If the isolation condition holds for all pairs before a step, it holds after it.

Assumptions: every ZIR memory operation allocates only in the acting request's region; values crossing a service boundary are deep-copied; S is immutable after boot; handles are validated for owner and generation before dereference; native code accesses no region memory. Sketch: a step changes reachability only by allocating (new cells belong to Mi), by storing (both source and target already in Mi or S), or by receiving a service result (fresh copies in Mi). None adds a cell of Mj to the reach of i. The argument is only as strong as the assumptions; it is not a proof about any implementation.

Effects and authority

An effect action a names a capability c and an operation op. The rule has a success case and a failure case:

  • If c ∈ Ki, c's type permits op, c's scope includes the target, and c's generation is current, the service performs op and the step yields Xi′ with the copied result placed in Mi′.
  • Otherwise the step yields a fault: Pi′ is the program's error handler with a CapabilityError, Mi is unchanged except for the error object, Ki is unchanged, and the service is never contacted.
Proposition 2 (no unauthorised effect, sketch)

Every externally observable effect performed during request i corresponds to a step whose capability was in Ki at that step.

Assumptions: services are the only components able to perform external effects on a request's behalf; extension shims are counted as services and declare their capabilities; the engine has no other path to system calls during request execution. Logging by the engine itself is out of scope.

Resource accounting

BudgetQi′ = Qi − cost(a),    Qi′ ≥ 0

Every action has a non-negative cost vector: instruction count, bytes allocated, resource handles opened, and wall time for effects that wait. The step is permitted only if every component stays non-negative. If any would go negative, the action is not performed and the request moves to Exhausted.

Exhaustion is not catchable by the program, by design: a handler that runs code would need budget the request no longer has. The engine runs the teardown sequence from TRACE B under a separate, fixed teardown allowance, then reports an error response. Budgets are configuration, not constants of the model, and choosing them well is an evaluation question.

Proposition 3 (bounded request, sketch)

A request performs at most Qi0 units of each resource plus the fixed teardown allowance.

Assumptions: cost is charged before an action takes effect; costs are non-negative and complete (no free action has unbounded work); services account their work to the calling request; the clock used for wall-time budgets is monotonic.

Compatibility matrix

The matrix lists what each area of the ecosystem would demand of the design. It deliberately contains no pass rates: there is no implementation to measure.

AreaConcernProposed strategyEvaluation method
Core semanticsCoercion, comparison, references, copy-on-write, destructor timingNamed ZIR operations per rule; reference counting for objects with destructorsDifferential execution against the reference engine, including warnings
Standard libraryHundreds of functions with individual edge casesImplement by usage frequency; unsupported functions fail loudlyUpstream language tests where licensing allows, plus generated inputs
Composer packagesAutoloading, static state, file-system assumptionsAutoload through a file capability; statics are request-scopedRun package test suites under both engines and diff outcomes
FrameworksBootstrapping cost, container singletons, worker-mode resetsFreeze boot artefacts into shared immutable data; containers per requestLifecycle tests: many sequential requests, assert no cross-request state
Database driversNative drivers, persistent connections, credentialsPooled database service behind a capability; no credentials in the cellProtocol-level tests and transaction-rollback-on-teardown checks
ReflectionIntrospection of private state, attributes, closuresSupported read-only over region values; no reflection into servicesTargeted suites for reflection APIs used by popular libraries
Dynamic loadingeval, computed include, runtime class creationRun the pipeline at request time under the same checks and budgetFuzz dynamic paths; assert budget accounting covers compilation
Native extensionsUnverifiable memory access, global stateCopying shim, declared capabilities, optional out-of-process hostingPer-extension review; independent assessment of the shim