You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Tracking issue for pillar P8. See docs/roadmap/roadmap.md.
Objective
Lower checked concrete DSL scenarios to the shared Scenario IR and execute them on the same runtime as XML, with composition operators (serial/parallel/one_of) and concrete-value movement modifiers, demonstrating execution parity via XML/DSL scenario pairs with matching trajectories (DSL §7.6 semantics, §8.8 actions, §8.9 movement modifiers). The DSL spec defines trace-acceptance rather than operational semantics (§7.6.1) — Scena's deterministic executor is one conformant operational choice, documented per section. Constraint solving and abstract-scenario generation are explicitly out of scope for v0.0.1 (ADR-0004).
GS-12/GS-13 green (GS-12 bit-identical to its XML twin)
Every DSL-execution matrix row In-v0.0.1 implemented with tests
scena-run accepts .osc concrete scenarios
Status (2026-08-02 continuous-improvement audit): all P8 sprints merged; GS-12 XML/DSL byte-identical parity is enforced in CI. Residuals against the exit criteria: sub-scenario invocation in do does not lower (#123); several §8.8 rows claim Exec In without a lowering (#124); on directives and most modifier arguments are dropped silently (#125); GS-13's --select arm never runs in CI (#116); the DSL matrix needs a truth pass + Tests column (#126, #127).
gs12-dsl-cruise.osc and gs12-xml-cruise.xosc are the same scenario in the
two languages, and their traces are equal byte for byte. The check is part
of golden.py check-all, so CI asserts it on macOS, Linux and Windows on every
push. "Two frontends, one runtime" is now a test rather than a claim.
Building that pair caught a real divergence, which is the best evidence it was
worth building: the DSL storyboard stops when its do directive ends (§7.6.2)
while the XML twin ran on, so the ramp froze at 19.975 m/s against 20. The twin
needed a Storyboard stop trigger — the only place XML can say the same thing.
The decisions, and where they are recorded
ADR-0030 — lowering: the entry point is named and a lone scenario names
itself (§7.7.2); a participant is a field deriving from std::physical_object;
concrete means keep(field == constant); §8.7 declares no performance limits
and lowering invents none; a remnant is reported, never approximated.
ADR-0031 — composition: an operator contributes exactly one thing, the
start trigger on a phase's Event. Concrete durations are arithmetic done at
load; a parallel join is one ConditionGroup, which is already an AND; one_of's alternative is an input defaulting to the first, because the
engine has no seed machinery and a hidden input is what determinism forbids.
ADR-0032 — modifiers: every §8.9 modifier lands on an action P2/P5 already
implements, or is reported. The at anchor decides how, and at: end needs
the phase length p8-s2 fixes. keep_speed/keep_position lower to nothing
on purpose.
What the DSL does not execute, and why
Reported with a §-citation, never approximated: emit/wait @event/on/ until (§7.6.2.5's events have no runtime carrier), along/along_trajectory
(a concrete route comes only from §8.12.2's map methods, which the standard says
may be external — §7.3.7.4), acceleration (no acceleration-target action in
the IR), distance (bounds a phase by distance, sequencing is by time), the
seven non-default parallel overlaps, and any value that would need a solver
(ADR-0004). The DSL coverage matrix lists each with its reason.
Standards defects found along the way
Recorded in docs/user-guide/one-scenario-two-languages.md and the coverage
matrix: the three §8.8/§8.9 name collisions, the two §8.15 contradictions, the
absent performance limits, animal's missing taxonomy counterpart, and
implementation-defined entry-point selection.
Two defects on our side surfaced too, and both are fixed: enum!member resolved only in the current namespace and never through the use
list (§7.7.4.2), which silently made every enum-valued keep look like one
needing a solver; and the .. range operator, which never lexed at all —
§7.2.2.6.7 spells [a '..' b] while a float's leading digits are optional, so [2..4] was a race the operator lost. The lexer and the parser agreed with each
other on a spelling the standard does not have, so every range in the suite was
written wrong and nothing noticed until duration: [10s..30s].
One is filed rather than fixed: #110, contextual resolution of an overloaded
enum literal (§7.3.3). It blocks nothing — the qualified spelling works — but a
scenario copied out of the specification may need the literal qualified.
Activity
docs(roadmap): add GitHub tracking map for the road to v0.0.1 (#48)
JArmandoAnaya commentedon Aug 2, 2026
P8 — OpenSCENARIO DSL Execution: complete
All four sprints are merged and their issues closed.
.oscin, trace out,through the same runtime the XML frontend has been feeding since P4.
b51de28,6b4fae4e3eb4c5d404e7d9c5427c13 golden scenarios / 47 checkpoints (was 11/39), 1392 gtest, 194 pytest,
32 ADRs.
The exit criterion, verified literally
gs12-dsl-cruise.oscandgs12-xml-cruise.xoscare the same scenario in thetwo languages, and their traces are equal byte for byte. The check is part
of
golden.py check-all, so CI asserts it on macOS, Linux and Windows on everypush. "Two frontends, one runtime" is now a test rather than a claim.
Building that pair caught a real divergence, which is the best evidence it was
worth building: the DSL storyboard stops when its
dodirective ends (§7.6.2)while the XML twin ran on, so the ramp froze at 19.975 m/s against 20. The twin
needed a Storyboard stop trigger — the only place XML can say the same thing.
The decisions, and where they are recorded
itself (§7.7.2); a participant is a field deriving from
std::physical_object;concrete means
keep(field == constant); §8.7 declares no performance limitsand lowering invents none; a remnant is reported, never approximated.
start trigger on a phase's Event. Concrete durations are arithmetic done at
load; a parallel join is one ConditionGroup, which is already an AND;
one_of's alternative is an input defaulting to the first, because theengine has no seed machinery and a hidden input is what determinism forbids.
implements, or is reported. The
atanchor decides how, andat: endneedsthe phase length p8-s2 fixes.
keep_speed/keep_positionlower to nothingon purpose.
What the DSL does not execute, and why
Reported with a §-citation, never approximated:
emit/wait @event/on/until(§7.6.2.5's events have no runtime carrier),along/along_trajectory(a concrete route comes only from §8.12.2's map methods, which the standard says
may be external — §7.3.7.4),
acceleration(no acceleration-target action inthe IR),
distance(bounds a phase by distance, sequencing is by time), theseven non-default parallel overlaps, and any value that would need a solver
(ADR-0004). The DSL coverage matrix lists each with its reason.
Standards defects found along the way
Recorded in
docs/user-guide/one-scenario-two-languages.mdand the coveragematrix: the three §8.8/§8.9 name collisions, the two §8.15 contradictions, the
absent performance limits,
animal's missing taxonomy counterpart, andimplementation-defined entry-point selection.
Two defects on our side surfaced too, and both are fixed:
enum!memberresolved only in the current namespace and never through the uselist (§7.7.4.2), which silently made every enum-valued
keeplook like oneneeding a solver; and the
..range operator, which never lexed at all —§7.2.2.6.7 spells
[a '..' b]while a float's leading digits are optional, so[2..4]was a race the operator lost. The lexer and the parser agreed with eachother on a spelling the standard does not have, so every range in the suite was
written wrong and nothing noticed until
duration: [10s..30s].One is filed rather than fixed: #110, contextual resolution of an overloaded
enum literal (§7.3.3). It blocks nothing — the qualified spelling works — but a
scenario copied out of the specification may need the literal qualified.
Left open per repo convention.