Provenance#

status:

non-normative

Where this specification came from, and what changed on the way. The previous specification lives in ~/proj/eichenbank-claude/spec and is frozen as reference. It should not be consulted for behavior: it is internally inconsistent — its grammar draft and its test notation disagree on syntax — which is the reason this document exists rather than a pointer to it.

Everything below was formerly recorded as a delta in spec/eb-changes.rst. That file is retired: the deltas are now folded into the rules themselves, and this is the record of what moved.

Keywords renamed#

Old

New

Notes

li

pi

periodic item; optional pi(period, offset) — period defaults to 1, offset defaults to the period (PI-15)

eh

event

ag

agent

rc

resource

state

state

kept — the effect discipline stays declared, not inferred

The two-letter forms are no longer keywords. Rule prefixes followed: LI-i became PI-i and EH-i became EV-i. AG-i and RC-i already matched their keywords and kept their names.

Syntax changes from the old specification#

Declarations keep :=. DECL-10 through DECL-40 are retained exactly.

Two-section programs. A program is model declarations, then the contextual keyword exec, then execution items (EXEC-05). Statements are valid only after exec. This is new; the old specification had no section marker.

pi periods and offsets (PI-15) are new, along with the open issue on non-integer periods.

Trailing pi-body items (PI-25) are new: keyword statements after the terminating expression belong to the pi and run after its value is committed.

Group references take expressions (GRP-40): source_{i%N+1}[-1]. Group declarations still require compile-time constant bounds.

Event and agent parameter lists are optional (AG-15, EV-15): agent workeragent worker().

Explicit release (CLAIM-10, CLAIM-15). This reverses the old specification’s structured claim(res) block end. The reasoning is in Design Rationale; in short, lexical nesting cannot express crossing resource lifetimes, which are routine in queueing models.

Semantic changes from the old specification#

Dynamic resource capacity (RC-60, RC-70) with drain semantics, and RC-30 amended from “positive” to “non-negative” so a resource may be taken offline and brought back.

Effect-matrix additions: functions may not read state variables (FN-32); events and agents may not read pi values (AG-55, EV-35); RNG intrinsics are restricted to pi/event/agent/fn/init (INTR-31); return is valid only in a fn and requires an expression (FN-25); direct event invocation is a compile error (EV-25).

Exec-section visibility (EXEC-45): after a run(), exec statements may read a pi’s or state variable’s final value directly.

Exec-level sched (EXEC-36) registers an initial event applied at the start of every run of every subsequent run().

Scenario timing (SCEN-40) pins that defaults are restored and the scenario applied before the duration and nruns expressions are evaluated. SCEN-50 forbids a scenario assigning a variable used in a group range.

Observation printing (INTR-64) refined: a single-value series prints as the bare value, and :print of a declared symbol prints its scalar value rather than its series.

:randseed (EXEC-35) is now exec-only and at most once per program.

Numeric details pinned — floor division and floor-consistent remainder (TYPE-65), negative int exponent a runtime error (TYPE-75), two’s-complement wrapping (TYPE-85), short-circuit and/or (TYPE-105), int/dbl widening across guard arms (GUARD-40), and the exact RNG and statistics algorithms (INTR-32, INTR-41).

Corrections to the old specification#

Two claims in the old text did not survive checking.

Suspension is not restricted to the top level of an agent body. The old rationale asserted it and rested the “agents without coroutines” argument on it. The compiler accepts timeout and claim inside if, match, and for, and executes them correctly. The invariant that actually delivers the no-coroutines property is narrower: suspension never occurs below a call frame, because fn and pi cannot suspend at all. Nesting inside control flow does not create a call frame.

The forget-to-release bug class is no longer eliminated. The old rationale claimed the structured claim block removed it entirely, which was true of that design. With explicit release it returns, bounded by two rules rather than by syntax: releasing an unheld unit is a runtime error (CLAIM-15), and an agent that terminates holding units returns them (CLAIM-70).

What was not carried across#

The old spec/arch/ and spec/impl/ directories describe interfaces (teal, lua) and an agent-compilation strategy for an implementation that no longer exists. The Rust compiler and VM design is documented in papers/qualifier/paper.rst and docs/source/rewrite.rst instead.

eb-examples.rst was dropped. The programs in eg/ are current syntax and ./mk eg proves they run, which a prose appendix cannot.