Skip to content

fix(runtime): interleave executors due at one instant move by move - #850

Merged
HuiJun merged 9 commits into
developfrom
fix/explore-executor-turns
Oct 7, 2026
Merged

HuiJun merged 9 commits into
developfrom
fix/explore-executor-turns

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

What and why

Executors due at one instant (two actions, an action and a state machine, two machines) are unordered, but under explore, check, replay and seed:<n> the executor drawn from the due order ran all its work at the instant before any other could move. Two actions that each read a shared counter and then write it never reached the lost update: both reads before either write.

The executor drawn now makes one move, then keeps its turn only while its next move is independent of everything each other due executor may still do at the instant; otherwise the due order is drawn again.

runDue / runTurn:
  owner := pickDue(due)
  loop:
    owner.runMove()
    if !owner.dueWork() || ctx.contended(owner): redraw
yieldTurn redraws when contended(driver) || endContended(driver)
contended(w)    = nextFootprint(w).DependentBy(futures.executorFuture(rival), ctx.relation(w, rival)) for some rival
endContended(w) = mayEnd(w) && some rival may still move   // an end observes every place
  • future_footprint.go: an executor's future at the instant is everything it may still do, stopped only at a wait on a literal delay that resolves past the instant. gate() gathers every send any executor may make at the instant; a machine's future then leaves out a transition whose signal no queued message carries and no gathered send can meet (cannotFire), unless some executor may send anything.
  • message_dependence.go Context.relation + lower.Footprint.DependentBy(g, rel): two executors on two objects commute on direct accesses to features each object holds itself (Relation.Held); a send naming no target (Channel.Own) meets no consumer run for another object. A send and an accept, or two accepts, are separated only where both signal types resolve statically and do not conform; an unresolved type, a via route, an unresolved receiver or port, and a dispatch that may drop the message all stay dependent.
  • advance.go Context.endContended: a move that may end the driver's performance (an action token past no unguarded succession, out of a nested frame, or reaching beyond its node; a machine that can complete or terminate) yields to any rival still able to move, since the run's outcome is read at that end.
  • -engine check holds the same turn: invocationRun.turn limits the enabled moves to the held executor, is part of the canonical state (turn: line) and is saved and restored with each frame. The persistent-set reduction uses the same DependentBy with the same relation, and persistentClosure.include now follows future dependence from every unit it adds, enabled or not; a do behavior stepping a stated flow contributes that flow's token footprints.
  • StateExecutor.runMove reports whether the machine ran a unit at all, not only whether it bumped the event or do-step counters, so resuming a held entry or completing the machine counts as its move and a turn goes on through the rest of the instant's work.
  • A callee a body performs that pauses at its start-shot move is marked held, as one paused on its waits already is, so the clock leaves it to the body that resumes it instead of running it as a due executor of its own.
  • declared and reverse keep their order: the executor drawn runs its work at the instant through (scheduler.interleavesTurns).

Specification basis

Kernel Semantic Library Clocks.kerml / Occurrences.kerml: two performances waiting on the same TimeInstantValue are HappensBefore-linked by nothing, so their steps interleave. The spec-compliance.md rows for executors due at one instant and for the model checker's moves now describe move-by-move turns; both stay Faithful.

How it was verified

  • New cmd/sysml/explore_turns_test.go:TestExploreRunsAHeldEntryAsAMove: a held entry cascade with a Go queued behind it and an action reading what the cascade writes. Every explored and seeded run dispatches Go at the instant (inner+b), and explore reaches the read between the cascade and the dispatch (order = 12; seen = 1).
  • New cmd/sysml/explore_turns_test.go:TestExploreInterleavesExecutorsMoveByMove: the read-then-write pair reaches 3 outcomes under explore (complete) and check (witness replayed), seeds 1..12 reach all three, and declared/reverse keep seen = 0, seen = 1 / seen = 1, seen = 0. It fails on develop (2 outcomes, no seed reaches the lost update).
  • Check's reduction: TestCheckReductionIsSound passes (reduced finals equal unreduced). Final outcome sets over the reduction corpus against develop: unchanged in 17 models, strictly larger in 2 (por_state_send_accept +1, por_state_join_exit +6), none lost.
  • The spacecraft showcase (runs=500), TestExploredRunsAreGivenOneObjectPerInstantiate and TestExploredPathsAreCheckedAgainstTheDeclarations reach their develop outcomes at their unchanged budgets.
  • go build ./..., go vet ./..., gofmt -l ., go test ./... (pilot library XMI downloaded), go test -race ./internal/exec/runtime/..., make lint, python3 scripts/changelog.py check pass. make docs-check fails only on docs/project/third-party-notices.md linking docs/assets/landing/libavoid-js.LICENSE.txt, which develop does not carry either.

Expectations that moved

Test develop This branch Why
reduction_expected.txt por_state_effect_write, por_state_guard_read 17 18 17 18 15 16 17 20 same finals; reduction now separates a turn's moves
por_state_do_write 34 36 34 36 46 50 56 68 same finals; each do step is a move the read depends on
por_state_send_accept 9 9 9 9 13 13 13 13 one more final outcome
por_state_join_exit 72 72 72 72 96 108 102 120 six more final outcomes
por_state_join_guard 26 24 26 24 34 38 36 42 same finals; more interleavings of the join's guard
por_constructor 19 21 19 22 18 21 18 21 same finals; constructors on two objects commute
repl explore Comms::Craft::ack 2 outcomes, complete 3 outcomes, complete new seen = 1; sent = 2: look reads sent before tx's count at t=3, which then runs before ack ends
cmd/sysml nested linked pair (explore, machine alone and siblings) complete (4 runs): received = 1 ×3, received = 2 ×1 complete (5 runs): received = 1 ×4, received = 2 ×1 same 2 outcomes; the received = 2 witness draws the due order at t=3 twice
repl linked pair RunFor complete (4 runs) complete (5 runs) same outcomes
lamp explore -advance (run_test, repl) complete (2 runs) complete (3 runs) same outcomes
lamp -engine check peek+glow 10 states, 9 moves, witness of 1 choice 9 states, 8 moves, witness of 2 choices same divergence (saw false or true); the witness names the turn's redraw

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

Link to Devin session: https://nasa-jpl-demo.devinenterprise.com/sessions/5344039f62464badb7a0a648e6384b08
Open in Devin Desktop: https://nasa-jpl-demo.devinenterprise.com/desktop/session/5344039f62464badb7a0a648e6384b08?variant=devin
Requested by: @HuiJun

@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 Bot and others added 3 commits October 3, 2026 18:05
…nd a move that may end a run

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

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

# Conflicts:
#	cmd/sysml/check_engine_test.go
#	internal/exec/runtime/advance.go
#	internal/exec/runtime/model.go
@devin-ai-integration
devin-ai-integration Bot marked this pull request as ready for review October 3, 2026 22:29
devin-ai-integration[bot]

This comment was marked as resolved.

…erleave

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

Copy link
Copy Markdown
Contributor Author

This branch now conflicts with develop. Conflicting files, and the merged PRs that changed them:

To resolve: merge current develop into this branch with an ordinary merge commit (no rebase or force-push).
Reconcile the code conflicts with #864's statement-order scheduling (calc, constraint and case-step bodies) rather than taking one side; a conflict that needs a design decision should be raised on this PR, not guessed.
Regenerate reduction_expected.txt with its test's update flag after the code merge rather than hand-merging it.

Planned merge order for the execution PRs: #844 → #850 → #838 → (#851 → #853 → #857) → #830 → #833 → #842 → #837 → #834 → #816.

Re-run the full gate (go build ./..., go vet ./..., gofmt -l ., make lint, make docs-check, go test ./...) and wait for green CI before marking ready.

…or-turns

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

# Conflicts:
#	docs/project/spec-compliance.md
#	internal/exec/runtime/model.go
#	internal/exec/runtime/scheduler.go
#	internal/exec/runtime/testdata/check/reduction_expected.txt
#	internal/ir/lower/footprint.go
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

Hold on pushes: please don't push to this branch, including develop merges or empty commits to retrigger CI, until a maintainer says the CI runners are free. Prepare the conflict resolution locally and push it then.

@HuiJun
HuiJun merged commit 4280028 into develop Oct 7, 2026
24 checks passed
@HuiJun
HuiJun deleted the fix/explore-executor-turns branch October 7, 2026 16:42
devin-ai-integration Bot added a commit that referenced this pull request Oct 8, 2026
…ock_flow_typed_node

Per #850's statement-order rule, direct statements without then are unordered; the fixture orders the output read after the typed node.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
HuiJun added a commit that referenced this pull request Oct 10, 2026
* fix(lower): perform inherited action steps and inherit step multiplicity

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

* fix(lower): prefer owned action successions when merging inheritance

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

* fix(runtime): merge typed action bodies without forwarding writes past the performance

Remove name-based write forwarding from invoked actions, observe state and
classifier perform bodies through bound inout pins, run state entry flows
stepped under one-move schedulers so check sees their token-order choices,
and record the open outcomes of typed nodes whose own statements race the
callee's steps.

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

* docs(changelog): describe inherited action steps from the user's side

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

* docs(changelog): name inherited-step examples without probe labels

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

* fix(lower): bound typed-body merging of actions nested in their own type

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

* refactor(lower): remove dead code flagged by staticcheck

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

* fix(lower): thread the resolver into block flows and refuse clock waits in stepped entry behaviors

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

* refactor(lower): group succession edge lowering fields

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

* fix(ir): preserve inherited assertions and pin bindings

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

* fix(lower): preserve unchecked inherited assertions

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

* fix(lower): carry ordered assertions through action inheritance

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

* fix(runtime): sequence nested typed action output reads

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

* fix(lower): preserve inherited succession flow gates

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

* fix(lower): let a specialization's own flows connect inherited steps

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

* fix(lower): resolve inherited gates in their declaring scope

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

* test(lower): sequence inherited action fixture steps

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

* fix(lower): retain inherited case-step lowering

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

* fix(lower): let a specialization's pin binding replace the inherited one

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

* test(runtime): order the typed-node output read with then in state_block_flow_typed_node

Per #850's statement-order rule, direct statements without then are unordered; the fixture orders the output read after the typed node.

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

* fix(client): restore generated Java protobuf sources byte-for-byte

The develop merge stripped trailing whitespace protoc emits in ExecuteStateResponse and its OrBuilder, so the proto-buf drift check regenerated a diff. Restore the generated output.

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

* fix(lower): keep a differently guarded inherited succession alongside an owned one

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

* chore(changes): drop fragment for a fix that never shipped

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

* fix(lower): keep the binding of inherited pins on bodied typed usages

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

* fix(lower): keep inherited successions whose end multiplicities differ

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

* test(runtime): cover inherited content in composite redefining steps

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

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: jason.han <hanhuijun@gmail.com>
HuiJun added a commit that referenced this pull request Oct 10, 2026
…ries

* fix(lower): perform inherited action steps and inherit step multiplicity

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

* fix(lower): prefer owned action successions when merging inheritance

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

* feat(runtime): execute repeated steps in block flows, part performs, reads and bindings

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

* test(parser): add parse goldens for repeated steps in loop bodies and on parts

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

* fix(runtime): give each repeated part performance its own occurrence

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

* fix(runtime): merge typed action bodies without forwarding writes past the performance

Remove name-based write forwarding from invoked actions, observe state and
classifier perform bodies through bound inout pins, run state entry flows
stepped under one-move schedulers so check sees their token-order choices,
and record the open outcomes of typed nodes whose own statements race the
callee's steps.

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

* docs(changelog): describe inherited action steps from the user's side

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

* feat(runtime): execute repeated steps adjacent to control nodes and guarded successions

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

* fix(runtime): observe change-trigger conditions at every feature write

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

* feat(lower,runtime): run effects and pseudostate routes of transitions out of the entry action

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

* test(runtime): admit both composite-entry interleavings

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

* docs(changelog): name inherited-step examples without probe labels

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

* feat(smt): encode exact repeated action steps

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

* test(parser): add parse golden for a guarded succession's written target end

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

* fix(smt): refuse the repeated-step shapes CheckStep refuses

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

* docs(project): record repeated-step coverage in the semantic oracle and compliance map

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

* fix(lower): bound typed-body merging of actions nested in their own type

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

* fix(ast): encode the written target end of a succession through the codec

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

* docs(states): derive entry-transition effects and write-granular change triggers, adjudicate PSSM movements

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

* fix(export): carry a guarded succession's written target end

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

* refactor(lower): remove dead code flagged by staticcheck

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

* fix(check): keep the accepter-source diagnostic for a triggered transition out of an entry action

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

* docs(states): name the accepter rule for a triggered transition out of an entry action

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

* fix(runtime): credit a synchronization to the token whose try performed it

A join reached per performance consumes the earliest sibling arrival and
mints the token that performs it, so the tried token neither moves nor
changes the token count and the step looked unacted. Compare the token-ID
counter before and after the step too, so the explore slot and the check
replay see the synchronization as that token's act. Pin every checkable
repeated-step conformance case with a check expectation; a case with a
check expectation may carry an explore budget without outcomes.

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

* fix(smt): spend a move on a repeated step's split

The runtime reaches a repeated step in one step, splits the token into its
siblings in the next, then performs the step in a third. The encoding
placed the siblings on the arriving move, compressing the split into the
arrival, so every witness step and choice was off by one and witnesses
would not replay. Arrivals into a repeated step now land the token pending
and the next move mints its siblings, mirroring the runtime, and the SMT
witness tests pin that violated properties over repeated steps replay.

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

* chore(workspace): regenerate the stdlib snapshot for the succession target ends

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

* fix(runtime): perform every target of several successions out of an ordinary action node

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

* docs(skills): note fan-out CLI checks in the REPL testing skill

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

* fix(lower): fix a control node's count to a repeated step's only where the successions derive it

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

* fix(exec): report repeated steps in block bodies as observed rather than proved or bounded

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

* docs(project): derive control-node and block-body repeated-step semantics from the spec

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

* chore(ci): re-run checks after a transient Reference-FMUs download failure

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

* fix(runtime): read entry-route junctions before the entry effect, keep choices open and alternatives disjunctive

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

* refactor(runtime): drop the dead choice branch from defaultEntryRouteAvailable

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

* fix(lower): read an unwritten control node's count as one unless its ends force the repeated step's

A control node that declares no multiplicity takes the executor's
one-performance reading beside a repeated step, so a written [*] into a
fork or decision is a barrier and a written [*] out of a join or merge
fans out. The four derived crossings — a bijective crossing into a join
or out of a fork, the lone incoming edge of a merge, the lone outgoing
edge of a decision — still fix the node's count to the step's, and a
merge or decision carrying another succession is unsatisfiable under
count one through the mandated 0..1 ends.

Restores the fork-barrier, decision-barrier and merge-fanout
conformance fixtures to running, and the corresponding SMT witness and
outcome cases. The conformance README notes that an exploration budget
raise is pinned for completeness only and never changes a standing.

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

* docs(project): describe the one-performance reading for unwritten nodes beside repeated steps

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

* fix(lower): thread the resolver into block flows and refuse clock waits in stepped entry behaviors

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

* test(conformance): pin the merge per-performance exploration budget

The default 1024-run budget leaves the check-agrees exploration of the
merge per-performance fixture incomplete; raise it like the join
per-performance fixture's.

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

* fix(smt): keep the token's identity when one succession out of an ordinary node is enabled

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

* refactor(lower): group succession edge lowering fields

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

* test(smt): keep the one-guard fan-out referee case within the solver budget

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

* fix(runtime): read a nested default entry's junction when its entry transition is taken

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

* test(runtime): make the outer-effect entry junction fixture discriminating

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

* docs(states): state the outer-effect entry junction fixture without reference to earlier behavior

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

* test(smt): restore the false-guard writer and give its referee case a solver budget

The one-guard fan-out fixture again assigns x := 3 in q, so an engine that ignores
the false guard reaches an outcome the set does not admit.

The referee's completion query over the default 40 moves takes z3 about a minute
locally (unsat, not unknown), and on CI it ran past the five-minute referee timeout.
Every run of the case ends within 12 moves, and the solve time is heavy-tailed in
the unrolling rather than in the model, so the case states "solverBudget":
{"moves": 20}. The completion query still proves every run ends within that bound.

Both fixtures with an admissible set that the fork-identity fix added gain the
check expectations TestCheckConformanceOracles requires.

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

* fix(smt): land a fork's token pending at a repeated target so its split makes the siblings

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

* fix(runtime): capture coverage notes in snapshots and fold them during the check search

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

* fix(exec): prune a literal-false succession into a single performance instead of refusing it

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

* fix(exec): return every direct behavior match so repeated performances stay ambiguous

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

* docs(project): note the pending fork landing at a repeated target and the pruned single-performance guard

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

* fix(ir): preserve inherited assertions and pin bindings

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

* fix(lower): preserve unchecked inherited assertions

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

* fix(lower): carry ordered assertions through action inheritance

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

* fix(runtime): sequence nested typed action output reads

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

* fix(lower): preserve inherited succession flow gates

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

* fix(lower): let a specialization's own flows connect inherited steps

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

* fix(lower): resolve inherited gates in their declaring scope

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

* test(lower): sequence inherited action fixture steps

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

* feat(libs): pin and sync the vendored extension libraries from OpenSysML-Extensions-Library

The extension libraries live upstream; scripts/sync-extension-libraries.sh vendors the pinned commit, --check fails CI on drift, and engine-contract.json records the qualified names the engine binds.

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

* test(libs): hold the runtime registry and bound names to engine-contract.json

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

* ci,docs: extension-libraries drift check, advisory upstream workflow, and the new library home

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

* fix(contract): re-pick extensions pin; reject duplicate manifest entries; name all 14 libraries in README

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

* docs: exclude the extension-libraries engineering record from the built site

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

* fix(libs): refuse an upstream without engine-contract.json; test the tools module in the upstream job

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

* chore: retrigger pull request checks

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

* chore(libs): pin the extension libraries to the merged Extensions-Library main

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

* chore: retrigger pull request checks

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

* fix(lower): retain inherited case-step lowering

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

* test(runtime): state every interleaving of a repeated step's unordered body statements

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

* fix(runtime): keep change-condition read sets across snapshot restore

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

* fix(lower): let a specialization's pin binding replace the inherited one

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

* test(runtime): order the typed-node output read with then in state_block_flow_typed_node

Per #850's statement-order rule, direct statements without then are unordered; the fixture orders the output read after the typed node.

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

* fix(client): restore generated Java protobuf sources byte-for-byte

The develop merge stripped trailing whitespace protoc emits in ExecuteStateResponse and its OrBuilder, so the proto-buf drift check regenerated a diff. Restore the generated output.

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

* test(check): expect open order for a repeated step in an unordered inherited loop body

The repeated-step coverage change lifts the block-body multiplicity refusal, so a repeated step in a loop body is refused only when its body states no succession: the inherited [2] case now expects the order-open finding, and an ordered inherited loop body is covered as supported at both the pass and the runtime (tick performs its inherited count per pass).

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

* fix(parser): read a guarded succession's written target end through the transition member

A keywordless first a if g then [m] b matches atMultiplicityFirstSuccession (the then-[ probe fires before the guard check), so it fell into the succession-usage parse and errored instead of reaching parseTransitionMember's then-[m] handling. An if at depth 0 before then means the member is a GuardedSuccession: bail so the guarded-succession dispatch reads it.

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

* test(semantics): expect both guarded-succession spellings as transition members

The keywordless first a if g then [m] b is a GuardedSuccession and parses as a TransitionMember like the succession-keyword spelling, so both edges are counted there instead of one under InitialNode.

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

* test(smt): expect the inherited repeated-step count to encode

A redefining step declaring no multiplicity takes the redefined step's [n], and the effective count is encoded like a declared one, so the inherited-step case is a count test rather than a refusal test.

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

* fix(lower): keep a differently guarded inherited succession alongside an owned one

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

* chore(changes): drop fragment for a fix that never shipped

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

* fix(smt): let a fork honour a repeated step's pending gate

On a pending split move the fork's actor landing, its none-retire, and its sibling placements applied unconditionally, contradicting the split's own constraints so a fan-out from a repeated step proved vacuously. Landings, the retire, placements, nextID, fails and full now apply under the same gate succeed uses, with the barrier retirement for a gate-false move; under pending only the split's constraints apply.

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

* fix(runtime): report open order for a false guard into an inherited repeated step

falseGuardLeavesRepeated skipped an inherited [n] because it read the declared-multiplicity table; it now gates on the effective HasStepMultiplicity, so a redefining step that takes the redefined step's count refuses the same way.

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

* fix(runtime): bound a performed action's performance count

classifierPerformanceCount answers the count both the deferred and the eager attachment loops then mint; it now applies the same step budget splitRepeatedStep enforces, so a huge declared count fails with ErrActionStepLimitExceeded before any behavior is allocated.

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

* style: shorten new test comments to the house limit

Trims the comments added with the inherited-step cases to at most two lines each.

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

* fix(lower): keep an inherited succession whose ends carry multiplicities

sameUnconditionalActionEdge compared ends, guard, name and carrier but not the written end multiplicities, so an owned plain succession restating the same ends swallowed the inherited edge and dropped its [*]..[1] crossing. An edge whose ends state multiplicities is now never the same unconditional edge as one without them or with different ones.

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

* fix(lower): deduplicate a restated succession by its ends' ranges

sameUnconditionalActionEdge compared written end multiplicities by node identity, so a derived action restating an inherited succession verbatim kept a second edge and the runtime had two orderings over the same ends. The comparison now evaluates each end's range in its own declaring scope and deduplicates only when both ends agree; an unevaluable bound still keeps both edges.

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

* fix(libs): qualify the SI magnetic dipole moment units through the errata overlay

ISQ::* re-exports a MagneticDipoleMomentUnit from both ISQElectromagnetism
(IEC 80000-6) and ISQAtomicNuclear (ISO 80000-10), and KerML 7.2.5.4 hides a
name two imports bring from the importing namespace, so the unqualified name in
SI.sysml names nothing by the letter and the electromagnetic unit by first
match. The declared errata overlay now qualifies line 233 ('m²⋅A', the atomic
unit) by ISQAtomicNuclear:: and line 303 ('Wb⋅m') by ISQElectromagnetism::;
the published text is unchanged.

The model gates pin the corrections as an exact set: a correction is a line
the checker rejects as published or a listed hidden-name correction. The
oracle baselines restate the registry (13 entries, 6 corrections). The
documentation records the eight ISQ names the clause hides, that resolution
binds the first import's member as the pilot does, and that the imported
duplicate-name warning marks the memberships the clause hides rather than a
validateNamespaceDistinguishibility violation.

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

* test(model): shorten the hidden-name correction comments

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

* docs(project): record the imported-collision constraint as approximate

The validation-constraint row for validateNamespaceDistinguishablity now
carries the same status as the compliance row: the colliding imported pair is
reported, but the reference resolves to the first import's member where KerML
7.2.5.4 leaves it unresolved, as in the pilot. Census 155 faithful / 9
approximate; baseline regenerated.

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

* docs(project): record the approximate status in the validation-census baseline

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

* feat(migrate): a strict migration refers to no OpenSysML library

Under -strict the migrator writes nothing a tool shipping only the standard
library cannot resolve: the MigrationMetadata name markers become comments,
a choice or junction a plain state, a branch probability a comment, an
interval wait its midpoint, Java's whole-number quotient and ceiling the
standard floor, a view carries no DiagramLayout geometry, and a history
pseudostate, a document, a table or a Monte Carlo analysis is refused with a
report line. The deferral encoding keeps its MigrationMetadata annotations.
The default migration is unchanged.

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

* fix(migrate): a strict probability note reaches an edge whose guard is not migrated; docs say a Monte Carlo analysis is approximated

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

* test(migrate): a strict probability note reaches an edge whose guard is not migrated

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

* fix(migrate): a strict else branch negates the choice's other guards; strict documents and layouts are accounted for

A strict migration writes a choice or junction as a plain state, whose
transitions compete, so its else branch is now guarded by the negation
of the other outgoing guards, or written unguarded with a report line
when one of them is not a v2 expression. A document a strict migration
refuses is refused before its content is planned, so the report holds
no mapped rows for views and paragraphs no Document carries. A strict
migration still joins layout records to the views they match, counting
the geometry it omits instead of reporting the views missing.

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

* fix(migrate): a strict else negates only the guards of transitions strict mode writes; omitted geometry counts no stream supplementation

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

* feat(migrate): use case diagrams draw actor associations, includes, extends and refines as connections between usages

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

* test(migrate): pin the vehicle report counts a refine written as a connection moves (77 mapped, 13 approximated)

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

* build(libs): pin the extension libraries to the develop sync branch

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

* fix(migrate): a «Refine» with several ends is a connection per pair; connection names yield to package members; use case views expose an association end's usages

A dependency with several clients or suppliers now writes one connection per
client–supplier pair, each named distinctly and each exposed by the views
that show the dependency. A connection named after its relationship takes
the name only when no member of the package it is written in has it. A use
case view showing only an association end exposes the connection and both
usages it joins, and only use case views expose those usages.

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

* feat(migrate): -portable appends the OpenSysML library packages the output refers to

A migration under -portable is one self-contained file: every OpenSysML
library package its notation names by qualified name, and every one those
refer to in turn, follows the model as a library package (a KerML library
in its SysML spelling), so the file loads where only the standard library
ships. What the migration writes is otherwise unchanged; the report names
the packages inlined.

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

* chore(migrate): drop the unused topLevelNamed helper

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

* fix(cli): -portable is a migration flag, refused without -migrate

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

* fix(cli): the v1 migration feature lists -portable among its flags; regenerate the manual page

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

* feat(migrate): actors and use cases are usages; use case connections named by their kind

A UML Actor is written as a part usage and a UseCase as a use case usage
(subject, includes and behavior inside it), so each is one element a tool
draws once and a connection can join. Actor associations, includes, extends
and refines are connections named by their kind with no trailing comment,
an extend's points and condition as the connection's doc. The interconnection
renderer draws an include as the connection's line, not a nested node.

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

* fix(migrate): named relationship connections keep their kind as doc; actor and use case instances are reported, not individual usages; Classifier filters list use case usages

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

* fix(migrate): classifier tables list actors and use cases by name; census cites actorLink

A generic table over Classifier, Type, Namespace or PackageableElement no longer selects UseCaseUsage by type, which also matched use-case-typed properties and include usages; it names the written actor and use case usages (Named intersected with the scope) and unions them with the type rows. Actor and UseCase tables select the same way. The transformation census baseline cites actorLink and connectActor for the actor mappings, scoped to uml:Actor, with the fixture counts remeasured.

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

* wip: untyped property kind

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

* fix(migrate): an Actor or UseCase table over a model without them lists no rows

typeFilter.query only calls Named when a usage is written; with none and no type to select, the rows are the scope less itself, since Named takes at least one name. The empty_classifier_tables fixture pins it.

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

* fix(migrate): an empty Actor or UseCase table lists the empty sequence rather than walking its scope twice

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

* build(libs): pin the extension libraries to OpenSysML-Extensions-Library main

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

* fix(migrate): an untyped property follows its tool's kind marker; unmarked, it is an attribute, or a part when composite

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

* fix(stdlib): pin the extension libraries with library package declarations

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

* chore(oracle): re-record the pilot differential baseline for the library package declarations

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

* fix(runtime): observe writes of behaviors a store starts after the store

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

* fix(runtime): terminate the machine at an entry route's terminate action

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

* fix(migrate): a slot of an untyped part is typed by its individual instead of crashing

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

* fix(runtime): restore change trigger state on store rollback

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

* fix(runtime): stop region entry after termination

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

* fix(migrate): a slot of an untyped part is checked against the type the part inherits by redefinition, subsetting or name

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

* refactor(runtime): journal change-trigger bookkeeping per transition

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

* fix(migrate): a slot of an untyped part is checked against every type the part inherits by redefinition, subsetting or name

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

* feat(migrate): a v1 requirement is a requirement usage; satisfy, verify, derive and refine join it directly

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

* feat(verify): bind the in parameters of a constraint or requirement at check time

VerifyConstraint and VerifyRequirement take positional and named arguments,
as RunAnalysis binds a case's inputs, under the verification_arguments
capability. The runtime binds them in declaration order or by name and leaves
the verdict undecided on an unknown name, an arity overrun, a parameter with
neither an argument, a default nor a same-named value on the checked object,
or a value of the wrong type; holds and satisfiable refuse arguments.

The CLI and REPL accept the invocation grammar -analysis uses
(-requirement 'P::R(limit = 5) P::t', %constraint C(3.0) t), and every client
binds through the same option.

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

* fix(migrate): a named satisfy or verify subsetting a requirement usage relates its subject to it; an allocate to a requirement stays a dependency

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

* chore(client): order Rust capability imports for rustfmt; keep the Python stub at the pinned grpcio-tools version

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

* fix(semantics): a declaring satisfy or verify relates its subject to every requirement it subsets or is typed by, aliases followed

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

* fix(runtime): keep a renamed inherited input's slot and default when binding check arguments; never share verdicts of checks with arguments

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

* fix(matlab): send verification namedArguments given as a containers.Map

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

* fix(lower): find an action step's symbol through the scope's declaration index

actionStepSymbol materialized and scanned every member of each enclosing scope
on every step, so performing a chain of N steps cost O(N^2). Scope already
indexes members by declaration; use it.

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

* fix(lower): keep the binding of inherited pins on bodied typed usages

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

* fix(lower): keep inherited successions whose end multiplicities differ

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

* test(runtime): cover inherited content in composite redefining steps

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

* docs(readme): name the REDK as the second-generation Model Development Kit (MDK2)

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

* build(libs): pin the extension libraries to OpenSysML-Extensions-Library main

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

* ci(docs): pin pymdown-extensions and take mkdocstrings 1.0.7

pymdown-extensions 12.2 changed the Highlight constructor, which mkdocstrings
1.0.6 calls without the new argument, so every documentation build failed with
"Highlight.__init__() missing 1 required positional argument: 'md'" once the
unpinned transitive dependency resolved to it. mkdocstrings 1.0.7 follows the new
signature; pinning pymdown-extensions keeps the toolchain fully reproducible.

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

* ci(docs): keep mkdocstrings 1.0.6 and pin pymdown-extensions to 12.1

mkdocstrings 1.0.7 requires Python 3.11, while the project's Python floor is
3.10. Pinning pymdown-extensions to 12.1, the last release with the Highlight
constructor that mkdocstrings 1.0.6 calls, restores the documentation build
without raising that floor.

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

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: jason.han <hanhuijun@gmail.com>
Co-authored-by: Jason Han <jason.han@jpl.nasa.gov>
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