Repository navigation
feat(pstack): add the statechart skill to draw TLA+ models as charts - #741
Merged
Merged
Conversation
Draws what a user sees as a Mermaid statechart generated from a TLA+ model. TLC checks the reader's rules as invariants. Each state is marked works, still wrong, or fixed by an open change, and each counterexample class is drawn as a numbered path. The skill also turns an agreed chart into a TLA+ skeleton and compares the drawn chart with the agreed one. Bumps pstack to 0.15.30 and regenerates the Claude Code harness tree.
- Check each rule in its own TLC run. The generated cfg names no rule, and a comment in it lists the rules. - Refuse TLC output from a run that failed or stopped early, and read counterexamples that a start state breaks. - Count steps that change nothing when a state is settled, number bugs that only the fixed model has after the current bugs, and escape quotes in captions. - Compare parallel regions as one machine, and refuse charts that were not drawn for comparison. - Refuse final states and duplicate captions, read class shorthand and states first named inside a composite, and match a never line to an exact state. - Rewrite SKILL.md to match, and run the skill script tests in CI.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit f149a2d. Configure here.
A -- at the top level of a chart opened a second root part that the parser never read, so every region after it was dropped. chart-to-tla wrote a one-region skeleton, and compare-charts could print "same". parseMermaid now refuses the chart. A unit test covers parseMermaid, chart-to-tla, and compare-charts. Co-authored-by: lauren <poteto@users.noreply.github.com>
compare-charts let a read or parse error escape, so a chart it could not read exited 1, the code for charts that differ. It now prints the file and the reason to stderr and exits 2, as SKILL.md says for a refused chart. Exit 1 now means only that the charts differ. Co-authored-by: lauren <poteto@users.noreply.github.com>
Replace the skill, its scripts, and its tests with the current version. statechart.mjs runs the whole flow with from-spec and from-chart, and its --help replaces the old Setup section. New features are a code-against-spec audit (--against), nested state boxes, parallel regions, guards, scoped charts, timer labels, and legend groups and colors chosen in the mapping. TLC comes from TLA2TOOLS and JAVA only. Without TLA2TOOLS, the scripts point to the TLA+ releases page and exit 2. Co-authored-by: lauren <poteto@users.noreply.github.com>
A failed mermaid-cli render printed "could not render" but still exited 0, or 0 with --expect-broken, so callers reported PNGs that did not exist. finish() now exits 2 whenever --png renders fewer PNGs than charts, and keeps the files it wrote. The --help exit codes say so, and a new test covers it with an npx that cannot launch a browser. Co-authored-by: lauren <poteto@users.noreply.github.com>
Rendered charts keep their full width. An edge label writes the opening words that its choices share once, instead of cutting the label with "…". --full-labels replaces --all-labels, and compare-charts refuses a chart drawn without it. The fix replay matches each bug step by the screens and step words that the reader sees, and two states get at most one arrow. Each rule also runs as a TLC CONSTRAINT, so a rule that stays broken stops at its first bad state instead of flooding TLC with counterexamples. statechart.mjs passes its arguments and models through functions instead of module globals. The --png exit code from the previous commit is now part of the source. Co-authored-by: lauren <poteto@users.noreply.github.com>
…the comment and assignment cleanups Co-authored-by: lauren <poteto@users.noreply.github.com>
Co-authored-by: lauren <poteto@users.noreply.github.com>
SmailG
added a commit
to SmailG/claude-cursor-plugins
that referenced
this pull request
Oct 22, 2026
…ill to draw TLA+ models as charts (cursor#741) chore: sync with cursor/plugins — feat(pstack): add the statechart skill to draw TLA+ models as charts (cursor#741)
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.

Why
A TLA+ model is hard to review for anyone who does not read TLA+. The new
/statechartskill draws the states that an app's user sees as a Mermaid statechart, built from the state graph that TLC explores. The chart and the checked model are one object, so a PM or a designer can judge the design from the chart.What changed
pstack/skills/statechart/adds the skill, a shared library, four scripts, and 58 unit tests.statechart.mjs from-specchecks each rule and draws the charts.--fixedshows what a fix changes, and--againstaudits code against an existing spec.from-chartwrites a TLA+ skeleton from a chart that the PM agreed to.scripts/model/OutputFolder.tla, with its.cfgand mapping, models two runs that share one output folder. A test draws its chart and checks that its five rules hold. Five mutants each remove one guard from the model, and the test checks that each mutant breaks the rule that its guard protects.poteto-helplist the skill. The harness tree gets its generated copy, and the pstack version goes from 0.15.29 to 0.15.30.validate-plugins.ymlruns the skill tests withnode --test.Scope
TLA2TOOLSandJAVA. WithoutTLA2TOOLS, they say where to downloadtla2tools.jarand exit 2.chart.pngdoes not stay behind.unshare. Each skips when its tool is missing.Blast Radius
The skill is new, and nothing outside it imports its scripts. The CI change adds one
node --teststep.Verification
Naturals.tladirectly in the run's own TLC temp folder. The nightly writes it one folder deeper, still inside that temp folder. The scripts work, and only the test's path check is too strict.validate-plugins.mjs,check-pstack-docs.mjs,generate-pstack-harness-trees.mjs --check,quick-validate, andlint-skill-frontmatterpass.The charts below come from the test chart, an invented notes app with one rule. The badge never shows Synced while the app is offline.
statechart.mjs from-chart notes-app.mmd --expect-broken NeverSyncedWhileOffline --title "Notes app sync" --pngfinds the one path that breaks the rule and draws both charts. These scripts write the samechart.mmdandbug-1.mmdthat the images show.