Skip to content

chore(release): merge main (0.9.1 + Windows hotfixes) back into develop - #754

Merged
HuiJun merged 40 commits into
developfrom
chore/backmerge-0.9.1
Sep 30, 2026
Merged

HuiJun merged 40 commits into
developfrom
chore/backmerge-0.9.1

Conversation

@devin-ai-integration

Copy link
Copy Markdown
Contributor

What and why

Back-merge of main after the 0.9.1 release (#614) and its two hotfixes (#752, #753), so develop carries:

  • the folded 0.9.1 CHANGELOG.md section and all versions at 0.9.1 (the fragments folded into it are removed);
  • the Windows-portable docrender fixture rename and the tests/hygiene tracked-path check;
  • the release-windows.yml tag dispatch and no-checkout MSI build, with the releasing.md recovery notes.

Plain git merge origin/main into origin/develop, no conflicts, no other changes. Only the two hotfix changelog fragments remain unreleased.

How it was verified

python3 scripts/changelog.py check, gofmt -l . (empty), go build ./..., go test ./tests/hygiene/... ./internal/doc/docrender/... locally; full suite in CI.

Checklist

  • make test and make lint pass locally (targeted; full in CI)
  • Tests added or updated for the change (merge only)
  • 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 (release fold carried from main)
  • baselines regenerated and make docs-counts run if a gate count moved (n/a)
  • 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/e0c5a204e0984415814ed38767578b41
Open in Devin Desktop: https://nasa-jpl-demo.devinenterprise.com/desktop/session/e0c5a204e0984415814ed38767578b41?variant=devin
Requested by: @HuiJun

devin-ai-integration Bot and others added 30 commits September 26, 2026 12:30
Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
… into release/0.9.1

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

# Conflicts:
#	client/rust/conformance/sysml.descriptor.binpb
Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>

# Conflicts:
#	changes/unreleased/authoring-transitions.added.md
…into release/0.9.1

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

# Conflicts:
#	internal/workspace/libs/stdlib.snapshot
#	internal/workspace/libs/stdlib/OpenSysML Libraries/MigrationMetadata.sysml
… into release/0.9.1

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…release/0.9.1

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

# Conflicts:
#	internal/semantic/semantics/annotations.go
#	internal/workspace/libs/stdlib.snapshot
…o release/0.9.1

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

# Conflicts:
#	docs/project/pilot-differential-baseline.json
Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
…ge name

#629 writes an owner-context activity as an action usage (action issue)
rather than a definition (action def Issue); #632's REPL step still named
the definition, so the Cmd was never sent.

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>
…t pom

Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
…narrating them twice

Co-Authored-By: jason.han <hanhuijun@gmail.com>
* fix(runtime): use effective parameter ranges for writes

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

* fix(runtime): clarify action parameter write ranges

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

* feat(convert): convert a model of several documents as one graph (#653)

-convert took one file and Convert refused a model_hash of several
documents; a file converted alone wrote a reference into another as an
unresolved name. The documents of a model are now analyzed together, as a
workspace analyzes them, and each is encoded over that one analysis: a
reference from one document to an element another declares links the
subject that document writes, by the name and identity its own encoder
gives it (a positional name included). Each document's root elements carry
sysx:sourceDocument.

- export.ModelToRDFWith, convert.ConvertModel
- sysml a.sysml b.sysml -convert ttl|api-json
- Convert of a multi-document model_hash to ttl or api-json; notation stays
  a one-document operation (FAILED_PRECONDITION, as before)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(export): a dependency's prefix metadata is an owned Annotation (#652)

Dependency takes PrefixMetadataAnnotation, not PrefixMetadataMember: the
metadata usage is the annotatingElement of an Annotation the dependency
owns. The reader takes that Annotation as the ownership edge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(check): distinguish shorthand succession multiplicity

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

* fix(examples): require single RocketEquation inputs

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

* fix(export): a flow's payload is a PayloadFeature (#652)

FlowDeclaration takes 'of' FlowPayloadFeatureMember: a FeatureMembership
owning a PayloadFeature. The declared payload is now written as that
feature (m.cmd reaches it), 'of T' as one typed by T, and the reader
rebuilds the 'of' clause from it instead of the sysx:payload expression.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(corpus): source positions move with a dropped blank line; lint

Seven KerML Annex A examples begin with a blank line the rendering drops,
so hop 2's positions sit a line higher: whitespace-only, not stable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(export): keep reading a legacy sysx:payload; refuse stray payload features

Review: a graph from an earlier release states a flow's payload as
sysx:payload beside standard ends, and it lost its 'of' clause. It is read
again; a flow stating both shapes is refused. Only the one payload feature a
flow's head writes is kept out of its body; any other is refused, not dropped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(export): prefix annotations in sync; refuse one annotating another element

Review: sync minted the dependency prefix's Annotation an id of its own,
and minted the prefix metadata usage one it cannot declare, so the next
export moved both back. The Annotation is a derived satellite that follows
its metadata usage (_an, as _om does), and a '#' prefix is not minted.
An owned Annotation whose annotatedElement is not its owner is refused
rather than written as the owner's prefix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(pilot-diff): refresh baseline figures and narrative

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

* fix(export): a source range ends at the declaration's last token

Review: a span runs on to the next token, so 'part a; /* note */' ended
a's range after the note. The range now ends at the last token that is not
trivia; a comment that is a declaration's body (doc /* ... */) stays in it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(python): keep add_member positional parameters stable

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

* fix(edit): accept other-language keywords in import targets

lexesAsQualifiedName rejected every token the lexer marks Keyword, so a
target naming an element after a word that is reserved only in the other
language (type in SysML sources, part in KerML sources) was refused as
not a qualified name. Read the token stream the way the parser does:
a keyword of the file's own grammar is refused with a message telling
the modeler to quote it, a keyword of the other grammar reads as a name,
and KindUnknown reads as SysML.

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

* fix(export): a model of several documents is checked as one

Review:
- identity scopes are counted across the documents, so one declared id
  in two projects is two subjects, not one;
- a subject two documents declare is refused, naming both;
- Convert of a modelHash refuses a document with syntax errors, with its
  diagnostics, as a single document is;
- several files to a flexo:// branch is refused rather than written as a path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(edit): keep visibility when replacing documentation

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

* fix(repl): read syntax-backed scopes for recorded files

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

* fix(doc): split a metadata column path outside quoted names

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

* fix(ci): give the CircleCI WebAssembly gate a 30-minute test budget

The "Go gates and binaries" job ran go test ./tests/wasm with the default
ten-minute budget. TestWasmBuilds alone takes 555-585 s on this executor, so
TestWasmRuns hit the deadline while linking the js target ("panic: test timed
out after 10m0s" at TestWasmRuns/js/version) on every develop run since the
gate reached the tests. The gate now runs with -timeout 30m, matching the
race job's budget for the same package, and the step's no-output timeout is
raised alongside it.

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

* fix(parser): parse rooted assert references

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

* fix(verify): preserve values in solver questions

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

* docs(verify): document satisfaction bindings and evaluation stamping

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

* fix(semantics): a parameter subsetting several features takes the intersection of their ranges

A subsetting feature by default shares the subsetted feature's properties
and may only restrict its multiplicity (KerML 1.0 §7.3.4.4), so several
subsetted features bound the parameter to what satisfies all of them — the
intersection of their ranges; a redefinition bounds it likewise
(§7.3.4.5). EffectiveParameterRangeAlong replaces the first-found walk,
which made the answer order-dependent, with a recursive intersect over
explicit RelSubsets/RelRedefines targets and the implicit chain successor;
a visited set ends cycles, and a target that states nothing, has no
implicit default, and whose own targets give nothing contributes no
bound. Ranges intersect by Range.Intersect, the same rule the runtime's
inheritedMultiplicity uses.

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

* fix(migrate): name the expression argument of a usage-owned document column

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

* test(edit): cover plain documentation replacement and note the visibility fix

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

* fix(export): compare a legacy transition trigger by the element it names

A graph carrying both a transition's trigger structure and an earlier
mapping's sysx:trigger was refused when the text qualified the payload
type differently ("T::Sig" beside accept Sig): an early check compared
the text against the type's short name. Drop that check and compare
sysx:trigger and sysml:via against the structure in transitionTrigger
by resolving each differing name from the transition through its
enclosing namespaces.

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

* fix(edit): place metadata prefixes after declaration modifiers

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

* fix(export): give same-named toolkit roots positional identities

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

* fix(export): keep the name of a reference to its own scope

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

* chore(pilot-diff): regenerate baseline after merging develop

develop@07cbe053e produces the same result without this branch because develop's optional bare in parameter change removes the warning at examples/runtime-showcase/delta-v-budget.sysml:93, and the committed baseline predates that change. The control also lacks the prior warning at Simple Tests/Behaviors.kerml:14; this additional movement is recorded in the refreshed counts.

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

* fix(source): read a lone carriage return in a comment as a line break

KerML 1.1 §8.2.2.1 makes \r, \n and \r\n line terminators, so Comment::body
processing (§8.2.3.3.2) and documentation prose split on all three.

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

* fix(migrate): key documentation sorts on the documentation the query reads

docKey read the exact Comment::body of the doc comment it writes, which keeps
the trailing space or line break single-line and multiline comments differ in,
while the OrderBy it generates reads DocumentationOf's prose.

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

* fix(parser): parse source multiplicities before then in nested action bodies

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

* fix(authoring): resolve sequence references to earlier declarations in nested bodies

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

* fix(authoring): refuse sequencing after a member that cannot be a succession source

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

* chore(diff): keep the parent's differential counts, restating the examples digest

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

* fix(check): count a calculation send by its result type, as the runtime sends it

A send invoking a calculation sends the calculation's value, so the
undeclared-signal lint now selects the invoked declaration with SelectCall
and decides with the new Model.CallsCalc, which the runtime's invokesCalc
now also uses. A calculation send records its result's declared type;
any other invocation still records the invoked name.

The when-trigger adjudication test now expects the lint's warning on an
injected signal nothing sends.

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

* fix(authoring): anchor sequence placement on declarations, not first references

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

* fix(runtime): a performance occurrence holds a parameter at its effective multiplicity

Context.materialize builds the occurrence's feature shape through
featureMultiplicity, which defaulted an unstated multiplicity to [1..1]:
when an earlier parameter default evaluated this, the occurrence
materialized, and a later bare parameter's empty binding was then written
through SetFeatureValue and rejected with a multiplicity violation.
featureMultiplicity now returns the parameter's §7.6.3 effective range, so
a bare parameter stores its binding as [0..*], and statedMultiplicity
answers the same for a parameter stating nothing. The parameter special
cases in admitsNoValue and pinsOf fold into the shared rule, alongside the
write-target path write_conformance already takes. The bindCalcParameters
override stays: Decl.Target.mult comes from extractMultiplicity, the
declared bound, not featureMultiplicity.

Migrating SysML v1: direction parameters that wrote no multiplicity (in,
out, inout and inout bindings, port and context members, Monte Carlo and
activity pin declarations) now emit an explicit [1], preserving the v1
reading of exactly one value under §7.6.3 instead of silently widening to
[0..*]; reduce-lambda parameters keep their bare form, which the grammar
requires.

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

* docs(semantics): tighten the effective parameter range comments

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

* fix(check): exempt only interfaces port-conjugation judges from the port lint

A connector's concrete ends were skipped whenever its type declared
port-typed ends, but port-conjugation judges only a two-ended interface,
so a connection definition pairing unrelated ports hid the mismatch from
both checks. The exemption now requires an interface with two port-typed
ends.

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

* fix(check): warn on non-unit source multiplicities in nested action bodies

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

* test(runtime): drop a duplicated succession from the this-default action fixtures

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

* ci: re-run checks after a transient Go module proxy error

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

* fix(referee): spell a parameter's multiplicity, one being unstated no longer

A bare parameter now takes [0..*], so the fUML translation spells the
multiplicity it means: [1] on in and inout parameters, pins and the
context, and an out parameter's upper bound with a 0 lower and an empty
default, since a performance's output holds nothing until a token
arrives.

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

* fix(python): restore develop's add_member positional order

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

* fix(solve): refuse failed defaults whose cause is a missing dependency

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

* fix(export): resolve quoted, global and library names in a legacy trigger

sameNames split the clause with strings.Fields, cutting a quoted name
with a space in two; it resolved $::T::Sig as a scoped name; and it
looked names up only among the graph's elements, so a standard library
type refused its short spelling. Split outside quotes, resolve a global
name from the root, read the structure's first-pass names as fully
qualified, look library names up in the catalog, and let a name only an
import brings into scope agree when it ends the qualified name the
other reaches.

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

* chore(ci): re-run checks

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

* fix(export): keep a looked-up trigger name in its written form

declaredName returned the canonical NUL-joined key, which nameSuffix then
re-read as a ::-delimited name. Return the element's qualified name as
written and canonicalize only for the equality test.

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

* fix(runtime): a write through a chain step holding one value reaches that object

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

* fix(fmi): spell a scalar FMU parameter's multiplicity, one being unstated no longer

The FMU-to-notation converter wrote every scalar in, out and return
parameter bare, which now reads [0..*], so a scalar output held a
sequence and the tool:fmi engine rejected its own result. An array
parameter keeps its spelled [n] nonunique.

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

* docs: regenerate documentation counts after merging the parent branch

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

* chore(diff): restate the examples digest after merging the parent branch

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

* fix(check): count a literal send's scalar type as the signal it sends

The runtime types a sent literal by its scalar type; the lint now names it
through the same classification, shared from semantics.

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

* fix(semantics): judge recorded and redefined ports for port-type-mismatch

A port's type is read from its record as from its declaration, conjugation
included, and a port redefining another takes that one's type. A recorded
interface definition is recognized by its definition kind.

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

* fix(check): count computed scalar sends in undeclared-signal

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

* fix(check): count the signal type a send's message carries at runtime

The undeclared-signal gatherer now reads the written message before the
body payload, counts a feature's value type rather than the feature's
name, and follows aliases to the definition they reach.

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

* fix(export): order toolkit roots by the root namespace and count root relationships

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

* fix(export): let a partially indexed root namespace keep its member order

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

* fix(export): list the root namespace's members in decoded root order

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

* fix(migrate): keep a v1 parameter's declared multiplicity when redeclaring, binding or ordering it

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

* fix(migrate): keep a parameter's multiplicity and collection modifiers where it is redeclared or bound

An operation's context body and a reception's parameter bindings wrote every
parameter as [1], so an optional or plural v1 parameter became required and
single in v2, and a reception binding a plural signal attribute was refused
even though bindingMismatch accepted it. Both now write the parameter's own
multiplicity through parameterShape, ordered/nonunique included, as do
behavior parameters and activity pins.

The implicit-singleton fallback for a v1 parameter that writes no multiplicity
now applies before the collection modifiers: an ordered singleton wrote a bare
ordered, which v2 reads as [0..*], and now writes [1] ordered.

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

* fix(export): read a message's ends from standalone parameter memberships

messageEnds only followed the flow's own sysx:ownedMembership and
sysx:ownedRelationship links, so a graph whose ParameterMemberships name
the flow from their side alone, through membershipOwningNamespace or
owningRelatedElement, gave the message no ends and it could not be
written back. The decoder now indexes those memberships by the namespace
they claim and includes their event-occurrence members, in subject
order, after the flow's own links.

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

* fix(export): order a message's ends by memberIndex or source and target, refuse when neither can

A message's ends come from two passes — the ParameterMemberships the flow links and the standalone memberships naming it back — so when a graph links only some ends from the flow, the standalone ends followed the linked ones and the message read back reversed. The ends now order by sysx:memberIndex or the flow's sysml:sourceFeature/sysml:targetFeature; a partly linked message neither can order is refused, as is one whose two orderings disagree.

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

* fix(export): order a message's ends by memberIndex only when every index is well-formed and distinct

A present sysx:memberIndex parsed through a lenient reader counted as an index even when malformed, and ends tied at one index kept discovery order — flow-linked first — so a partly linked message read back reversed. byIndex now orders the ends only when every membership, or else its end, states a well-formed and distinct integer; otherwise the source/target fallback and the partly linked refusal apply as before.

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

* test(export): state the malformed memberIndex alone on its membership

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

* test(runtime): pin this in a part-owned action to the owning part

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

* Fix formatting in then_after_members.golden.ttl

* Fix missing newline at end of rdf_out.go

Add newline at the end of rdf_out.go file

* Fix missing newline at end of export_test.go

Add missing newline at the end of the file.

* Fix missing newline at end of names.go

Add newline at the end of names.go file

* Fix missing newline at end of rdf_out.go

Add a newline at the end of the file.

* Fix formatting in payload_declaration_bodies.golden.ttl

* fix(export): an end-free flow writes its payload; refuse a payload with a body

Review: 'message m of T;' states no ends, so its head never wrote the
payload the body no longer holds, and it came back as 'flow m;'. A flow with
no ends writes 'of <payload>' after its declaration (FlowDeclaration,
MessageDeclaration). A PayloadFeature with members or a body is refused,
since the 'of' clause has no place for one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Update shadowing_parameters.golden.ttl with source info

Added source line and column information for shadowing parameters.

* Add source line and column metadata to state machine

* fix(export): a source range ends at the body the parser attached

Review: a body comment was told from trivia by the token before it, so
'doc // note' with its body on the next line ended the range at 'doc'. The
encoder records each body span the parser attached (Documentation, Comment,
TextualRepresentation) and treats every other /* */ comment as trivia.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(solve): model short-circuit reachability of unreadable reads in holds/satisfiable

The translator tracks the evaluator's left-to-right, short-circuit evaluation path (and/&/implies reach the right operand where the left holds, or/| where it fails, xor and not always, a conditional its selected branch, an element's conditions in order) as Var.Reached. UnfixedRead refuses a failed default read on every path, guards one reached only under a condition out of the query's models (Query.Unreadable, left out of Query.Free), and Query.Reached asks whether any assignment reaches it, so holds/unsatisfiable are claimed only where the evaluator answers on every assignment.

Resolves #719

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

* perf(runtime): memoize the parameter range, chain-host and chain-declaring checks a derivation repeats

EffectiveParameterRange walked the redefinition chain on every calc
parameter binding; shapeOf re-derived isChainHost from the relationships
of every feature value on every shared-default check; and
pendingNestedRedefinitions built its name and seen maps for objects whose
types declare no chain at all. Each is memoized where its answer is fixed
by the model, and takeShared/shareDerived intern the shape once.

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

* Bring the architecture self-model up to date with develop

Model the Julia and MATLAB clients, the Cameo and SysON integrations, the
HTML document backend, the SysML v1 migrator and calc code generator, the
PSSM, fUML, validation-census and conformance-suite oracles, the sweep-run
budget, the language server's full capability set and every source-edit
operation; point the gates at the test packages that hold them; extend the
self-model test to check the new language-server and edit-operation claims;
and correct the README's stale figures.

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

* test(grpc): lift the held-objects bound for the warm Instantiate benchmark

The benchmark holds every object it makes, so with the default bound it fails
past 10 000 objects and never reports a figure.

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

* perf(runtime): skip aliasing redefined feature values for a type with no redefinition group

The two name maps were built on every materialization; a type whose
features share no name has nothing to alias.

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

* docs(examples): refresh the example walkthroughs and transcripts for 0.9.1

Replay every example command against the current binary and bring the
transcripts back in line: the standing lines every analysis prints, the
probability column of -schedule explore, the sysml: property names of OSLC
query rows, the current RDF experimental note and byte counts, the
%features form of event occurrences and library features, and the
%check assignment listing.

Fix the two commands that no longer ran as written: the disposal-robot
state machine is exhibited by RobotController, so -state names the
controller instance; and disposal-team's usableReach and teamEndurance
returned duplicate values into unique collections, so their parameters
are declared nonunique.

Correct the semantic-layer README, whose feature names, section line
numbers and REPL invocation had drifted from demo.sysml, and drop its
dead PR link. Record that the Apollo 11 model now validates with two
warnings, not four, since a parameter written without a multiplicity
takes its effective [0..*] and is not reported unbound. List the
semantic-layer walkthrough and the loose guide models in examples/README.

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

* Resolve SonarCloud code smells outside cognitive complexity

Constants and small helpers for repeated literals, renamed shadowed
predeclared identifiers, parameter structs for wide signatures, dropped
unnecessary if-scoped declarations, split composite assertions and
hoisted the tested calls out of assertThrows/pytest.raises lambdas.
Pins setup-julia to a commit, adds the default case of race-shard.sh,
and names the sponsor link by its visible label.

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

* fix(examples): give the disposal-team verification case its verdict

CheckPayload declared its verdict and never assigned it, so
-requirement TeamCases::payloadHolds -satisfy reported the verification
as an error with no value. The verdict is now PassIf over the payload
comparison the requirement states. The README's validate transcript
shows the two conforming-types warnings the sum over MassValue raises,
as the runtime showcase does for the same pattern, and the calculation
and satisfaction transcripts carry their standing lines.

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

* chore(ci): rerun checks after the static job hit its time limit

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

* Keep the sponsor pill's height with the icon wrapped

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

* Re-record the pilot differential baseline's examples digest

The self-model files under examples/ changed, so the provenance digest of
the examples root moved. Every verdict is unchanged: a fresh run agrees
with the committed baseline entry for entry (380 files, 345 fully
agreeing, 38 agreed, 41 only ours, 1614 only the pilot's).

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

* refactor(export): split toolkit graph normalization into per-pass methods

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

* refactor(export): split the remaining high-complexity decoder and encoder functions

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

* chore(diff): restate the examples digest for the corrected disposal-team model

Only the provenance digest of examples/ moves; the differential itself
is unchanged (380 files, 345 fully agreeing, 38 agreed, 41 only ours).

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

* refactor(migrate): split high-complexity view, context, deferral and classification functions

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

* refactor: split symbol stream reader, FMI notation writer and fUML closure walks

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

* fix(export): payload identity, ownership, ordering; legacy-end payloads

Review:
- a flow with legacy relatedFeature ends and a separate sysx:payload kept
  its ends and lost its payload; both shapes are read, disagreeing ones refused;
- a payload's declared id is annotated 'about' it in the flow's body, as a
  cross feature's is, so it survives the graph alone;
- only a payload owned through a FeatureMembership is written after 'of';
- 'ordered' and 'nonunique' on a declared payload are parsed (they belong to
  its multiplicity part), exported and written back; an unnamed payload
  stating one is refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(analysis): split record shape settling, CSV/regex reply readers and dry-run preview

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

* fix(export): a transition's trigger action carries its source range

Review: the accept action a trigger declares is written without going
through head, so it had no position. It is placed where the trigger is
written; the goldens gain only those properties.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(runtime): split pin binding, invocation inputs, nested redefinitions, weights and tool calls

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

* refactor(edit): split add-member checks, trivia scan, layout bindings and statement formatting

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

* refactor: split remaining complex Go functions across passes, semantics, IR, REPL, parser and CLI

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

* fix(solve): guard a chain's declared value that does not evaluate instead of leaving it free

ChainPins skipped every chain read failing with ErrNoValue, so a nested default reading a feature with no value (inner.dependent = input + 1.0) stayed free and the solver could witness a value for it; any other failure refused the question even where the evaluator never reaches the read. It now tells a feature holding nothing (still free) from a declared value that does not evaluate — the runtime marks the latter ErrFeatureValueMaterialization — and returns the latter as Unfixed naming the exact chain variable, which UnfixedRead refuses or guards by Var.Reached as it does a direct read. translatedQuestion applies the chain reads' guards, and reapplies every guard when chain pins require translating again. The differential harness classifies a chain's failed declared value as unreadable and its randomized generator declares one on a nested part read through a chain.

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

* refactor: split edit-request building in the Python and Java clients

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

* Match release tags on ASCII digits only

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

* perf(runtime): bind a calc's this hook once per occurrence and statement engine

Every statement evaluation and binding env bound host.materializeOccurrence
afresh, an allocation per step of a loop body; the bound hook now lives on
the engine, the occurrence and the pooled invocation frame it belongs to.

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

* perf(semantics): memoize PortFeatures by port type

The port-type-mismatch lint asks for the features of the same port types
once per connection end; the answer is now journaled on the model as
conjugatedSupertypes already is.

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

* fix(solve): constrain Query.Reached only by the guards the evaluator checks before the read

A definedness guard hoisted from an operation the evaluator performs only after
reaching a failed default — a later required condition's divisor — could make
Query.Reached unsat and certify a proof on a question that is unsat for its own
reasons, though assignments reaching the read exist and the evaluator gives no
verdict there. Each conditional read now records the guards asserted before its
first reference (Var.Preceding); Reached requires them with the read's condition
and asserts no other definedness guard.

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

* perf(runtime): memoize the chain-host check on the model, not the effective feature

The self-model counts runtime.EffectiveFeature's fields; a private cache
field does not belong in that shape. Key the isChainHost memo by feature
symbol on the runtime model beside declaresChains instead.

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

* ci: rerun after a Go module proxy stream error in the static checks

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

* fix(export): untyped named payloads, flags before the typing, duplicate names

Review:
- a named payload with no typing was written 'of cmd', which reads back as
  a payload typed by cmd; a named payload needs its one typing and is
  refused otherwise;
- 'of p[1] ordered : T' failed the declaration lookahead, which now skips
  the multiplicity part's ordered/nonunique before the colon;
- a payload named like a body member is identified by its position, as
  any member whose name a sibling took first is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(project): record the 0.9.1 candidate's performance against 0.9.0

Every package benchmark on both revisions, whole-binary scaling on
generated models and Apollo 11, and each regression fixed or priced with
the commit that introduced it.

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

* docs(changelog): performance entry for the 0.9.1 fixes

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

* ci: rerun after the rest race shard stalled on the runner

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

* docs(performance): re-time the Apollo 11 validation on the 0.9.1 candidate

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

* fix(cli): refuse -o naming one of a model's several files

The graph of a model of several files could be written over one of them;
each file, and a link to one, is now refused as the output path as the
migration's paths are.

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

* docs(changelog): own fragment for the -o overwrite refusal

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

* feat(python): wrap ParseSources to parse several documents as one model

Connection.parse_sources and opensysml.parse_sources take paths,
(name, text) pairs and SourceDocuments, require the parse_sources
capability (and inline_language/strict_conformance when asked for), and
return the Model that load returns, with one root per document in
Model.roots and their names in Model.documents. Model.find, get and the
name walk search every root. The response's error field raises
ModelError, as a strict load does.

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

* test(export): the payload features carry source ranges

develop's source ranges (#654) place every declared element, the payload
features this branch adds included; the golden gains only those lines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(client-node): rename the package to @openmbee/opensysml

Derives the published name and the platform-package prefix from a single
src/core/package.ts, so binary.ts, capabilities.ts, the platform-package
generator and the tests all read the same source. Version follows
client/python/opensysml/_version.py in lockstep.

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

* test(release): check the Node client's version in lockstep

Adds check_version.py --node, which verifies client/node/package.json
against _version.py and the tag, and a ci-changed-areas rule so a PR
touching only that file still runs the Python suite that gates it.

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

* ci(release): publish the Node client to npm from the core tag

publish-npm now runs in the release workflow on the v* tag, at the same
version and carrying build-release's binaries — replacing the
client-node-v* path, which never ran.

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

* ci(release): tidy the npm publish job and its verification snippet

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

* fix(edit): resolve an ApplyEdits batch's references against the whole batch

A succession reference or metadata prefix an operation writes is now
checked once against the model the batch leaves, so it may name a member
or metadata definition a later operation of the same batch declares.
Names are still taken in operation order, and a `first x` label no
longer takes or makes visible the name it borrows.

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

* feat(parser): accept a target-end multiplicity on action-body then successions

The SysML v2 grammar lets the target a `then` references carry a crossing
multiplicity (SysML.xtext TargetSuccession -> ConnectorEndMember): `then [m] x;`,
`then [m] x { ... }`, `then [m] done;` and `[m] then [n] x;`. The pilot accepts
them; the parser rejected them with "a multiplicity in an action body must
precede then". The AST records the target multiplicity beside the source one,
semantics carry it on the target end, RDF export writes it on the target
connector end and reads every form back without source text, and the
end-feature-multiplicity warning stays limited to source ends.

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

* fix(python): refuse a bare document and non-str fields in parse_sources

A string passed where the sequence of documents goes was iterated as
its characters, so the complaint was about two documents named 's';
it is now refused as one document outside a sequence. SourceDocument
fields of a type other than str raise TypeError up front instead of
the protobuf's opaque one.

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

* docs(skills): probes for parse_sources across documents

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

* fix(cli): check -o against every model file before reading any

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

* fix(python): generate a typed module from every document of a model

generate_source collected definitions from model.root alone, so a model
parsed with parse_sources produced a module of its first document only,
and a type or redefinition crossing documents could not resolve.
collect_definitions now takes every root and builds one facts map.

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

* docs(python): say the typed-class command line takes one source file

A model of several documents is generated from Python with
generate_source; the command line still reads one file.

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

* fix(parser): reference a declared node-word member after a bracketed then multiplicity

namesEdgeEnd read the tokens at fixed offsets from `then`, so `then [m] fork;`
with `action fork;` declared was taken as a new fork node with a source
multiplicity. The lookahead is now relative to the offset after the
multiplicity and prefix metadata, and a declared name followed by a body is an
end as well.

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

* fix(parser): keep a node keyword with a body a node declaration after then

A control-node keyword followed by `{` declares an anonymous node with that
body (SysML.xtext ForkNode, MergeNode) regardless of a member sharing the
keyword's name; only `then <kw>;` and `then <kw> <name>;` are read as
references to a declared member.

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

* feat(client-java): lock the version to the core and auto-publish to Central

The pom and its consumers follow _version.py in lockstep, checked by
check_version.py --java and a pytest gate that also runs on a
manifest-only change; the release profile publishes the validated
deployment itself and waits until it is on Central.

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

* ci(release): publish the Java client to Maven Central from the core tag

publish-maven runs in the release workflow on the v* tag, beside
publish-pypi and publish-npm, signing and uploading at the core version
from the restricted maven-central context.

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

* docs(release): document the Maven Central publish

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

* test(release): import ElementTree at module level; tidy the context wording

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

* ci(release): read the Maven Central credentials from project variables

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

* fix(edit): follow a batch's deferred references through later renames

A succession end or metadata prefix an operation writes is now anchored to
the byte it starts at in the edited document and moved past the later
operations' splices, so the deferred check reads the name the batch leaves
there rather than the one the operation was given: a later rename of the
metadata definition, of the prefixed declaration or of the sequenced node
no longer refuses a valid prefix or skips the duplicate-prefix check.

ActionNodeOfBody and FeatureSymbolInScope look past a `first g;` label to
the inherited member of that name, so the label no longer hides it.

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

* fix(edit): judge a deferred succession end under its `$::` root

The end read back from the final AST is passed to the visibility check, and
reported, with the global root it was written with, so a `$::`-rooted end
resolves through the index rather than the edited document's scopes.

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

* ci(release): warn against debug output on the Maven publish step

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

* feat(client-rust): lock the crate version to the core

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

* ci(release): publish the Rust client to crates.io from the core tag

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

* docs(release): document the crates.io publish

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

* ci(changed-areas): run the lockstep tests when an editor's client reference changes

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

* docs(release): drop --offline from the Cargo.lock refresh

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

* fix(client-rust): accept a literal-string crate version

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

* fix(parser): `then fork F;` declares the node beside a member named fork

namesEdgeEnd read a control-node keyword followed by a name as a
two-ended succession to the member sharing the keyword's name. The
grammar gives the keyword its own declaration (ForkNode, JoinNode,
MergeNode, DecisionNode: 'fork' UsageDeclaration? ActionBody), so only
the bare `then <kw>;` beside such a member is an edge end.

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

* refactor: resolve the SonarCloud findings left on develop after the cleanup

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

* perf(runtime): attribute and fix the 0.9.1 satisfaction, gRPC, migration and lint regressions

Shared-default and shared-verdict tracing recorded every path of a nested shared value per read, deduplicated reads through a key string built per read, spelled a dotted path at every ancestor to ask whether a binding governs it, and every journal mark cloned the clock's waiter list. The trace now records a nested value once, compares paths in place, prefilters the binding question by the features a type's bindings start at (memoized on Model.bindingRoots), and the clock replaces its waiter list instead of editing it so a mark keeps the slice it saw.

The migration writer reuses the buffers of closed blocks and indents from a table. The nested-usage subsetting memoizes declaredSubsettedNames on the runtime model and makes its deduplication and reachability sets on first use. The undeclared-signal lint walks the document once per analysis through kit.ScopedNodes instead of twice.

The performance record's findings 5–8 carry the attribution, the six-run benchstat tables against v0.9.0 and the tree before this change, the profile frames, and what remains as the price of a rule.

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

* ci(release): read the registry credentials from the org contexts

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

* ci(release): read the Maven Central credentials from its context

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

* ci(release): add a no-publish release rehearsal

One pipeline parameter, release_rehearsal, runs the release workflow on a
branch with every check live and the irreversible commands - cosign signing,
ghr, twine upload, npm publish, mvn deploy, cargo publish - skipped. A
rehearsal exports a stand-in CIRCLE_TAG translated from _version.py (PEP 440
to SemVer), and rehearsals probe the GitHub, npm and Central tokens and build
and sign the Maven artifacts. The tag path is unchanged: the jobs drop only
the branches-ignore filter, which the workflow-level when now replaces.

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

* docs(release): state the rehearsal's limits without overclaiming

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

* chore(editors): lock the editor versions to the core version

The editors carry the core version the clients already follow: 0.9.0 in the
two package.json files (locks regenerated, only the version lines move), the
Cameo and SysON poms, and the child poms' <parent><version>. Nothing
publishes the editors, but check_version.py --editors now reads every editor
manifest - package.json, package-lock.json (both version copies must agree),
pom and child <parent><version> - through the shared lockstep check, so a
release tag fails early when one disagrees. The python changed-area trigger
covers every editor manifest, build-python-package runs --editors before
anything is built, and releasing.md's bump step lists the files.

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

* ci(release): don't print Central's probe response in the rehearsal

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

* chore(release): set the client and editor versions to 0.9.1

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

* chore(release): fold the late fixes into the 0.9.1 changelog

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

* docs(release): point the Java and editor READMEs at 0.9.1

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

* fix(java): keep the parent's SCM URLs verbatim in the published client pom

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

* chore(java): publish the Java client as org.openmbee:opensysml

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

* fix(ci): accept a base64-encoded GPG signing key in publish-maven

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

* docs(readme): point the Apollo 11 defects at the showcase instead of narrating them twice

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: Somesh Kashyap <someshsandbox@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Jason Han <jason.han@jpl.nasa.gov>
devin-ai-integration Bot and others added 9 commits September 30, 2026 17:53
…uch paths

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>
…ackage

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

Co-Authored-By: jason.han <hanhuijun@gmail.com>
* fix(docrender): rename the Windows-illegal image fixture and reject such paths

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

* ci(release-windows): let the workflow re-run against an existing tag

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

* ci(release-windows): sign tagged dispatches like a tag push

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

* fix(client-node): lock the published sysml-grpc optional dependencies

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

* fix(client-node): let the binary-resolution tests hide the platform package

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

* fix(client-node): leave a skipped platform package out of the places looked

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 <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>
@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

@HuiJun
HuiJun marked this pull request as ready for review September 30, 2026 20:37
devin-ai-integration[bot]

This comment was marked as resolved.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@HuiJun
HuiJun merged commit b570ccf into develop Sep 30, 2026
23 checks passed
@HuiJun
HuiJun deleted the chore/backmerge-0.9.1 branch September 30, 2026 21:05
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