Skip to content

feat(pssm): bind entry, do and effect parameters from the accepted event and return a behavior's outputs - #490

Open
devin-ai-integration[bot] wants to merge 8 commits into
developfrom
feature/pssm-behavior-parameters
Open

devin-ai-integration[bot] wants to merge 8 commits into
developfrom
feature/pssm-behavior-parameters

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

What and why

Builds on #486, now on develop. The classifier's behavior parameter and operation result constructs were "no translation" refusals: UML binds an entry/exit/do behavior's parameters from the triggering event occurrence's data (PSSM §8.5, CallEventOccurrence/SignalEventOccurrence), and a call event's operation returns whatever the triggered behavior produces; SysML v2 has a spelling for each, but the emitter did not carry it. This PR adds the spellings so the referee can run these tests instead of refusing them, and pins where the spelling does not hold.

Per construct:

Construct Verdict Reading
Behavior parameter — entry, do, transition effect translated A v2 accept binds the payload on the transition (SysML v2 §7.18.3, accept actions §7.17.8). The accepting transition's effect stores the payload or the operation's arguments in machine attributes (trigger_<Signal>, trigger_<op>_<param>), and the target state's entry/do action declares its parameters bound to them: entry action : S_entry { inout log = log; in p1 = trigger_op_p1; }. Same values, same run-to-completion step, no extra trace unit. An effect that is itself the parameterised behavior reads the accept's parameters directly. Data-less paths (completion, accept without payload) that reach such a behavior stay refused, since UML then has no data to bind.
Behavior parameter — exit refused (behavior parameter <state>) UML runs the exit before the leaving transition's effect, which is the first place a v2 spelling can read the accepted data; a candidate that stores the data before the exit would need to run before the transition fires, an extra observable unit the admitted traces do not have. Recorded as a refusal in the alignment note.
Operation result translated The behavior producing the value becomes an action def with out parameters (out output : String / out 'return' : Boolean), its return an assignment; the runtime's call path from #486 returns the outputs to the synchronous caller after the step.
Tester trace translated in #486; here the driver's ordering is exercised by the returning cases
Standalone machine translated in #486; Standalone 003 now runs

Emitter additions the traces needed, read from the model rather than hard-coded: operation in parameters on call triggers, Util::Tracing::formatParameterValue, ToString, or/xor/not, and qualified library names for packaged behaviors.

PSSM buckets

52 pass / 13 fail / 37 not-expressible / 1 differs-by-design (after #486) → 56 / 13 / 33 / 1. Every movement is adjudicated in docs/project/pssm-referee.md ("Moves"):

Test Movement Adjudication
Event 019 D not-expressiblepass T2's effect return "output" spelled with out output; the one admitted trace reached and nothing else
Event 019 E not-expressiblepass or(left, right) arguments carried into the two regions' entries; both admitted orders reached and nothing else
Deferred 007 not-expressiblepass deferred op(p1) dispatched from S2, T4_effect with in p/out 'return'; the one admitted trace reached
Standalone 003 not-expressiblepass same machine as Event 019 E, standalone
Event 017 B, Event 019 B, Event 019 C stay not-expressible, reason shrank entries, do and effects bind; each has an exit reading the leaving transition's data
Standalone 002 stays not-expressible exit point ExitPoint1; entry point EntryPoint1; behavior parameter S2 — first two byte-identical
Entry 002 F stays not-expressible entry point EntryPoint1; local transition T1.1; local transition T1.2 — byte-identical

The classification pinned by TestSuiteClassification moves 35 standard / 31 extension / 37 not-expressible → 38 / 32 / 33. No fail moved.

Runtime changes

None. The runtime's call-result path is #486's; this PR touches tools/referee/pssm/ and the records only.

Unresolved

  • An exit behavior with parameters stays a refusal (Event 017 B, 019 B, 019 C, Standalone 002), with the reading above.
  • Same-named operations are told apart by identity throughout (tester call, sameEvent, one set of carried attributes per overload, trigger_bump_1_count / trigger_bump_2_flag). Two whose input names cover each other — bump(in count : Integer) and bump(in count : Boolean) — have one accept bump(count) spelling between them, so a trigger naming either is refused (TestParametersOverloadsWithOneSpellingRefused); no suite test has the shape.
  • A do activity with out parameters, a behavior reached by several triggers or by events of different shapes, and a signal with several attributes stay refused with precise reasons (TestParametersRefusals).

Specification basis

PSSM ptc/18-11-06 §8.5 (event occurrences binding a triggered behavior's parameters; the caller of a synchronous call event resumed with the outputs after the run-to-completion step); SysML v2 §7.18.3 (transition accept and its payload), §7.17.8 (accept actions), §7.17.2 (action parameters), KerML StatePerformances.kerml and TransitionPerformances.kerml. No row of docs/project/spec-compliance.md moves — no runtime rule changed. The alignment note (docs/internals/design/precise-semantics-alignment.md) gains the input → emitted-v2 spelling for each construct so the translation can be re-implemented from the record.

How it was verified

New tests: tools/referee/pssm/parameters_test.go (signal and operation-argument binding, rebinding per occurrence, do-activity inputs, operation outputs, and the refusal cases), driver tests in run_test.go (TestDriveTesterTraceAfterCallReturns, TestTracerMakesEachCallOnce), TestParametersUnnamedReturnIsRead (an operation and entry whose UML return parameter is unnamed, read as return throughout), and TestSuiteNoTranslationReasons pinning the remaining reasons per test.

All gates pass:

go build ./... && go vet ./... && gofmt -l .                      # clean, gofmt prints nothing
go test ./...                                                     # ok
go test -C tools ./... && go vet -C tools ./...                   # ok
OPENSYSML_REQUIRE_PSSM_SUITE=1 go test -C tools ./referee/pssm/... # ok
go run -C tools ./cmd/pssm-referee -check                         # 56 pass / 13 fail / 33 not-expressible / 1 differs-by-design, baseline reproduces
OPENSYSML_REQUIRE_TRAINING_CORPUS=1 OPENSYSML_REQUIRE_PILOT_CORPORA=1 go test -count=1 ./tests/corpus  # ok
make lint && make docs-check                                      # ok
python3 scripts/changelog.py check && python3 scripts/check-doc-ids.py  # ok
go run -C tools ./cmd/doc-counts -check                           # already current

Referee checks by hand: -json output byte-identical under -jobs 1, -jobs 8 twice, and no data race under -race; -check rejects a mutated count and a mutated provenance digest (provenance first) with exit 1; -update is reproducible; an absent suite is a skip (exit 0) unless OPENSYSML_REQUIRE_PSSM_SUITE=1; a wrong checksum is refused; a hand-broken trace separator fails -check on the first test and the front end rejects a hand-broken emitted type; -keep writes 70 models (38 standard + 32 extension); a flipped construct disposition fails TestSuiteClassification.

Checklist

  • make test and make lint pass locally
  • Tests added or updated for the change
  • Documentation extended where it already covers the surface (see CONTRIBUTING.md)
  • Changelog entry added as changes/unreleased/<slug>.<section>.md, not as an edit to CHANGELOG.md
  • baselines regenerated and make docs-counts run if a gate count moved (compliance rows need nothing: the census is counted at docs build)
  • No internal work-item labels (waves, slices, F4, K5) in the body, docs, or changelog

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration
devin-ai-integration Bot force-pushed the feature/pssm-behavior-parameters branch from f50517e to e5c3841 Compare September 21, 2026 10:07
@devin-ai-integration
devin-ai-integration Bot marked this pull request as ready for review September 21, 2026 10:43
@devin-ai-integration
devin-ai-integration Bot force-pushed the feature/pssm-behavior-parameters branch from e5c3841 to ba3b081 Compare September 21, 2026 10:46
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

@devin-ai-integration
devin-ai-integration Bot force-pushed the feature/pssm-behavior-parameters branch from 391bbb7 to a68e7ed Compare September 21, 2026 11:46
devin-ai-integration[bot]

This comment was marked as resolved.

@devin-ai-integration
devin-ai-integration Bot force-pushed the feature/pssm-behavior-parameters branch from a68e7ed to 100032b Compare September 21, 2026 12:08
devin-ai-integration[bot]

This comment was marked as resolved.

@devin-ai-integration
devin-ai-integration Bot force-pushed the feature/pssm-behavior-parameters branch from 3216804 to 2efe36e Compare September 21, 2026 13:02
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration Bot and others added 7 commits September 21, 2026 13:51
…ent and return a behavior's outputs

The emitter stores a transition's accepted signal payload or operation
arguments in attributes of the machine and declares the target state's
entry or do action inputs bound to them; an effect reads the accept's own
parameters. A behavior producing the operation's result becomes an action
def with out parameters the runtime returns to the caller. The classifier
refuses only an exit with parameters, which runs before the leaving
transition's effect. Event 019 D, Event 019 E, Deferred 007 and
Standalone 003 move from not-expressible to pass.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
…put types against the operation's

An inout parameter is one feature of the action def, bound inout in the usage
and returned as the operation's inout; its write is spelled after the body's
other statements, as UML posts the output node's value when the activity
completes. outputNames refuses a behavior whose output types differ from the
operation's by position instead of returning the value under the operation's
name.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
An inout parameter's write was moved, expression and all, after the body's
other statements, so it read state those statements had changed since the
output parameter node was fed. The write now evaluates in place into a
holding attribute of the definition, and the body ends by assigning it to
the inout, which is when UML posts the node's value.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
A call operation action names one operation; the referee kept only its name, so a tester's call and a behavior's binding resolved to the first operation of that name and same-named overloads were merged. Statement and Expr now carry the operation's xmi:id, Class.Operation looks one up by it, and sameEvent compares call events by the operation, spelling both signatures in the refusal when two overloads reach one behavior.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…tributes

Carried-event attributes and the carried-event set are keyed by the
operation, not its name, with the overload's number joining the attribute
name; a call trigger whose accept spelling cannot tell two same-named
operations apart is refused.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…is read

The reader gave an unnamed return parameter its name only when spelling the
producing behavior's outputs, so a tester reading such an operation's result
pin read an empty result and the trace was refused as reading a value the
operation does not return. The name is now given once, when the parameter is
read, so the operation's outputs, the behavior's return statement and the
tester's read of the result agree.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@devin-ai-integration
devin-ai-integration Bot force-pushed the feature/pssm-behavior-parameters branch from ca13594 to db5e90b Compare September 21, 2026 14:02

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 new potential issues.

Devin Review

Comment thread tools/referee/pssm/binding.go
Comment thread tools/referee/pssm/emit_behavior.go Outdated
…y identity

A transition from a substate into the state enclosing it completes that
state's region (PSSM 8.5.8) and does not re-enter it, so the binder no
longer counts it among the transitions entering the state. A behavior call
carries the referenced activity's xmi:id and the emitter inlines that owned
behavior rather than the first of its name.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
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