Skip to content

feat(dsl): standard library — movement modifiers (p7-s5) - #103

Merged
JArmandoAnaya merged 1 commit into
mainfrom
feat/p7-s5-movement-modifiers
Aug 2, 2026
Merged

feat(dsl): standard library — movement modifiers (p7-s5)#103
JArmandoAnaya merged 1 commit into
mainfrom
feat/p7-s5-movement-modifiers

Conversation

@JArmandoAnaya

Copy link
Copy Markdown
Contributor

Slice 43g of #43, and the last of the library. §8.9 as bundled DSL source: the
any_shape / common_*_shape hierarchy, the seven §8.9.19–§8.9.25 enums, and
the 17 movement modifiers.

With this the whole §8 standard library is declared. Only the CLI and
bindings slice (43i) remains before #43 closes.

The common parameters

Every modifier carries §8.9.1.1's four: at, movement_mode, track, shape
— on the strength of "The following parameters are common to all domain model
movement modifiers."

Five usage signatures (keep_position, keep_speed, keep_lane,
physical_movement, avoid_collisions) omit the
<standard-movement-parameters> placeholder the other twelve include. The
general statement is the normative one and the signatures illustrate a typical
call, so all seventeen get them — and over-accepting is the safer error, since
the alternative rejects a scenario the standard permits.

The modifiers are actor-associated, and §7.3 says so

§7.3.12.3's example of an actor-associated modifier is:

modifier vehicle.keep_lane():   # "keep_lane() is defined in the domain model (see §8.9.16)"

The language reference is telling us how this chapter is declared. Each modifier
goes on the most general actor that can execute the movement actions it tunes:
movable_object, which owns move() and parents both vehicle and person,
or vehicle for the lane-related pair §7.3.12.3 places there by name.

Association is not decoration — it is what makes the chapter declarable. An
unassociated modifier lane collides head-on with §8.12.10's struct lane, and
an unassociated modifier speed shadows stdtypes::speed so thoroughly that
speed_range: range of speed stops naming a physical type. Under
vehicle.lane and movable_object.speed neither problem arises.
AssociationIsWhatMakesTheChapterDeclarable pins this, so the declarations are
not later "simplified" back into a collision.

Three modifiers where the standard collides with itself

§8.8 declares actions movable_object.change_speed,
movable_object.keep_speed and vehicle.change_lane. §8.9 declares
modifiers of the same names for the same actors. A qualified behavior name
identifies exactly one declaration (§7.2.2.2.5), so the language cannot hold
both.

§7.3.12.3's unassociated form is the only spelling that exists in the language
and does not collide, so those three take it. The defect is in the standard
rather than in the translation; it is recorded in the worksheet, in the coverage
matrix, and in
ThreeModifiersAreUnassociatedBecauseTheStandardCollides.

43f's forward-looking guard fired on exactly this, which is what it was for. It
is updated rather than deleted: it now pins that an action and a modifier may
share a simple name, and points at the collision test for the case they cannot.

Reported, not fixed — second facet of #100

Probing this chapter found that a modifier application inside a with: block
is not validated at all
:

v1.drive() with:
    no_such_modifier(1)     # accepted silently: Status::Ok, 0 diagnostics

check_modifier_application runs for a scenario-member application but not for
the ones collected in a with block. That is the larger half of #100, since the
with: block is where the domain model expects nearly every movement modifier
to be applied. Added as a comment there with the §7.3.12.2 scoping rule that
also explains the original symptom.

p8-s3 (#46) needs #100 fixed first, and §8.9 is the surface to test it
against — which is the useful thing this slice hands the next one.

Tests

dsl_stdlib_test.cpp, +7 cases: the shape hierarchy and what each compute()
returns; the seven enums; all four common parameters on all seventeen
modifiers; the actor association; the three-way collision; the scalar/range
pairs as separate fields with the range one actually a range type; and the
collision guard.

1285 gtest (+7), 184 pytest. TheBundledLibraryChecksClean still asserts
zero diagnostics of any severity across the now-complete library.

Docs: osc-dsl-coverage.md, frontends/dsl/README.md, the new worksheet, and a
note in the worksheet README that §8.9 is the chapter where the
strip-the-examples trick does not help, because its examples are inline.

Refs #43

Translates §8.9 into bundled DSL source: the `any_shape`/`common_*_shape`
hierarchy §8.9.1.2 prints as DSL, the seven §8.9.19–§8.9.25 enums, and the
seventeen modifiers that tune a movement action. With this the whole §8
standard library is declared.

Every modifier carries §8.9.1.1's four common parameters — `at`,
`movement_mode`, `track`, `shape` — on the strength of "The following
parameters are common to all domain model movement modifiers". Five usage
signatures omit the `<standard-movement-parameters>` placeholder the other
twelve include; the general statement is the normative one, and accepting a
parameter the standard permits beats rejecting a valid scenario.

The modifiers are actor-associated, which §7.3.12.3 states outright: its
example of an actor-associated modifier is `modifier vehicle.keep_lane()`,
annotated "keep_lane() is defined in the domain model (see §8.9.16)". Each one
goes on the most general actor that can run the actions it tunes —
`movable_object`, which owns `move()` and parents both `vehicle` and `person`,
or `vehicle` for the lane-related pair §7.3.12.3 places there by name.

Association turns out to be what makes the chapter declarable at all. An
unassociated `modifier lane` collides head-on with §8.12.10's `struct lane`,
and an unassociated `modifier speed` shadows `stdtypes::speed` so thoroughly
that `speed_range: range of speed` stops naming a physical type. Under the
qualified names neither problem arises. A test pins this so the declarations
are not later "simplified" back into a collision.

Three modifiers must nonetheless be unassociated. §8.8 declares ACTIONS
`movable_object.change_speed`, `movable_object.keep_speed` and
`vehicle.change_lane`; §8.9 declares MODIFIERS of the same names for the same
actors. A qualified behavior name identifies exactly one declaration
(§7.2.2.2.5), so the language cannot hold both. §7.3.12.3's unassociated form
is the only spelling that exists and does not collide. The defect is in the
standard, not in the translation, and it is recorded in the worksheet, the
coverage matrix and a test.

43f's forward-looking guard fired on this, exactly as intended, and is updated
rather than deleted: it now pins that an action and a modifier may share a
simple name, and points at the collision test for the case they cannot.

Second facet added to #100 while probing this chapter: a modifier application
inside a `with:` block is not validated at all — a nonsense modifier name is
accepted silently. That is the larger half of the gap, since the `with:` block
is where the domain model expects nearly every movement modifier to be
applied. §8.9 is the surface that fix should be tested against, and p8-s3
(#46) needs it first.

1285 gtest (+7), 184 pytest. The library still checks with zero diagnostics of
any severity.

Refs #43
@JArmandoAnaya
JArmandoAnaya merged commit b1b583c into main Aug 2, 2026
12 checks passed
@JArmandoAnaya
JArmandoAnaya deleted the feat/p7-s5-movement-modifiers branch August 2, 2026 05:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant