Skip to content

feat(migrate): translate opaque JavaScript/English bodies, guards, swimlane names and clock reads to executable v2 - #382

Open
devin-ai-integration[bot] wants to merge 40 commits into
feature/v1-state-interaction-fidelityfrom
feature/v1-opaque-behavior-migration
Open

devin-ai-integration[bot] wants to merge 40 commits into
feature/v1-state-interaction-fidelityfrom
feature/v1-opaque-behavior-migration

Conversation

@devin-ai-integration

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

Copy link
Copy Markdown
Contributor

What and why

The v1 → v2 migrator wrote activities and state machines in executable v2 but kept every OpaqueAction, OpaqueExpression, OpaqueBehavior and guard body a Cameo author had written in JavaScript or "English" as a comment, unless it already happened to parse as v2 with visible names. That left retry loops unguarded and clock bookkeeping dead. This PR translates a bounded subset of those languages into executable v2, resolves the names they use through the swimlane (ActivityPartition.represents) they sit in, gives simtime an executable form, and cleans up the report for the constructs this exposes.

Opaque-language subset (internal/translate/migrate/opaque.go, new): a lexer/parser/translator for JavaScript / ECMAScript / Java / empty-language bodies and English guards. A script label is read only when every word of it is JavaScript, ECMAScript, JS, Rhino or Nashorn plus at most one version (Javascript Rhino, JavaScript (Nashorn) 1.8, ECMAScript 2015); a Java label is Java plus at most one version; any other word (JavaScript Expression Language, ECMAScript for XML, JavaCC, JSON) is a language the translator does not read.

  • Statements: x = e, x += e (-=, *=, /=), sequences separated by ;/newlines, var/let/const x = e for a declared local (a const is never assigned again, nor is an in parameter).
  • Expressions: integer/real/boolean/string literals, identifiers and dotted members, + - * / % (a Java / on two whole operands is OpenSysMLMathFunctions::quotient(x, y), the exact quotient truncated toward zero; refused when the types cannot tell), comparisons, && || !, parentheses, trivially mappable ?:, Math.min/max/abs/floor/ceil/round/sqrt/powRealFunctions::… (Math.min/max variadic in JavaScript, folded pairwise — one argument is itself, none is refused as an infinity — and exactly two arguments in Java; Math.round(x) as floor(x + 0.5), JavaScript's half-up; Math.ceil(x) as OpenSysMLMathFunctions::ceiling(x), exact at the least Integer where -floor(-x) overflows), string escapes decoded as JavaScript reads them (legacy octal escapes and characters the notation cannot spell are refused), java.util.Collections.max/min(s)max/min on a collection. A Java body's a.equals(b) on strings is a == b (the comparison of content), and its ==/!= with a string operand is refused, since Java compares strings there by identity; JavaScript string == is a value comparison and translates as it stands.
  • English: TRUE/FALSE/true/false, a property name — spaces and all: a run of words between operators is one name (not Guide Star Lost and i < Retries), refused whole when nothing visible is called that — not X, X and Y, X or Y, comparisons written with =/==, parentheses. English has no calls: Math.sqrt(t) > 3 or name.equals(other) is a construct refusal, never dispatched to the script function table.
  • Everything else is a typed refusal carrying the offending token (refusedLanguage/Syntax/Construct/Call/Name/Type/Context): loops, calls outside the table, new, string methods, regexes, non-simple declarations, this. in unknown context, type-incompatible operands. A refusal of a recognized language is final — the body is never re-read as v2 syntax. A translation is emitted only when every name resolves, the types agree where known, and the result parses with the v2 parser.

Swimlane context (swimlane.go, new): partitions are indexed through node and inPartition; represents is resolved as a property (this.tcs, nested this.a.b) or classifier (this). Names in a body or guard resolve against the represented object first, then the activity's parameters/locals, then the owning block. Unset, dangling, absent, untyped and unwritable representations and nodes outside any partition each get a defined behavior and a note; a partition is reported mapped only when a name was actually resolved through it. A partition representing a collection (cells : Gauge[2]), or a dotted name through a multi-valued feature, is a collection from that step on: arithmetic on it, a scalar assigned from it and a write through it are refused naming the carrier, and a call in such a lane runs in the caller's context with the report saying why; only java.util.Collections.max/min reductions accept it.

Clock (translate.go, internal/exec/runtime/clock_read.go): the SimulationConfig.timeVariableName (default simtime) is read as localClock.currentTime; the runtime evaluates currentTime on the standard Clocks::Clock against the shared runtime.Clock, so -observe this.Time_Acq_Total and %runs report the migrated attribute. Assigning currentTime is refused with ErrClockNotAssignable; a redefinition of it (attribute now :>> currentTime;) is recognised by the redefinition chain, not the name, so it reads the clock and refuses the write alike, bare or through a part. A calc def result expression is checked against the single return/output parameter's type; a behavior with several outputs is refused as a result expression. A DurationObservation whose two events are nodes of the activity (an initial node counts as a start, stamped right after start, before the activity's wait) becomes a pair of [0..1] attributes with no default, the start instant and the elapsed clock, assigned only when a run reaches each event, so an unreached observation is blank in %runs/-observe rather than 0.0 (observation.go, new); every other shape — including a flag asking for the end of an initial, final or control node — says why it is not.

Where it lands: opaque/value/structural-feature actions → assign statements (multi-statement bodies as a sequence); guards → if on the succession; OpaqueExpression defaults → attribute defaults; JavaScript constraints → constraint def expressions over the ConstraintBlock's parameters; JavaScript OpaqueBehaviors → calc def / action bodies. Symbolic durations (ditSetup s) resolve through the same lookup.

Report hygiene: a CallBehaviorAction with no behavior, no pins and only a DurationConstraint is a leaf step and is mapped ("a step with a duration and no further behavior"); calls with pins or an unresolved behavior stay unmapped with a pin-oriented reason. A UML region with no vertex is not written (nothing could enter it, and the runtime correctly refuses a region with no initial state) and is reported approximated — this is the change to states.go, kept to the seven lines in regions() with the helper in region.go.

XMI: stereotypes whose profile schema namespace ends in .xmi (SimulationProfile.xmi) were mistaken for XMI bookkeeping and dropped. The shared reader on develop now recognizes only the metamodel namespaces (IsXMINamespace/IsUMLNamespace); this PR pins that with TestStereotypeUnderSchemaNamespace in internal/core/xmi/sysmlv1. It surfaces «Refines», «TMT_Requirement», … in the report (see the Dependency row below).

Runtime: OpenSysMLMathFunctions::quotient(x, y) joins the non-normative extension library (integerQuotient: exact Integer quotient truncated toward zero, ErrDivisionByZero for y == 0, ErrArithmeticOverflow for the least Integer by -1 rather than a wrapped result; conformance calc_integer_quotient, TestRuntimeRobustnessIntegerQuotient, snapshot regenerated). perform members of an action def performed as a classifier behavior run as steps of the performance; a non-behavior named as an action fails with ErrNotABehavior (this moved two refused rows of docs/project/analysis-library-census.json).

TMT proof (TMT-2024x.mdzip)

Header (this PR's base, feature/v1-state-interaction-fidelity, → this PR, same TMT-2024x.mdzip): 28113 mapped, 10367 approximated, 5656 unmapped28625 mapped, 10319 approximated, 5192 unmapped (1713 skipped as profile/library/notation content and 764 unreferenced elements in both); both outputs validate with 0 errors.

Metaclass mapped approximated unmapped
ActivityPartition 0 → 15 104 → 89 0
CallBehaviorAction 295 → 499 199 → 432 670 → 233
«TODO_Owner» CallBehaviorAction 2 1 → 2 2 → 1
Constraint 0 → 26 3 → 0 37 → 14
ControlFlow 2295 → 2337 100 → 58 33
«Probability» ControlFlow 31 → 33 52 → 50 0
DecisionNode 70 → 91 83 → 62 0
OpaqueAction 0 → 136 178 → 42 0
ObjectFlow 453 → 465 353 → 341 116
DurationConstraint 0 185 → 188 44 → 41
Slot 9880 → 9933 53 → 0 1100
«ValueProperty» Property 416 → 417 54 → 53 0

Every other row is identical on the base and here: ValueSpecificationAction (approximated for structural reasons, 4 now carry translated values), OpaqueBehavior (translated bodies are written as state entry/do bodies and stay approximated; toolkit calls outside the table and empty bodies keep their comments), DurationObservation (all 380 observe no event; the report says so), Region and Dependency (the vertex-less-region and XMI-namespace fixes are on the base).

Execution: bin/sysml tmt.sysml -action "'Acquire Target with IRIS and NFIRAOS - Logical' 'Acquire Target with IRIS and NFIRAOS'" -runs 100 -seed 1 -observe clock -observe this.Time_Acq_Total — on the base output all 100 runs complete but this.Time_Acq_Total stays at its 0.0 default (the Time_Acq_Total = simtime - Time_Acq_Total body is a comment); here this.Time_Acq_Total = clock in every run: min 19.4 s, mean 141.5 s, p50 116.8 s, max 455.5 s. (These differ from the figures over a develop base because the base writes the model's own «Probability» values — p = ProbabilityBTOOP, 1.0 - ProbabilityBTOOP, … — where even splits were written before.) The retry loop is exercised on the seeds whose draws reach it: -runs 1 -seed 6 -trace shows this.TCS.i := 1, guard i >= Retries (Retries -> 2) false, retry, this.TCS.i := i + 1 -> 2, guard true, exit. Lamp::'Lamp Ohm Law' (V = R * i) is written as constraint def 'Lamp Ohm Law' { in attribute V, i, R : ScalarValues::Real; V == R * i } and, with -seed 1 (the base's draw policy refuses an unseeded uniform), evaluates true for (12.0, 6.0, 2.0), false for i = 5.0, and %validate of an instantiated Lamp reports the constraint true/false the same way.

Cameo's stored snapshots for the same activity: Group 0 mean 96.6 s (6 runs, 80–119 s), Group 1 157 s, Groups 3/6 ≈ 210 s. The OpenSysML numbers differ and are not tuned: which per-group SimulationConfig applies (probabilities and durations) is selected by the simulation-configuration work this PR is stacked on.

Known limitations

  • Bare min(a,b)/max(a,b) (no Math.) and other toolkit calls (ALH.*) are refused, as are UML Expression trees and bodies that are not expressions.
  • A DurationObservation with no events (all 380 in TMT) cannot be timed; the referring DurationConstraint keeps its own value.
  • -observe reports features of the run's performer; features of nested parts (this.TCS.i) are read through -trace or the REPL.
  • OpaqueBehaviors written as state entry/do bodies stay approximated even when translated, because the state body is still an approximation of the v1 behavior call.
  • A configured clock name is recognized model-wide: SimulationConfig does not say which bodies its executionTarget reaches, so any visible feature of that name shadows it, but a name configured for one activity is also recognized in another.
  • Two non-nesting partitions representing different objects give a node no partition to resolve through; its names fall back to the activity and its block, and both report lines say so.
  • A part whose multiplicity is not written in numbers (banks : Bank[1..n]) may hold one object or several: a name read through it, a partition representing it, and a partition whose object is reached through it are refused with the part named, never read as one object (the written v2 feature holds one value, as the base migrator writes it, so a default of that feature is checked as one value).
  • Type checks between non-scalars need the migrator to know both types: a feature typed by a value type of unknown base, or by a proxy, is trusted to fit. The whole number -9223372036854775808 is refused because the magnitude is read before its sign.
  • Whole-number arithmetic is the exact arithmetic of a v2 Integer: where a JavaScript Number would round a result beyond 2⁵³ or a Java int/long would wrap, the translation does not reproduce that; the modeler's Integer-typed feature keeps the exact value. Only literals are refused for range (above 2⁵³ − 1 in JavaScript, beyond int64 anywhere). Math.floor/ceil/round return the library's Integer: exact through the whole Integer range, and a whole Real at or beyond 2⁶³ or below −2⁶³ is a typed arithmetic-overflow error at run time, never a wrapped Integer.
  • A two-event DurationObservation with no firstEvent flags spans both nodes whole (first's start to second's end); UML 2.5.1 gives firstEvent ([0..2]) no default. Explicit flags are honored per event.
  • The branch adds no package: every new file lives in an existing translate (internal/translate/migrate) or exec (internal/exec/runtime) package, so the layering gate's packageLayer, permitted and tolerated tables are unchanged, and no ratcheted baseline moved.

Specification basis

Kernel Semantic Library Clocks.kerml (Clock::currentTime, Clocks::universalClock) and Occurrences.kerml (Occurrence::localClock) for the clock read; SysML v2 textual notation for assign, succession guards (if), constraint def and calc def bodies for the translated output; UML 2.5.1 ActivityPartition::represents, OpaqueAction/OpaqueExpression/OpaqueBehavior bodies and DurationObservation::event for the source. Adds the Clock::currentTime and action-def-performance rows to docs/project/spec-compliance.md.

How it was verified

  • gofmt -l . (empty), go vet ./..., make lint, go build ./..., go test ./... (81 packages ok).
  • Corpus gates with the corpora downloaded: OPENSYSML_REQUIRE_TRAINING_CORPUS=1 OPENSYSML_REQUIRE_PILOT_CORPORA=1 OPENSYSML_REQUIRE_PILOT_LIBRARY_XMI=1 go test -count=1 ./tests/corpus ./tests/identity -run 'TestTrainingExamples|TestPilotCorpora|TestPilotLibraryXMI|TestCorpusRoundTrip' ok.
  • make docs-check (0 broken links), python3 scripts/changelog.py check, python3 scripts/check-doc-ids.py, go run -C tools ./cmd/doc-counts -check.
  • New tests: opaque_test.go (translator table + refusals), opaque_migration_test.go and fixtures acquisition.xmi, plant.xmi, reactor.xmi (partitions incl. nested/unset/dangling/absent/untyped/unwritable/no-partition, JS assignments, English guards, clock reads, non-default timeVariableName, DurationObservation shapes, constraint bodies, calc bodies, refusals), empty_region_test.go (under tests/migrate), internal/translate/xmi/sysmlv1/xmi_test.go (TestStereotypeUnderSchemaNamespace), runtime conformance clock_read_local_clock_elapsed, clock_read_redefined_current_time and performed_action_def_perform_members_are_steps, robustness robustness_clock_read_test.go (TestRuntimeRobustnessClockRead).
  • By hand: the TMT migration, validation, 100-run execution, retry trace and constraint evaluation above.

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 Bot and others added 5 commits September 17, 2026 22:28
…ames, read the clock

Opaque JavaScript and English bodies are translated to v2 expressions by a
bounded translator with typed refusals; names resolve against the partition's
represented element before the activity and its owning block; the configured
clock variable reads the local clock, which the runtime evaluates; profile
stereotypes serialized under a schema namespace ending in .xmi are no longer
skipped as XMI bookkeeping.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…formance, not behaviors of the occurrence

A performance occurrence materialized for a typed action step ran the def's
own perform members as classifier behaviors of the occurrence, in the wrong
frame and before the step itself performed them. Typed constraint bodies and
precedence-aware spelling of translated opaque expressions come along, with
conformance fixtures for clock reads through localClock.currentTime.

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

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…document the opaque subset

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration
devin-ai-integration Bot marked this pull request as ready for review September 18, 2026 01:06
devin-ai-integration[bot]

This comment was marked as resolved.

…xt, bare clock assignment

- a JavaScript const declared in a body is readable but a later assignment
  to it is refused; declared locals are typed ScalarValues::T so they resolve
- a write to an in parameter is refused whether the direction is written or
  omitted (UML's default), through parameterDirection
- a guard or default is one expression: text after its one optional ';' is
  refused instead of silently dropped
- the runtime refuses a clock's own bare 'assign currentTime := ...' with
  ErrClockNotAssignable, as it already did through 'localClock.currentTime'
- a one-event DurationObservation documents the UML semantics it applies
  (the node's own execution) and the acquisition fixture covers it

Co-Authored-By: jason.han <hanhuijun@gmail.com>
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration Bot and others added 2 commits September 18, 2026 02:18
…sional swimlanes, let features shadow the clock name

A declaration of a name the body already has — a prior local, a member every
action inherits, or a pin, parameter or property visible where the body lands —
is refused instead of writing a second member. Pins are recorded as declared so
bodies read them by their written name and cannot assign an input pin.

A node held by partitions that do not nest resolves through the one naming an
object, or through either when both name the same object; partitions naming
different objects are a clash the node's and the partitions' report lines state,
and names fall back to the activity and its block.

A configured clock variable is recognized only where no feature of that name is
visible; the report line names the configuration naming it, or counts the
configurations when several do. A dotted name through an untyped pin is refused
rather than dereferenced.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
devin-ai-integration[bot]

This comment was marked as resolved.

…alves as JavaScript does

Opaque string literals decode \b \f \xHH \uHHHH \u{...} and line
continuations; legacy octal escapes and characters the notation cannot
spell (NUL, vertical tab, other control characters, lone surrogates) are
typed refusals instead of silently losing the backslash. Math.round(x)
translates to RealFunctions::floor(x + 0.5), which rounds a half toward
positive infinity as JavaScript does, rather than RealFunctions::round.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
devin-ai-integration[bot]

This comment was marked as resolved.

…rce's edge unresolved, divide Java whole numbers as Java does

An opaque action whose body translates is no longer marked inert, so the flows leaving the output pins its body assigns are written; only an output pin the body never assigns, or an action whose body is kept as a comment, keeps its flows as comments, each saying which.

An edge in no partition takes its source node's partitions whenever the source is in any, so a source held by two dimensions naming different objects refuses the edge's guard with that clash instead of reading it through the target's partition.

Java is its own dialect: `/` on two whole operands lowers to `RealFunctions::floor((x - x % y) / y)`, the truncating quotient Java computes; when the types cannot tell that both operands are whole, the division is refused. JavaScript `/` stays real division.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
devin-ai-integration[bot]

This comment was marked as resolved.

…urrogate pairs

A JavaScript whole number beyond 2^53 - 1, which the script's Number rounds,
and any whole number beyond what an Integer holds are refused instead of
being written as a different value. A feature typed by an enumeration or a
block is known to hold no scalar: it is refused where a number or Boolean is
wanted, when assigned a value of a type that neither is nor specializes its
own, and when compared with or chosen beside a value sharing no type with it;
a feature of unknown type is still trusted. A high and low surrogate escape
pair in a string spells the one character it encodes; a lone surrogate stays
refused.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
devin-ai-integration[bot]

This comment was marked as resolved.

… the clock's own scale

The Time library's Clock reads a point on the clock's scale, in seconds since
the run began, the same instant `accept at` waits for. Add a conformance case
that stores the read into a TimeInstantValue, subtracts two reads into a
DurationValue, waits at an instant derived from one and orders two instants,
and a robustness case that comparing the instant with a point on Time::UTC is
refused since the library binds the universal clock to no named scale.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
devin-ai-integration[bot]

This comment was marked as resolved.

… unary operand of **

A default in a language the translator reads is never re-read as v2 syntax
once the translator has refused it for a construct, call, name or type; only a
syntax or unsupported-language refusal falls back to the generic v2 parser.

The value of a typed pin or result is translated against the pin's scalar
type, so a Real expression on a Boolean pin is refused rather than written.

JavaScript rejects -x ** y (a unary operand of ** must be parenthesized), so
the translator refuses it; (-x) ** y, -(x ** y) and 2 ** -x still translate,
and a Java body's ** is refused since Java has no exponentiation operator.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
devin-ai-integration[bot]

This comment was marked as resolved.

… `/` to an exact Integer quotient

A dotted name that reads through a multi-valued feature or a swimlane representing a collection is a collection from that step on: arithmetic on it, a scalar assigned from it and any write through it are refused naming the carrier, and a call behavior action in such a lane runs in the caller's context, the report saying why. Only collection reductions (java.util.Collections.max/min) accept it.

A Java body's `/` over two whole numbers is written OpenSysMLMathFunctions::quotient(x, y), a new function of the non-normative extension library: the exact quotient truncated toward zero, ErrDivisionByZero for y == 0 and ErrArithmeticOverflow for the least Integer by -1 instead of an overflow through a Real intermediate. Parenthesized groups keep their precedence so (i + 1) / 2 is written without redundant parentheses; (-x) ** y keeps its own.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
devin-ai-integration[bot]

This comment was marked as resolved.

…ature's classifier and multiplicity

A translated opaque default or typed pin/result value was checked only against the feature's scalar base, so a value of a block or enumeration type went unchecked: a conditional choosing a Gauge could be written as the default of a Needle. The wanted type now carries the feature's scalar, its non-scalar type with generalizations, and whether it holds one value; a value of another family or a collection where one value is held is refused with a typed report note.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
devin-ai-integration[bot]

This comment was marked as resolved.

…mp a flow final's start

A DurationObservation whose event list names an element the document does not define was read as the one event that resolves, so a two-event observation with a dangling end became a single-node span. Unresolved event references are now checked before the resolved events are read, and the observation is refused with the dangling ids in the report.

A FlowFinalNode is the point a token ends, so an observation may start there: the edges into it lead to the stamp (through a merge when there are several) and then to done, and a duration constraint on it is written as its wait. A flag asking for a flow final's end is still refused, as for an initial node. Fixture acquisition.xmi covers both, end to end at run time.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
devin-ai-integration[bot]

This comment was marked as resolved.

Java declares Math.floor(double) and Math.ceil(double) as returning a double, so a Java / after them is real division; the translator typed both Integer and lowered Math.floor(x) / 2 to OpenSysMLMathFunctions::quotient. Java Math.round stays Integer, as its long result is. The meter fixture runs both at the boundary and the docs and changelog state the rule.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration Bot and others added 3 commits September 18, 2026 11:39
Java's == and != on String operands compare identity, which a v2 value
comparison does not reproduce; a Java body's equality with an operand
known to be a string is now a construct refusal, while a.equals(b) and
"x".equals(b) on strings translate to a == b, the comparison of content.
JavaScript string equality is unchanged.

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

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

# Conflicts:
#	tests/migrate/testdata/xmi/acquisition.golden.report.txt
#	tests/migrate/testdata/xmi/acquisition.golden.sysml
#	tests/migrate/testdata/xmi/acquisition.xmi
#	tests/migrate/testdata/xmi/meter.golden.report.txt
#	tests/migrate/testdata/xmi/meter.golden.sysml
#	tests/migrate/testdata/xmi/meter.xmi
#	tests/migrate/testdata/xmi/plant.golden.report.txt
#	tests/migrate/testdata/xmi/plant.golden.sysml
#	tests/migrate/testdata/xmi/plant.xmi
#	tests/migrate/testdata/xmi/reactor.golden.report.txt
#	tests/migrate/testdata/xmi/reactor.golden.sysml
#	tests/migrate/testdata/xmi/reactor.xmi
…behavior-migration

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

# Conflicts:
#	internal/core/migrate/activity.go
#	internal/core/migrate/behavior.go
#	internal/core/migrate/migrate.go
#	internal/core/migrate/states.go
#	internal/core/migrate/values.go
#	internal/core/xmi/xmi.go
#	internal/core/xmi/xmi_test.go
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration Bot and others added 2 commits September 19, 2026 01:14
…t; pin it by fixture

A pin is bound as a script variable by the tool, so a body's bare name that
matches a pin of the node is that pin, not a feature of the represented
object; the reference now lists pins first in the lookup order, and
acquisition.xmi has a node in the swimlane whose value pin Retries shadows
TCS::Retries, asserted written as the pin.

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

Re-homes the branch's runtime files under internal/exec/runtime and its migrate files under internal/translate/migrate, rewriting their imports to the new layer paths; no behavior changes.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration Bot and others added 2 commits September 19, 2026 19:14
…uments

Java's Math.max and Math.min take exactly two arguments, so a Java body calling them with one or three is a compile error there and is now a call refusal; JavaScript's are variadic and keep folding pairwise.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…aque-behavior-migration

Merge origin/feature/v1-state-interaction-fidelity (simulation configurations, results and probability; interactions, receptions, pseudostates, contexts and carriers) with the opaque-body, swimlane and clock-read migration.

Both sides' semantics are kept: the migration struct carries the union of fields; a translated opaque state behavior stays Approximated with its "written as v2 assignments" note; the REPL's missing-observable test follows the "no completed run ... produced a value" diagnostic; the branch-side region.go is dropped in favor of the populatedRegions in states.go; the stdlib snapshot is regenerated over the merged libraries.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@devin-ai-integration
devin-ai-integration Bot changed the base branch from develop to feature/v1-state-interaction-fidelity September 19, 2026 21:24
devin-ai-integration[bot]

This comment was marked as resolved.

@devin-ai-integration
devin-ai-integration Bot added this pull request to stack #455 September 19, 2026 21:38
…ble multiplicities

An English body has no calls: `Math.sqrt(t) > 3` or `name.equals(other)` in an English guard is a construct refusal, never dispatched to the script function table.

A script label is read only when every word of it names JavaScript, ECMAScript, JS, Rhino or Nashorn, plus at most one digit-led version; `JavaScript Expression Language`, `ECMAScript for XML`, `Rhino Shell` and `JSON` are languages the translator does not read, so their bodies stay comments.

A part whose multiplicity is not written in numbers (`1..n`) may hold one object or several: a name read through it, a swimlane representing it and a swimlane whose object is reached through it are refused with the part named, instead of being read as one object. `meter.xmi` covers each path end to end.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration Bot and others added 2 commits September 19, 2026 22:11
…the argument

JavaScript's Math.max(x) and Math.min(x) answer x itself, so the pairwise fold starts from the one argument after checking it is a number; only the no-argument forms, which answer an infinity the subset has no form for, are refused. A Java body still requires exactly two arguments.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…elity' into feature/v1-opaque-behavior-migration

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

# Conflicts:
#	docs/reference/sysml-v1-migration.md
#	internal/translate/migrate/activity.go
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration Bot and others added 2 commits September 19, 2026 23:34
… edge leaves

A decision, merge, fork or join with no outgoing edge ends the token as done
does, but the stamp a DurationObservation (or the wait a DurationConstraint)
placed on it was never written: the node had no entry, so every succession
into it led straight to done and the observation's attribute stayed blank.
Such a node now gets the lead-in a flow final has — the stamp, and a merge
when several edges reach it — before done.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…elity' into feature/v1-opaque-behavior-migration

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

# Conflicts:
#	internal/translate/migrate/activity.go
#	internal/translate/migrate/behavior.go
devin-ai-integration[bot]

This comment was marked as resolved.

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