chore(release): 0.9.0 - #564
Merged
Merged
Conversation
A feature a view exposes from outside its owner cannot be written private: v2 hides a private member from the qualified path an expose (and any layout annotation naming it) must resolve, so such references came out unresolved. planViews now records each shown element a placed view exposes through m.exposed — the mechanism featureVisibility and hiddenFromHeirs already consult — so its declaration keeps its reachability and the report notes "private visibility is not written: view ... exposes it". Co-Authored-By: jason.han <hanhuijun@gmail.com>
A non-recursive membership import (import P::x, expose x) surfaces only its last segment or the target's short name, so an unqualified lookup of any other name cannot match it. importPrefixAvailable now prunes such imports before their target is resolved: previously each import's target resolution re-walked the scope's members and so resolved every sibling import's target in turn, making lookups in a namespace with many expose/import members factorial in their number (a view with 30+ exposes never finished -validate). The prune consults Index.ShortNamed, which reports whether a name is registered as some symbol's short name. Its reads are tracked by a new ReadSegment kind on symbols.ReadRecorder so a document's frame is invalidated precisely when a name under a consulted segment is registered or dropped, rather than forcing re-analysis on any edit. Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: jason.han <hanhuijun@gmail.com>
…ility A feature a view exposes from outside its owner cannot be written private: v2 hides a private member from the qualified path an expose (and any layout annotation naming it) must resolve, so such references came out unresolved. planViews now records each shown element a placed view exposes through m.exposed — the mechanism featureVisibility and hiddenFromHeirs already consult — so its declaration keeps its reachability and the report notes "private visibility is not written: view ... exposes it". Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: jason.han <hanhuijun@gmail.com>
Explicit table rows go into one Union whose other is Named over every row; WhereType and WhereMetadata take several names, so a table with many row types filters once per kind instead of once per type; the remaining joins nest as a balanced tree. The deepest generated query chain drops from 47 calls to 7. Collaborator paragraphs are placed by the view their ownerId names within the document their viewId names; paragraphs no view shows are kept as stray paragraphs. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…bles-and-documents
Co-Authored-By: jason.han <hanhuijun@gmail.com>
«ValueProperty», «PartProperty», «SharedProperty», «ReferenceProperty» and «ConstraintProperty» applied from MagicDraw's SysML customization profile to a UML Property, with no tag, say what the usage keyword already says. They are dropped in annotated(), beside «ConstraintParameter», so metadata usages, comments and the report agree; a same-named stereotype from another profile, a tagged marker, and a marker on a property written as another kind are still written. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…parameter A «PartProperty» on a constraint parameter is dropped as its `in ref part` form says, since a parameter is a reference by necessity; a «ValueProperty» on a block-typed parameter or a «ReferenceProperty» on a value-typed one contradicts the written form and is kept, as elsewhere. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…tarts Co-Authored-By: jason.han <hanhuijun@gmail.com>
Typing a call re-read its arguments for every reader of the enclosing call — the argument check, the result type, the held element type — so each level of nesting doubled the work and validating a generated query nesting twenty calls did not finish. The checker now memoizes a call's argument types and scalar type per scope for the silent checkers spawned from one reporting checker, tracking calls still being typed so a re-entered call is never recorded as its provisional unknown type. The reporting checker itself never answers from the memo, so each diagnostic is still reported once where it arose. SelectCall answers a memoized selection without retyping the call's arguments. Co-Authored-By: jason.han <hanhuijun@gmail.com>
The graph the RDF and api-json mappings write now carries the relationship elements the metamodel defines beside the collapsed properties: FeatureTyping/Subclassification/Subsetting/ ReferenceSubsetting/Redefinition ends, MultiplicityRange bounds, ConjugatedPortDefinition/PortConjugation, SubjectMembership, RequirementConstraintMembership, ResultExpressionMembership, ElementFilterMembership, the Membership an expression referent is carried by, and an OwningMembership for a declared relationship member. Decoding accepts the materialized elements where the collapsed properties imply them and refuses them where they contradict; perform/exhibit/include/assert usages take their own metaclasses and kindless or unnamed members read as ReferenceUsage. Co-Authored-By: jason.han <hanhuijun@gmail.com>
ReadAPIJSON now decodes the toolkit's compact-json and full-json to byte-identical notation: the root Namespace wrapper is transparent, @ref and unresolved-derived targets read as the names they spell, and stated defaults collapse back off isImpliedIncluded elements while ends the notation cannot place are refused. -convert takes -id uuid to mint name-based uuids the way the library convention does; the form reads back with its derived ids implied rather than annotated. Co-Authored-By: jason.han <hanhuijun@gmail.com>
Spell out the materialized relationship elements, the sysx extension metaclasses an element-form consumer does not read, toolkit compact/full import behavior, and the uuid id form; add the matching compliance rows and changelog fragments. Co-Authored-By: jason.han <hanhuijun@gmail.com>
Drop the unread 'out' initializer in subjectOf's uuid branch, remove the unused isParameterMembership helper, and restructure the subject-parameter verify loop so the early return is not unconditional — referent-by-referent matching against the satisfy's stated subjects, erroring only when one matches none. Name the element-form detection for what the API element form states (every default) rather than who wrote it. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…ions 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>
…collapsed kind Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
…argets by value An element whose target ends name what a literal collapsed property never states is refused, as it is under IRI targets; a literal collapsed target counts as stated by its value, an element end spelled as the element the literal names joins to it by that name, and an end spelled as an element the graph names nothing for — a legacy graph's bare uuid — stays vacuous. Co-Authored-By: jason.han <hanhuijun@gmail.com>
A referent or targetFeature membership minted in the element namespace was never claimed, so a declared element id landing on its IRI merged the two subjects silently; it now records the same UnsupportedError as a minted relationship. Co-Authored-By: jason.han <hanhuijun@gmail.com>
… in coverage A child whose metaclass maps to two collapsed kinds deleted its target from both, so a feature stating the same target under two kinds was covered by a single element; coverage now consumes the first kind still stating it, and the encoder mints the feature-specializes Subsetting under a _sp suffix so the two kinds never merge onto one subject. Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
A quoted segment may carry ::, so unescapeName now parses the written form with source.QualifiedNameSegments and re-spells it canonically, and qualifiedNameText prints written names by their own segments; the feature-chain segment's element spelling prefers declaredName over splitting the unescaped qualified name. Co-Authored-By: jason.han <hanhuijun@gmail.com>
The uuid id form keyed each root's package namespace on the root's name alone, so two scopes' roots of one name would derive one namespace and collide; the derivation now feeds the scoped root IRI and returns the uuid IRI through ScopedElementIRIForID, keeping the project scope on every derived subject. Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
…backed content Co-Authored-By: jason.han <hanhuijun@gmail.com>
…n without a title page The acm theme documented 9pt tables but sized only the landscape wide-table path; an ordinary table stayed at the 10pt body. A --sysml-table-font-size token now applies to every acm table in HTML and PDF. The nasa companion reset the page counter on the first main page, which was the bare title heading when a contents list was asked for without a title page: the title counted 1, the contents ii and the body continued at 3. The title heading leading a contents list now shares its front page, and the article itself is the main page, so running text ahead of the first section opens the body at 1. Installed-toolchain tests read the table size back under each convention theme and the footer sequence back from a nasa report under every title-page and contents combination. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…ptions in the convention's face The nasa companion kept the page counter for the front matter and reset it on the first main page, so a body opening on a landscape wide page printed the physical page number and the next portrait page restarted at 1. The cover and front pages now leave the page counter at 0 and count in roman on a front counter, so the body opens at 1 whichever named page it starts on. nasa table captions take the sans face like the rest of the table; acm captions take the text face acmart sets them in. Co-Authored-By: jason.han <hanhuijun@gmail.com>
* fix(view): leave layout annotations and render members out of renderings A view's DiagramLayout annotations and its render members describe the picture, not the model; the shared member walk now skips them so every graphical form omits them, while ordinary metadata usages stay shown. Co-Authored-By: jason.han <hanhuijun@gmail.com> * fix(view): head a member drawn under its owner by its name below that owner Co-Authored-By: jason.han <hanhuijun@gmail.com> * feat(view): fit a stated box's label to it and draw symbol kinds as their notation A node a Layout sizes keeps its box: the head word-wraps at the width and shrinks from 14pt to 8pt until it fits the height, the keyword and detail lines follow only while height remains, and a head too long at 8pt is cut and ellipsized. Decision, merge and choice nodes in stated boxes are drawn as diamonds, forks and joins as filled bars, initial nodes as the filled dot, final nodes and terminate actions as the double ring, and ports as their square, with no text inside; a name is set beside the symbol unless the node marks it as synthesized. A terminate action usage is kinded as one, so the notation's final node is recognised. Co-Authored-By: jason.han <hanhuijun@gmail.com> * docs(view): describe the fitted labels, symbols, owner-relative heads and the bookkeeping left undrawn Co-Authored-By: jason.han <hanhuijun@gmail.com> * fix(view): draw an initial or final node with a synthesized name as the dot or ring Co-Authored-By: jason.han <hanhuijun@gmail.com> * fix(view): clip an edge at a stated junction's radius Co-Authored-By: jason.han <hanhuijun@gmail.com> * fix(view): head a member below its owner's drawn type, and write an enclosing box before the boxes in it Co-Authored-By: jason.han <hanhuijun@gmail.com> * feat(migrate): mark the names a migration makes up and draw those elements unnamed A bundled MigrationMetadata::SynthesizedName metadata def, written once per body as an about list over the names the migration made up; the semantic model reads it (Model.NameSynthesized), the view IR carries it on nodes, and the graphical writers draw such an element as its source did: a bare control symbol, an edge without a label, a typed node as ': Type'. An action's language-given start and done are treated the same way. Re-indexed twins of one declaration share the about annotations the declaration gathered. Co-Authored-By: jason.han <hanhuijun@gmail.com> * chore(docs): re-record the examples digest in the pilot differential baseline Co-Authored-By: jason.han <hanhuijun@gmail.com> * feat(view): keep words whole in a fitted head, shrinking before breaking one Co-Authored-By: jason.han <hanhuijun@gmail.com> * fix(lower): let a parallel state own a metadata usage in its body Co-Authored-By: jason.han <hanhuijun@gmail.com> * docs(changelog): note the parallel state's metadata member Co-Authored-By: jason.han <hanhuijun@gmail.com> * feat(view): head a stated box above the stated boxes it holds, and name a member below its resolved owner A stated box that encloses other stated boxes fits its title to the strip above the topmost of them and sets it there (labelloc=t), so a container's title is not covered by its members, which keep their stated geometry. A box the Layout only places is sized to its label and does not move the title. A node now carries the qualified names its typings resolve to (Node.Typings, from Model.DeclaredTypes), so a member drawn inside a usage whose written type differs from the type's canonical name is still headed below it. Co-Authored-By: jason.han <hanhuijun@gmail.com> * feat(view): leave a positioned drawing's unplaced nodes undrawn, or set them in a strip below it on request A DOT drawing that positions some nodes left the others to neato, which set them over the placed boxes. They are now omitted with the edges at them, under a notice, so a migrated diagram shows what its source showed. The new -render-unplaced strip (Options.Unplaced) packs them in rows below the canvas or the positioned extent instead, on -render, -render-all, -render-document and -render-documents alike. Every drawn node is pinned, so the layout header never names plain neato. Co-Authored-By: jason.han <hanhuijun@gmail.com> * test(docpdf): read the tall figure's first node back by its kind head Co-Authored-By: jason.han <hanhuijun@gmail.com> * fix(view): give a stated box's whole width and height to its fitted label Graphviz pads a node's label by its default margin of 0.11 by 0.055 in, so a head fitted to the full stated width could still be drawn past the box's border. A stated box that carries a label now sets margin=0, so the fit and the drawing agree; a head filling the width keeps its size, one a point over it shrinks. Co-Authored-By: jason.han <hanhuijun@gmail.com> * fix(view,migrate): keep a typed port's type outside its symbol and mark every synthesized declaration name A port with no given name but a type drew nothing beside its square; the type is now set as its xlabel like a given name. Anonymous parameters, port payloads, generated subjects, stakeholders, includes and instance slots are declared under a synthesized name that the SynthesizedName marker did not cover; they are now marked, and an empty name is never marked. 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>
…emes * fix(docpdf): name Times, Arial and Courier ahead of the generic print families The print and pandoc stylesheets asked for bare serif, sans-serif and monospace, which fontconfig resolves to DejaVu on most Linux machines while the Times-metric Liberation faces installed beside it go unchosen. The default body, heading, code and page-number stacks now name the conventional families, their metric-compatible free equivalents and the generic family last. Sizes, margins and page size are unchanged; print.css also declares the opensysml-print-theme layer a theme's print companion fills. Co-Authored-By: jason.han <hanhuijun@gmail.com> * feat(docrender): bundle nasa, ieee and acm themes with print companions A theme may carry themes/<name>.print.css, laid by the PDF backend over its print sheet in the opensysml-print-theme layer so the theme's page size, margins, faces, body size, heading scale and footer reach paper. Themes() leaves companions out of the public list. nasa, ieee and acm follow the NASA STI, IEEE Transactions and ACM acmart conventions; print and report gain companions so their print faces and sizes now print. Co-Authored-By: jason.han <hanhuijun@gmail.com> * docs(doc): list the convention themes and the PDF theme cascade Usage text, manual page, CLI reference, outputs manual and the backend design note name every bundled theme, the print-companion cascade order, the sources and choices behind nasa, ieee and acm, and their limits; changelog fragments for the themes and the default font stack. Co-Authored-By: jason.han <hanhuijun@gmail.com> * test(doc): pin theme discovery, the print cascade and the PDF faces Theme discovery lists the seven themes and no companion; each convention theme's tokens are asserted; a fake-tool test pins default/theme, print sheet, companion, KaTeX, reader order and that -html-no-default-css drops every bundled sheet; installed-toolchain tests read /BaseFont, MediaBox and the body size back from the PDF for the default and each theme. Co-Authored-By: jason.han <hanhuijun@gmail.com> * fix(docrender): set acm tables at 9pt and keep nasa front matter roman without a title page The acm theme documented 9pt tables but sized only the landscape wide-table path; an ordinary table stayed at the 10pt body. A --sysml-table-font-size token now applies to every acm table in HTML and PDF. The nasa companion reset the page counter on the first main page, which was the bare title heading when a contents list was asked for without a title page: the title counted 1, the contents ii and the body continued at 3. The title heading leading a contents list now shares its front page, and the article itself is the main page, so running text ahead of the first section opens the body at 1. Installed-toolchain tests read the table size back under each convention theme and the footer sequence back from a nasa report under every title-page and contents combination. Co-Authored-By: jason.han <hanhuijun@gmail.com> * fix(docrender): count nasa front matter on its own counter and set captions in the convention's face The nasa companion kept the page counter for the front matter and reset it on the first main page, so a body opening on a landscape wide page printed the physical page number and the next portrait page restarted at 1. The cover and front pages now leave the page counter at 0 and count in roman on a front counter, so the body opens at 1 whichever named page it starts on. nasa table captions take the sans face like the rest of the table; acm captions take the text face acmart sets them in. 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>
* fix(symbols): memoize ShortNamed per index generation Co-Authored-By: jason.han <hanhuijun@gmail.com> * test(symbols): treat the short-named cache as unobservable in snapshot comparisons 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: jason.han <hanhuijun@gmail.com>
…ation ends in Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
Contributor
Author
|
I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".
|
… the visit budget RelatedElements, WhereRelated and relationship-derived columns build a kind's edge table by scanning every workspace declaration, and charged each one to the query's visit budget, so any model past ~100k declarations failed every relationship query before traversing. The scan is now memoized in queryexec.Context.Related, shared across the queries a document evaluates, and left uncharged; traversal still pays one visit per element reached. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…n parameterless calls Co-Authored-By: jason.han <hanhuijun@gmail.com>
…uilt from takes an edit Co-Authored-By: jason.han <hanhuijun@gmail.com>
* fix(view): label transition triggers by the name their signal or operation ends in Co-Authored-By: jason.han <hanhuijun@gmail.com> * docs(views): trigger labels head their signal by its end name Co-Authored-By: jason.han <hanhuijun@gmail.com> * fix(view): take a trigger's end name from its last segment; keep () on parameterless calls 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>
* docs(examples): record analysis runs in the model and report them in a document Co-Authored-By: jason.han <hanhuijun@gmail.com> * docs(examples): state which recorded runs predate the relay edit Co-Authored-By: jason.han <hanhuijun@gmail.com> * docs(examples): note the sweep's exit status in the analysis-results demo Co-Authored-By: jason.han <hanhuijun@gmail.com> * docs(examples): re-record the pilot-differential baseline for the new example Co-Authored-By: jason.han <hanhuijun@gmail.com> * docs(project): update the differential figures for the new example Co-Authored-By: jason.han <hanhuijun@gmail.com> * docs(examples): build the analysis-results demo on the AnalysisRecords library Co-Authored-By: jason.han <hanhuijun@gmail.com> * docs(project): re-record the differential baseline for the library-based demo Co-Authored-By: jason.han <hanhuijun@gmail.com> * docs(examples): root the analysis-results report at the Records package so recorded runs join it Co-Authored-By: jason.han <hanhuijun@gmail.com> * docs(project): re-record the differential baseline for the Records-rooted demo Co-Authored-By: jason.han <hanhuijun@gmail.com> * docs(project): re-record the differential baseline after merging develop 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
marked this pull request as ready for review
September 24, 2026 16:10
* fix(doc): build relationship edge tables once per model, uncharged to the visit budget RelatedElements, WhereRelated and relationship-derived columns build a kind's edge table by scanning every workspace declaration, and charged each one to the query's visit budget, so any model past ~100k declarations failed every relationship query before traversing. The scan is now memoized in queryexec.Context.Related, shared across the queries a document evaluates, and left uncharged; traversal still pays one visit per element reached. Co-Authored-By: jason.han <hanhuijun@gmail.com> * fix(doc): rebuild relationship edge tables when the index they were built from takes an edit 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
Bot
force-pushed
the
release/0.9.0
branch
from
September 24, 2026 18:08
17c3cbd to
584cf48
Compare
…alking the tree Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
* fix(check): read the ~ operator sites the parser records instead of walking the tree Co-Authored-By: jason.han <hanhuijun@gmail.com> * fix(parser): record nested ~ operators in source order Co-Authored-By: jason.han <hanhuijun@gmail.com> * test(parser): exercise a checkpoint restore over recorded ~ operators 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>
…dation Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
devin-ai-integration
Bot
force-pushed
the
release/0.9.0
branch
from
September 24, 2026 20:18
584cf48 to
3b054bf
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
Release branch for 0.9.0, cut from
developat 1d02c68 (everything merged since v0.8.1, through #566). Perdocs/project/releasing.md:python3 scripts/changelog.py release 0.9.0folded the 229 unreleased fragments intoCHANGELOG.mdas## 0.9.0 — 2026-09-24(Added 140 / Changed 82 / Fixed 85 / Performance 7) and removed them fromchanges/unreleased/.client/python/opensysml/_version.py:VERSION = "0.5.0"→"0.9.0", so thev0.9.0tag publishes the matchingopensysmlwheel.Do not squash: merge with a merge commit, tag
mainasv0.9.0, then mergemainback intodevelop.How it was verified
On the release head (3b054bf):
gofmt -l .(empty),go build ./...,go vet ./...,make lint,go test -run TestStdlibConformance ./internal/workspace/libsgo test -race -count=1 -p 1 ./...— 83 packages, all passOPENSYSML_REQUIRE_TRAINING_CORPUS/PILOT_CORPORA/PILOT_LIBRARY_XMI/PSSM_SUITE=1,go test ./tests/corpus ./tests/identity) — pass, no baseline movement vs v0.8.1: training 100/100, pilot ratchets unchanged, PSSM referee 36 → 60 pass, validation census 156 → 157 faithful.make build-grpc+pytest client/python/tests/— 983 passed, 94 skipped;python client/python/scripts/check_version.py --tag v0.9.0prints0.9.0python3 scripts/changelog.py check,python3 scripts/check-doc-links.py,python3 scripts/check-doc-ids.py,go run ./cmd/doc-counts -check(already current)make proto-breaking BUF_BREAKING_REF=origin/main— no breaking schema changesundefined-operatorcheck no longer walks every node (about 7% offLoadModel); whole-binary-validateon Apollo 0.38 → ~0.45 s and a 12k-element generated model 0.37 → ~0.50 s (residual, attributed mostly to per-document dependency journaling in the resolver); LSP cold references after an edit slower by design, as noted in the changelog. Validate-hang repros (30exposes, 25-deep nested calls) complete in ~0.02 s.Checklist
make testandmake lintpass locallydocs/project/releasing.mdprescribesmake docs-countsrun if a gate count moved (compliance rows need nothing: the census is counted at docs build)F4,K5) in the body, docs, or changelogLink to Devin session: https://nasa-jpl-demo.devinenterprise.com/sessions/bb80cf5ab72a4155979b6b455ff3b1f8
Open in Devin Desktop: https://nasa-jpl-demo.devinenterprise.com/desktop/session/bb80cf5ab72a4155979b6b455ff3b1f8?variant=devin
Requested by: @HuiJun