feat(migrate): encode deferred triggers in standard SysML v2 under -strict - #632
Conversation
…trict A state's deferrableTrigger on a SignalEvent is written under -strict as an item buffer, a do action whose accept loop keeps each occurrence, and an exit action that sends the kept occurrences to self, merged beside the state's own do and exit behavior; a signal an outgoing transition accepts is not kept. Both modes annotate the state with MigrationMetadata::DeferredEvent. The runtime lowers a state's item usages as state data and an explicit `send ... to self` as a send to the sending object, so the encoding executes. Co-Authored-By: jason.han <hanhuijun@gmail.com>
|
I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".
|
…eature/strict-deferred-events Co-Authored-By: jason.han <hanhuijun@gmail.com> # Conflicts: # internal/translate/migrate/states.go # tests/migrate/behavior_more_test.go
A state's deferred-signal buffers are initialized once, so without clearing them a second visit's exit replayed every occurrence the first visit kept. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…rded transitions Under -strict the accept loop that keeps a deferred signal now runs once per route the signal reaches the object by (direct and via each port portRoutes finds), so port-delivered occurrences are buffered too. A guarded transition out of the state accepting the same signal no longer suppresses the deferral: the transition takes the occurrence while its guard holds, the loop keeps it otherwise. Only an unguarded (or statically true) transition still wins. Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
…ly when written The generated do action rendered the state's own do behavior after the fork lines, so a behavior that is not written as an action (a state machine, an unwritten reference) left a succession to a missing action. Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
…tate's transition Only a transition out of the deferring state itself, under no guard, takes the signal from the deferral outright; one out of a substate wins only while that substate is active, so the state keeps the signal the rest of the time. A deferral dropped for a completion transition is kept as a comment in the state's body. Co-Authored-By: jason.han <hanhuijun@gmail.com>
|
Fixed in 17f0ed7: a deferral dropped for a completion transition is now kept as a |
|
Re "Interleaved deferred signals replay out of order" (thread PRRT_kwDOTp2CH86mXFkH): confirmed — with one |
… time With several deferred signals in one state the flush keeps arrival order within each signal but not between signals; UML leaves the event pool's order open, so the report note and the reference say this is a permitted approximation. Co-Authored-By: jason.han <hanhuijun@gmail.com>
|
Resolved as a documented limitation (maintainer decision): UML 2.5.1 §13.3.3.3 makes the dequeuing order of the event pool a semantic variation point, so replaying one signal at a time, each in arrival order, is a permitted approximation. 77be761 states this in the migration report note on every deferred trigger of a state with several deferred signals (asserted in |
Co-Authored-By: jason.han <hanhuijun@gmail.com>
…vior's usage name Co-Authored-By: jason.han <hanhuijun@gmail.com>
… its route alone Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
…on takes Co-Authored-By: jason.han <hanhuijun@gmail.com>
…into feature/strict-deferred-events Co-Authored-By: jason.han <hanhuijun@gmail.com> # Conflicts: # internal/translate/migrate/migrate.go # internal/workspace/libs/stdlib.snapshot # internal/workspace/libs/stdlib/OpenSysML Libraries/MigrationMetadata.sysml
…ing names clear of what they refer to A transition out of a deferring state on a general of the deferred signal accepts its occurrences, as a v2 accept typed by the general does, so it takes precedence over the deferral; one on a specialization contests it only for those occurrences. The members the strict encoding adds no longer take the name of the deferred signal, its root namespace, a port, or the library packages it refers to, and SequenceFunctions::including is written from the root when a member of an enclosing scope shadows the package. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…s not written A transition into a pseudostate -strict refuses (choice, junction, history) no longer takes the deferred signal's routes, since the output never writes it; the deferral keeps its accept loop instead. The note and reference doc also state that the runtime keeps an occurrence a substate's transition takes without leaving the deferring state. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…sing do-behavior accepts A transition chosen for a message now takes it from the accept of a do behavior of the state it fires out of and of every state enclosing that, whether or not the firing leaves those states; a do behavior in a sibling orthogonal region still shares the occurrence. Under -strict a deferring state whose completion transitions are all guarded keeps its accept loop (Approximated, noted) instead of dropping the deferral; an unguarded completion transition still drops it. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…sed completion transitions A deferrable trigger's own SignalEvent is reported approximated when an outgoing transition takes every route, instead of falling to the unwritten- events sweep; a completion transition -strict does not write no longer drops the deferral. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…into feature/strict-deferred-events Co-Authored-By: jason.han <hanhuijun@gmail.com> # Conflicts: # internal/workspace/libs/stdlib.snapshot
A deferred signal yields to, or is dropped for, only a transition the strict output writes: transitionWritten shares the writer's end and target checks, so a transition into a final state of another region or a state of another machine no longer suppresses the accept loops. The note on a deferral names an internal transition of the state, whose self-transition form flushes the buffer to self on re-entry and keeps the occurrences again. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…d a general of it Under -strict a deferral of a signal the same state also defers a general of, or defers again by another trigger, gets no accept loop by the routes the other deferral's loop already accepts by, so the exit action sends each kept occurrence once. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…fold through a chain Co-Authored-By: jason.han <hanhuijun@gmail.com>
What and why
Built on #625 (
feature/strict-migration, now merged), targetingdevelop.Under
-stricta UMLdeferrableTriggeron a SignalEvent used to be dropped as unmapped; by default it is written as the OpenSysML-onlydefer Sig;, which the OMG pilot's parser rejects (and in a large model such as TMT one rejected line cascades into tens of thousands of parse errors). Strict output now carries the deferral in standard SysML v2:do action; the state's own exit behavior runs first in theexit action, the flush after it.SynthesizedNamemachinery and is chosen clear of the state's own members; a state's nested do/exit behavior keeps its name, with its qualified name (used by view exposes and diagram layouts) now routed through the generated action.portRoutesa transition trigger uses: the direct accept plusaccept … via <port>for each connector-derived port, or only the ports the deferrable trigger names. The flush replays toself, which a port-less trigger accepts (noted).true) transition out of the state itself is not kept (Approximated, note names the transition). A guarded transition, or a transition out of a substate, does not suppress the deferral: the transition takes the occurrence while its guard holds / its substate is active, the loop keeps it otherwise (noted as an approximation of UML's priority). A state left by a completion transition keeps nothing (Unmapped, with anot migrated: defer Sig;comment in the state body: the accept loop would never let the do action complete).doActivity) leaves the accept loop alone, with the existing comment.@MigrationMetadata::DeferredEvent { ref :>> signal : Sig; }(metadata def DeferredEvent { ref signal : Base::Anything[1]; }added to the bundled library; theref :>> signal : Sigform is what the pilot accepts). Default mode still writesdefer Sig;. Non-signal deferrable events stay unmapped as before.internal/ir/lowertreats a state'sitemusages as state data (like its attributes), and lowers an explicitsend … to selfas a send to the sending object (the same route as a send with no target).Specification basis
UML 2.5.1 §14.2.3.9 (deferred events: kept while the state is active, dispatched on exit; a transition on the same event takes precedence). No row of
docs/project/spec-compliance.mdmoves. Documented indocs/reference/sysml-v1-migration.md(deferrable-trigger rows and a new "Deferred signals under-strict" subsection, including that the composite state's do action covers its substates' activation) anddocs/guide/11-migrating-from-sysml-v1.md.How it was verified
go build ./... && go vet ./... && gofmt -l . && go test ./...clean;python3 scripts/changelog.py check,scripts/check-doc-links.py,scripts/check-doc-ids.pyclean.tests/migrate/behavior_more_test.go: theovenMachinedefault and strict tests now assert the metadata, the strict encoding and the absence ofdefer; newTestStrictDeferredSignalsAreKeptAndReplayedcovers two deferred signals in one state with its own do and exit behavior, a composite substate, outgoing-transition precedence, a completion-transition state, report targets through the generated action, and executes the migrated model in the REPL session: signals sent while in the state are kept and delivered after it exits, a transition-triggered signal is not buffered, and the state's own do/exit behavior still runs. NewTestStrictDeferredSignalsAreKeptByEveryRoutecovers a connector-delivered signal (via inbox), a trigger naming a port (via side) and a guarded matching transition whose guard is initially false, executing that the connector-delivered occurrence is kept, then replayed and taken by the transition once its guard holds. NewTestStrictDeferralSurvivesInactiveSubstateTransitionexecutes a composite state deferring a signal that one substate's transition accepts: sent while the other substate is active it is kept and replayed on exit. NewTestStrictDeferralWithoutRunnableDoBehaviorcovers adoActivitythat is a StateMachine.validate-sysml-batch, pinned pilot) over the strict output of everytests/migrate/testdata/xmifixture plus our libraries:oven.sysml(the deferred-trigger fixture) 0 errors; 0 errors mentiondefer, the buffer, or the flush. The remaining 472 errors in that run are unrelated buckets (unresolvedthis.xreferences in opaque behaviors,transition/fork/elseparse breaks inempty_behaviors,plant_states,station_points,.kermllibraries not collected).Open-MBEE/TMT-SysML-Model,TMT.mdzip, 823 deferred triggers),bin/sysml TMT.mdzip -strict -convert sysml, pilot over the output plus our libraries — before (base branch) vs after:no viable alternative/mismatched input/missing EOF): 50 → 50, none attributable todefer(the 50 are the decision-elseordering andtransition/first/accept/dobreaks owned by other sessions).error:lines: 32,536 → 32,592. The +56 are all additional references to signal/item types the pilot already fails to resolve on the base branch (e.g.GCFrame,PEAS-TCSsignals): each such deferral now names the type three more times (metadata, buffer, accept). Not fixed here.internal/exec/runtimeconformance fixture foritemstate data /send … to self; that behavior is covered by the migrate execution test only.Checklist
make testandmake lintpass locallychanges/unreleased/<slug>.<section>.md, not as an edit toCHANGELOG.mdmake docs-countsrun if a gate count moved (compliance rows need nothing: the census is counted at docs build)F4,K5) in the body, docs, or changelogLink to Devin session: https://nasa-jpl-demo.devinenterprise.com/sessions/2a00d846dce845f1b62739e756690000
Open in Devin Desktop: https://nasa-jpl-demo.devinenterprise.com/desktop/session/2a00d846dce845f1b62739e756690000?variant=devin
Requested by: @HuiJun