fix(migrate): close v1 migration fidelity residuals in calls, results and run configurations - #481
Merged
Merged
Conversation
…n configuration A Cameo Simulation Toolkit result snapshot may carry the MagicDraw analysis pattern's MonteCarloAnalysis properties (N, Mean, Deviation, OutOfSpec) beside the observed values. Such a snapshot summarises N runs of the observable the analysis binds to Mean rather than recording one more run, so the migrator now keeps those properties out of the ordinary observables, records them as statistics of the bound observable, and reports metadata that is incomplete, non-integral, unbound, or of another configuration's observable. The -compare-results harness counts stored runs semantically, pools raw values and summary means, shows only the statistics a summary holds, runs configurations that store no result with an explicit 'no stored result to compare' row, and defaults a missing numberOfRuns to one run, as the tool does. Co-Authored-By: jason.han <hanhuijun@gmail.com>
A case body's action flow waited on the clock for its own accept after, but the clock did not know its waits, so a timed step in an analysis or verification case deadlocked. The flow is attached to the clock for the run. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…'s waits A case's action flow was put on the clock by every run of its body, so a case performed as a step of an action body and an ordinary calc usage were clock waiters of their own. Now a run with no body to pause puts the flow on the clock for the run only, and a body performing the case pauses on the step while its executor lists the case's waits among its own, resuming the step when the instant comes; the calc depth and running mark are held for a call into the body, not across its pauses, so a paused case can be snapshotted. An expression reading a case's output takes the case whole: a wait under it is the typed ErrCaseReadWaits rather than a stale running mark. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…r classifier A result location may hold snapshots the tool named after a classifier that is neither the configuration's execution target nor a general or special of it; they are runs of another configuration stored in the same package, so they are not read as the configuration's results and the sidecar says so. The sidecar also carries the notes saying why a configuration runs no behavior. Co-Authored-By: jason.han <hanhuijun@gmail.com>
A call passing no argument, or a pin no flow feeds, for a required parameter was written as a placeholder performing nothing. v1 runs the callee with the parameter unset, so the parameter or pin is now declared admitting no value ([0..upper]) and the call is performed; the absence propagates through pins, nested activity outputs and method parameters, and writes of a required feature from a value that may be absent are guarded. Sends of a signal whose required attribute gets no value keep refusing. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…aviors and report constraint blocks per rule Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
…ity-residuals Co-Authored-By: jason.han <hanhuijun@gmail.com> # Conflicts: # internal/frontend/repl/compare.go # internal/translate/migrate/activity.go # internal/translate/migrate/results.go
Binding ends written at an action node are statements of the body, so a name there resolves to the enclosing action's parameter before the performer's same-named feature. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…location of a behavior-less call Co-Authored-By: jason.han <hanhuijun@gmail.com>
…urations on the tool's A run's clock can step by a fixed number of seconds (-clock-step, %clock-step, Question.ClockStep, the engine wire's clockStep), on which every wait comes due at the first tick not before its end; a witness records the step and replays on it. A migrated SimulationConfig stating startTime ran on the tool's internal clock, so the results sidecar records its stepSize in timeUnit as clockStep and -compare-results runs the configuration on it. Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
…otes Co-Authored-By: jason.han <hanhuijun@gmail.com>
Contributor
Author
|
I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".
|
… statistics as none, bound clock tick rounding A console print whose argument assigns, counts or calls anything but a value-computing function of the table is refused rather than left out. A MonteCarloAnalysis statistic that is no number (a string, NaN, several values) is noted and the snapshot holds no statistics instead of zeros. The rounding a clock wait allows onto a tick is bounded at a millionth of a tick, so a wait at a large time never fires on the tick before it. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…s and string-only Java equals A summarising snapshot's OutOfSpec is carried into the sidecar and a missing Deviation stays absent instead of reading as zero: Statistics.Deviation and OutOfSpec are optional, written only when recorded, and Disagrees judges nothing without both deviations. An OutOfSpec that is no count of the runs is noted like any malformed statistic. A clock step so fine that t/step overflows a float64 no longer queues an infinite wait: onTick leaves such an instant as it is, and a tick past the last finite instant is refused before the wait is queued. A Java equals in a console print counts as a pure call only on a receiver known to be a string (a literal, or a feature or local declared String); any other type's equals is that type's own method and refuses the print. The expression translation of equals applies the same receiver rule. Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
…ing-end names in the body A result location outside the document, or one holding no snapshot of the target's classifier, was noted in the migration report but dropped from the configuration's results, so the sidecar gave no reason for its missing snapshots. The notes now reach ConfigurationResults.Notes as well. A binding end written at a node of a performed action resolves a simple name in the body's scope first — the enclosing action's parameter before a same-named feature of the performing part — and a pin valued by its own name reads the feature it masks around the owning usage rather than itself. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…assed instant under a step A stepSize whose unit conversion overflows to infinity leaves the clock continuous with a note instead of writing Inf into the sidecar; a MonteCarloAnalysis::N of 2^63 or more is a malformed statistic instead of a negative int64 run count; and an absolute instant the clock has already passed comes due at the current instant rather than being rounded onto the next tick of a step set while the clock stood between ticks. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…an underflowed clock step from reading as continuous Co-Authored-By: jason.han <hanhuijun@gmail.com>
…nts and empty-effect braces under the fidelity residuals Empty transition effects keep the braced form the migrator now writes, and the input pins the primitive mappings declare optional take their approximation notes; both goldens and the compliance record follow. Co-Authored-By: jason.han <hanhuijun@gmail.com>
devin-ai-integration
Bot
changed the base branch from
develop
to
feature/fuml-alf-primitive-behaviors
September 21, 2026 15:53
… into fix/migrator-fidelity-residuals
…iors' into fix/migrator-fidelity-residuals
…ad no ownership into a coincident Mean A snapshot whose slots are of features of the configuration's target lineage is a snapshot of a run on it whatever its name says; only a name after a special of that lineage, which its slots leave open, sets it aside as a run on the special. A snapshot whose Mean an unrelated observable happens to hold is no longer set aside as another configuration's: the statistics are not read and a note says which observable the analysis binds, as a numeric coincidence is no evidence of the run's configuration. Co-Authored-By: jason.han <hanhuijun@gmail.com>
… into fix/migrator-fidelity-residuals
…ol clock's step and note its start The simulation toolkit's default time unit is the millisecond, so a bare duration constraint, time event or SimulationConfig step is scaled from milliseconds, with the reading noted; a unit is read as before, and the toolkit's unit spellings (m, wk, millisec, microsec, nsec) are known. A SimulationConfig stating no stepSize but an endTime and a numberOfSteps ran on the step the tool derives, (endTime - startTime) / numberOfSteps. A startTime other than 0 started the tool's clock where a run's does not, so it is noted, in the report, the sidecar and the comparison, as offsetting every instant read on the clock. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…iors' into fix/migrator-fidelity-residuals
… into fix/migrator-fidelity-residuals
Co-Authored-By: jason.han <hanhuijun@gmail.com>
… into fix/migrator-fidelity-residuals
Base automatically changed from
feature/fuml-alf-primitive-behaviors
to
develop
September 21, 2026 20:05
…eral slots Co-Authored-By: jason.han <hanhuijun@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
The SysML v1 → v2 migrator, its
-migration-resultssidecar and the-compare-resultsharness lost fidelity on large Cameo Simulation Toolkit models in ways that were all general: a call whose required input receives no value was replaced by a placeholder performing nothing, result snapshots were matched to a configuration by package proximity rather than by the execution target's classifier, Monte Carlo summaries were read as single runs, configurations with no stored snapshot or nonumberOfRunswere skipped or refused, parametric configurations were refused with a blanket message, and a few runtime defects (a case body's timed steps off the clock, a bodyless state behavior refused, a state machine's poll of the signals in flight re-done at every step) surfaced only on such models. Every change is expressed in UML/SysML v1 semantics, the MagicDraw profile (by namespace provenance) or the Simulation Toolkit's conventions; nothing is keyed to a particular model.Migrator (
internal/translate/migrate)[0..upper], the call is performed, the absence propagates through pins, nested activity outputs and method parameters, and a write of a required feature from a may-be-absent one is guarded withif x->notEmpty(). A send of a signal with a required attribute unset still stands in for itself. The report says per parameter/pin why a value may fail to reach it.Probability(recognised by the namespace its application is serialised under, as every standard stereotype is) weights a decision's branches; a same-named stereotype from another profile weights nothing and the report says which profile it comes from:«Probability» from <profile> is not the SysML profile's; its probability is not read. Missing values, unmarked-branch remainders, scaling and out-of-range values behave as before. See the note under Leakage audit on why the gate is the SysML profile's namespace and notSimulationProfile's.print(…),println(…),System.out.print[ln](…)statements change nothing of the model, so they are omitted (each noted as an approximation) while the rest of the body is translated; a body of prints alone becomes an empty action. A print whose argument assigns, counts or calls anything but a value-computing function of the table is refused rather than left out; a Javaequalscounts as such a function only on a receiver known to be a string (a literal, or a feature or local declaredString), any other type'sequalsbeing that type's own method. Other unknown calls are still refused.simconfig.go): the execution target's classifier behavior is resolved through generalizations; a target with no classifier behavior whose parts hold constraint properties is reported per constraint property (which constraint block, whether its rule is a migrated constraint or which call of an opaque rule stops it) instead of a blanket refusal;treatAllClassifiersAsActive = falseandautostartActiveObjects = falseare typed notes;startTime/stepSize/timeUnitbecome the sidecar'sclockStep.VerdictKindliteral is reported precisely as the run's verdict rather than an instance of the slot's type.do action logand no longer leaves a dangling;beforethen.Result sidecar and comparison (
internal/translate/simresults,internal/frontend/repl/compare.go)MonteCarloAnalysissummaries (N,Mean,Deviation,OutOfSpec) become the snapshot'sstatisticsof the observable the analysis binds, standing forNruns —deviationandoutOfSpecare written only when the snapshot records them, so a summary without aDeviationstates none rather than a zero and the disagreement test needs both deviations; a statistic that is no number, or anOutOfSpecthat is no count of theNruns, is noted and the snapshot read as an ordinary run; raw values and summaries are pooled by run count.tool (no stored result to compare)row; one with nonumberOfRunsruns once with a note (the tool's default); refusals name the configuration.Runtime (
internal/exec/runtime,internal/ir/lower)analysis_steps_wait_on_clock,action_case_step_waits_on_clock; typedErrAcceptDeadlock/ErrCaseReadWaits).-clock-step <seconds>/%clock-step: a fixed-step clock on every engine, the external-engine protocol (clockStep) and gRPC; witnesses record and replay it. A wait comes due on the first tick not before its instant, within a rounding tolerance capped at a millionth of a tick; a step so fine that the tick count overflows a float64 leaves the instant as it is, and a tick past the last finite instant is a typed error before the wait is queued.entry action hello;,do action log) lowers to an empty body and executes as nothing (state_behavior_action_of_no_content).Specification basis
SysML 1.6 §11.3.2.1 (
ProbabilityonActivityEdge/ParameterSet) and §11.3.1.2 (standard stereotypes keyed by profile); UML 2.5.1 §16.2 (anInputPin/Parameterwith lower bound 0 admits no value; aCallBehaviorActionwith an unset argument still executes) and §14.2.3.4 (an entry/exit/doBehaviorof no content); SysML v2 KerML 8.4.4 ([0..1]multiplicity on features), SysML v2 §7.16 (state behaviors as action usages), §7.20 (analysis/verification case steps on the clock).docs/project/spec-compliance.mdgains rows for the bodyless state behavior, the case body's timed steps and the fixed-step clock; no row moves down.How it was verified
Gates, all green locally:
make build,make test,make lint,make docs-check,python3 scripts/changelog.py check,python3 scripts/check-doc-ids.py,make man-check,gofmt -l .(empty),go vet ./..., and with the three corpora downloadedOPENSYSML_REQUIRE_TRAINING_CORPUS=1 OPENSYSML_REQUIRE_PILOT_CORPORA=1 OPENSYSML_REQUIRE_PILOT_LIBRARY_XMI=1 go test -count=1 -race ./...(80 packages ok;training_examples_expected.txtunchanged; no ratchet moved).Second-fixture proof of each mechanism (hand-written, non-benchmark XMI under
tests/migrate/testdata/xmi/or runtime conformance fixtures)[0..upper]propagation, guarded writes; allocated behavior-less call stays unresolvedtests/migrate/arguments_test.go;meter.xmigoldensTestCallsWithoutRequiredArgumentsAdmitNone,TestAllocatedCallsWithoutBehaviorStayUnresolved,TestConstructFixtures/meterweighted_decision.xmi(+ goldens)TestWeightedDecisionReadsOnlyTheSysMLProfilesProbability, inline cases intests/migrate/behavior_test.godo action logplant_states.xmi(+ goldens); inline bodies inopaque_migration_test.gotests/migrate/states_test.go,tests/migrate/opaque_migration_test.go,internal/translate/migrate/opaque_test.gomontecarlo.xmi(+ goldens); sidecars ininternal/frontend/repl/compare_test.goTestMonteCarloAnalysisSnapshotsAreSummaries,TestDisagreeingSummaries,TestComparisonTablePoolsSummarisedResults,TestCompareNotesSnapshotsStoredTwice,TestSummarisedMigrationResultsThroughCLIclockStepfromstartTime/stepSizetests/migrate/simconfig_test.goTestSimulationConfigReportsWhatItCannotRun,TestSimulationConfigPerformsATestCaseClassifierBehavior,TestSimulationConfigNamesTheConstraintsOfAParametricTarget,TestSimulationConfigRecordsTheClockStepOfTheToolsInternalClocknumberOfRunsdefaults to one run; refusals name the configurationinternal/frontend/repl/compare_test.goTestCompareRunsConfigurationsWithoutStoredResults,TestCompareDefaultsToOneRun,TestCompareNamesTheConfigurationItRefusestests/migrate/values_test.goTestConstraintSlotHoldingAVerdictIsUnmappedAsOneanalysis_steps_wait_on_clock.sysml,action_case_step_waits_on_clock.sysml(+ trace goldens)TestExecutionConformance,TestExecutionTrace,TestRuntimeRobustnessCaseClockWaitclock_step_waits_come_due_on_ticks.sysml(+ trace golden)TestExecutionConformance,TestRuntimeRobustnessClockStep,internal/exec/runtime/clock_step_test.go,internal/frontend/repl/clock_step_test.gostate_behavior_action_of_no_content.sysmlTestExecutionConformanceTestExecutionTrace,tests/perfBenchmark model (Cameo Simulation Toolkit model, 44,136 elements) — used only as a test bench
Counts: before 28,626 mapped / 10,319 approximated / 5,191 unmapped → after 28,389 mapped / 10,556 approximated / 5,191 unmapped; validation errors 0 → 0. (275 elements moved from mapped to approximated — almost all input pins and parameters now declared admitting no value, with the reason a value may fail to reach them — and 38 the other way: object flows, decision nodes and run configurations that are now mapped outright.)
-compare-results -seed 1, all 62 configurations (before: 14 compared, 32 silently skipped for lack of a snapshot, 11 refused as "performs no migrated behavior", 5 refused for nonumberOfRuns; after: 41 run, 21 refused with a per-configuration reason). Means of the numeric observable(s);n/a= the tool stored no result, so only our statistics are printed.uninitialized feature value: alternatives(trade-study driver reads a feature nothing sets)tBB1/tFinal/tM3Align/tNB_Results0 vs 612/3712/67.75/56.5)aPS Mission Logical,analysisDriver), no numeric observablet*_Results0)[1]pinSend Ackwaits for the clock, which only a do behavior mayControl::finish; the tool's run is interactive)treatAllClassifiersAsActive = falsehas no v2 form (typed note); the target's classifier behavior is a state machine, which a run performs as no actionResiduals closed (mechanism in parentheses): 1 result-location wiring (snapshots matched by the target's classifier and by the observable the analysis binds; a snapshot of another observable or a copy of another configuration's is a typed note rather than a comparison of the wrong number); 2 identical dither groups — partly (the calls whose required inputs get no value are now performed, so Group 2 differs from 0/1/4; 0/1/4 remain identical, see below); 3 the +33 % IRIS/NFIRAOS Group 0 gap (calls with unset required inputs performed; the tool's four stored summaries for this configuration disagree by more than three standard errors, which the harness now says); 4 blanket "performs no migrated behavior" (per-constraint-property report, inherited classifier behaviors, interaction/state-machine classifier behaviors named); 5 no
numberOfRuns(defaults to one run with a note); 6 no snapshot (run and printed with ano stored resultrow); 7 opaqueALH.*/console prints, bodyless state behaviors,treatAllClassifiersAsActive,VerdictKindslots (generic fixes or precise typed notes).Remaining, with cause:
Time_Acq_Totalrather than of the observable its analysis binds (set aside, reported); neither target has a stored result of its own.t*_Resultsof the APS duration analyses (0 vs 612/3712/…) — runtime gap, reported per action: the duration comes from opaque JavaScript actions beyond the translated subset (ALH.inState,ALH.createList, lookup-table reads) which stay as refused opaque actions.Send Acktransition effects (Reference Point Tracking, Pre-Session Calibration) — no v2 equivalent: a transition effect cannot wait on the clock (only a do behavior may); typed runtime error.Leakage audit
rg -n -i 'tmt|Time_Acq|Time_Dither|IRIS|NFIRAOS|WFOS|ProbabilityAcq|Retries|GS_Found' internal --glob '!*_test.go' --glob '!**/testdata/**'returns only generic hits:stmt/Stmt(statement identifiers incodegen,migrate,runtime),IRIs/iris(RDF IRIs intranslate/rdf,export,interop) and the English verb "retries" in four comments. No benchmark element, package, observable, property name or numeric shape appears in non-test code, docs or changelog.«Probability» provenance: in the benchmark model all 83 «Probability» applications are serialised under the OMG SysML profile namespace (
http://www.omg.org/spec/SysML/…/SysML), none underSimulationProfile—Probabilityis a SysML 1.x standard stereotype, not a Simulation Toolkit one, so the gate is the standard-profile namespace (the same check the migrator applies to «Block» etc.), notisSimulationProfile, which would have dropped every weight. With the gate in place the model's 187@Stochastic::Probabilityannotations and its report entries are byte-identical to the pre-gate output (0 foreign-profile notes); the foreign-profile case is proven onweighted_decision.xmi, where a same-named stereotype fromhttp://example.com/routing/profileis not read and its edge falls back to the remainder weight.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 changelog