Skip to content

fix(view): render directed calc parameters as parameter pins in tree views - #1584

Merged
HuiJun merged 6 commits into
developfrom
fix/calc-parameter-pins
Oct 27, 2026
Merged

HuiJun merged 6 commits into
developfrom
fix/calc-parameter-pins

Conversation

@devin-ai-integration

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

Copy link
Copy Markdown
Contributor

What and why

Refs #1576 (the rendering half; the default-kind half — calcs defaulting to the action rendering — is a sibling change in default_kind.go).

A tree rendering (sysml -render '#tree:A::add', REPL and Jupyter %viz A::add, any render asTreeDiagram view) drew the directed parameters of a calculation as ordinary attribute members with membership (diamond) edges, and the anonymous return as a bare attribute:

calc add
  attribute x
  attribute y
  attribute

Root cause (internal/ir/view): treeNode appends every member that pinnedAt does not pin as a child node, and pinnedAt pins only port usages, case pins and constraint parameters; treeNodeShallow labels a child by declKind → Symbol.Notation(), which for a keyword-less directed usage is the parser's default kind attribute, so the direction was never read. The same held for action and constraint definitions and usages in a tree (#tree:Pins::Heat printed attribute b, attribute t).

What changed (view layer only; no parser or semantic change):

  • tree_parameters.go: treeParameter(owner, member) — a directed usage (in/out/inout/return, by the existing pinDirection) of a calc, action or constraint definition or usage — is drawn by pinParameter as a Port{Parameter: true, Direction, Name, Type, Inherited} of its owner's node instead of a child. treeNode and treeDescendants pin it at every depth (as ports and case pins already were at the depth bound or under a collapsed Layout).
  • The anonymous return : Integer is the pin result: parameterName takes the declared name, else Model.EffectiveNameOf, else result for a result parameter — the name of the Function::result it redefines (§7.19.2). A named return r is the out pin r.
  • Inherited parameters: a calc usage typed by a calc def (calc sum : Add { in x = a; }) pins in x, in ^y, out ^result — each once, the redefining one as its own, the def's others inherited (effectiveMembers already dedupes the redefinition; the pin carries Inherited). A calc nested in a part keeps its tree containment under the part.
  • Forms: text lists the pins under the node direction first (in x, in x : Integer under typings, mirroring how action pins print), dot draws them as pin cells (inputs above the head, outputs below, as action pins), d2 as nested pin shapes, mermaid (flowchart) and plantuml (class diagram), which have no pin on a tree node, list them in a parameters compartment of the label (labeller.parameterLines, the §8.2.3.17/19 parameters-compartment). The JSON/LSP data carries them as Ports of the node.
  • narrow.go: a tree keeps its parameter pins whatever parameter-symbols says (default off), the way it keeps a case's parameters as members and a port as a member — otherwise the default display would have hidden the parameters altogether.

Decision on action and constraint trees: §8.2.3.17 (action-def, action), §8.2.3.19 (calc-def, calc) and §8.2.3.20 (constraint-def, constraint) give all three node forms the same param-l* … param-r* … param-b* border pins, so a tree forced over an action or constraint def/usage pins its directed parameters the same way as a calc. Case parameters (subject, actor, …) are untouched: a tree still lists them as members (existing, documented behaviour); interconnection, action and mixed renderings are untouched.

Before / after on the reporter's model (-render '#tree:A::add', text; -render-show typings adds : Integer):

calc add              →   calc add
  attribute x               in x
  attribute y               in y
  attribute                 out result

Mermaid before / after:

n0("`*«calc»*               n0("`*«calc»*
**add**`")                  **add**
  n1("`*«attribute»*        parameters
**x**`")                    in x
  n2("`*«attribute»*        in y
**y**`")                    out result`")
  n3("`**attribute**`")
n0 ---|"◇"| n1
n0 ---|"◇"| n2
n0 ---|"◇"| n3

REPL %viz A::add text on this branch prints the same in x / in y / out result tree; the Jupyter kernel's default rendering goes through session.Render, the same path.

Specification basis

SysML v2.1 §7.19.2 (directed usages in a calc body are its parameters; return declares the result parameter; every calc has one), §8.2.3.17, §8.2.3.19 and §8.2.3.20 (action, calc and constraint nodes carry param-l*/param-r*/param-b* pins, optionally a parameters compartment of FeatureDirection UsageDeclaration entries), KerML §7.4.6 (an unnamed result parameter redefines Function::result). No row of docs/project/spec-compliance.md moves (rendering is not a compliance row).

Golden movements

  • New: internal/ir/view/testdata/calc-parameters.sysml with calc-parameters.{text,mermaid,dot,plantuml,d2}.golden and calc-parameter-definitions.{text,mermaid,dot,plantuml,d2}.golden (anonymous return, named return r, in/out/inout, calc def vs calc usage typed by it, a calc nested in a part def, an action def and a constraint def in a tree). The first commit records them on unmodified develop (attribute children); the second re-records them with the fix, so the diff between the two commits is the before/after.
  • Existing goldens moved: none (go test ./internal/ir/view/..., ./internal/doc/..., ./internal/frontend/..., ./cmd/..., ./tests/... all green without any other re-record).

How it was verified

  • go test ./internal/ir/view/... (new tree_parameters_test.go: pins and no edges for #tree: over the reporter's calc, text with and without typings, default Data keeps the pins, typed usage shows each parameter once with Inherited, action/constraint defs, collapsed Layout keeps the pins), ./internal/frontend/..., ./internal/doc/..., ./cmd/..., ./tests/...: green.
  • go build ./..., go vet ./..., gofmt -l . empty; python3 scripts/changelog.py check; python3 scripts/check-doc-links.py.
  • Full go test -timeout 40m ./...: green (no FAIL); make lint (staticcheck + gosec): ✓ Lint passed.
  • CI: green on the head after merging develop at e7506f7 (the earlier tools/referee/apijson baseline failure was develop's own, restated by docs(project): restate the api-json differential figures from the re-recorded baseline #1580). Dry-merged against fix(view): render calculations with the behaviour view and parameter pins by default #1583 (fix/calc-default-behaviour-view, 92d50ad): clean, view suite green on the merged tree.
  • By hand: bin/sysml -render '#tree:A::add' (text, -render-form mermaid, -render-show typings) and the REPL %viz A::add on this branch vs develop, output above.

Checklist

  • make test and make lint pass locally (see above)
  • Tests added or updated for the change
  • Documentation extended where it already covers the surface (docs/project/view-rendering-forms.md, docs/reference/cli.md)
  • Changelog entry added as changes/unreleased/calc-parameter-pins.fixed.md
  • baselines regenerated and make docs-counts run if a gate count moved — none moved
  • No internal work-item labels in the body, docs, or changelog

…t parameters

Directed parameters of calc, action and constraint definitions and usages
render as attribute children of their owner, and an anonymous result
parameter as a bare attribute. The fixture pins the rendering as it stands
before the fix.

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

…views

A tree drew the directed parameters of a calculation, action or constraint
definition or usage as attribute members with membership edges, and an
anonymous return as a bare attribute: treeNode appended every non-pinned
member as a child and labelled it by its default kind, never reading its
direction. They are now parameter pins of their owner's node, as §8.2.3.17,
§8.2.3.19 and §8.2.3.20 set them, the anonymous result named result, a usage
typed by a definition showing each parameter once. The text form lists the
pins direction first, DOT and D2 draw them, Mermaid and PlantUML list them
in a parameters compartment; a tree keeps them whatever parameter-symbols
says, as it keeps its members.

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

This comment was marked as resolved.

…its on

A parameter drawn as a pin has no node of its own, so its Note annotations
were dropped; they are now anchored to the owner's node, as narrowing
anchors a note at a pin the display leaves out.

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

This comment was marked as resolved.

…er's member

A note about one usage's inherited parameter (about a::x) reached every
usage inheriting it: the pin looked notes up by the declaring symbol. It
now resolves them as the member the owner has under the name, through
MemberLayoutOf and MemberNotesOf, as inherited start and done nodes do.

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

This comment was marked as resolved.

devin-ai-integration Bot and others added 2 commits October 27, 2026 16:52
…e, not its notation

localName quotes a name the notation cannot write bare, and LookupMember
reads the name itself, so a parameter named 'input value' lost its Layout
and Notes.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@devin-ai-integration
devin-ai-integration Bot marked this pull request as ready for review October 27, 2026 18:51
@HuiJun
HuiJun merged commit 5590df5 into develop Oct 27, 2026
53 checks passed
@HuiJun
HuiJun deleted the fix/calc-parameter-pins branch October 27, 2026 22:00
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