Skip to content

Show the verifier's states of a state error on the state machine - #160

Merged
CatarinaGamboa merged 1 commit into
mainfrom
feat/verifier-state-context
Oct 25, 2026
Merged

CatarinaGamboa merged 1 commit into
mainfrom
feat/verifier-state-context

Conversation

@CatarinaGamboa

Copy link
Copy Markdown
Collaborator

Why

Until now, the state machine view got the receiver's possible and accepted states from liquidjava-fsm, which re-read the error's expected and found predicates as text. The verifier now computes those states with the SMT solver and reports them on StateRefinementError#getContext() (liquid-java/liquidjava#421). fsm 0.2.0 dropped its error context and only draws diagrams (liquid-java/liquidjava-fsm#12). This PR switches the view to the verifier's answer, so the diagram never contradicts the error next to it.

What

Dependencies: liquidjava-verifier 0.0.36, liquidjava-fsm 0.2.0 and Spoon 11.5.0, the version the verifier now uses.

Server

  • StateRefinementErrorDTO builds the diagram with StateMachineParser.parse(declaration file, context.receiverClass()), so a file that declares several classes shows the receiver's class.
  • The new StateMachineDTO and StateErrorContextDTO keep the shape the webview already reads (stateMachine.errorContext). The error context now has calledMethod, receiver, possibleStates, acceptedStates, validStates and invalidStates.
  • The verifier names each state in every state set. The diagram shows the first set, and a state is marked so that the marks are never wrong:
    • It is valid only if the call is accepted in every possible combination with that state.
    • It is invalid only if the call is accepted in none of them.
    • Otherwise it stays unmarked. When the accepted states depend on the arguments, nothing is marked.
    • With one state set, this gives the same marks as before.

Client

  • getStateErrorFocus uses the server's lists directly. The fallbacks to definiteFoundState and actualStates are gone, and so are expectedCondition and foundCondition, which nothing displayed.

Fixed: the setHint test, which broke when hints became a list (liquid-java/liquidjava#410).

Output for the fsm study fixtures (DatagramSocket and tree node), serialized by the server:

{"calledMethod":"receive","receiver":"socket","possibleStates":["bound","closed"],"acceptedStates":["unbound","bound","connected"],"validStates":["bound"],"invalidStates":["closed"]}
{"calledMethod":"getFirstChild","receiver":"root","possibleStates":["childrenAllowed"],"acceptedStates":["maybeHasChildren"],"validStates":[],"invalidStates":["childrenAllowed"]}

These are the same marks the view showed before for these examples.

Follow-ups

Tests

  • Server: mvn test, 27 tests pass, including the new StateErrorContextDTOTest: one state set, several sets with a partly accepted state, and unknown accepted states.
  • Client: vitest, 71 tests pass, and tsc is clean.

🤖 Generated with Claude Code

Bumps the verifier to 0.0.36, liquidjava-fsm to 0.2.0 and Spoon to 11.5.0.
fsm now only draws the diagram, picked by the error's receiver class, and
the possible, accepted, valid and invalid states come from the verifier's
StateErrorContext instead of fsm's reading of the predicates' text. A
state of the diagram is marked only when every possible combination with
it agrees, so the marks stay true for classes with several state sets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@CatarinaGamboa
CatarinaGamboa merged commit f1c258a into main Oct 25, 2026
3 checks passed
CatarinaGamboa added a commit that referenced this pull request Oct 26, 2026
## Description
Closes #155.

Makes the State Machine view easy to reach from a state error and keeps
the error there. Before, the only way in was a small icon on the error
in the Verification tab, and clicking the State Machine tab dropped the
error, so getting back meant going through the Verification tab again.

This replaces the earlier version of this PR, which listed the errors
beside the diagram. That worked for one error but crowded the view with
several, so the view now shows one error at a time.

- **Opens on the first error.** The State Machine tab shows the first
state error of the current file, focused, as #158 draws it.
- **Keeps the error.** An error chosen with **Show in state machine** or
the arrows stays shown after visiting another tab. Opening another file
shows its first error instead.
- **Follows the cursor.** When the cursor reaches a state error in the
editor, the view shows it. A choice made in the view is kept until the
cursor reaches another error, and a new verification does not undo it.
- **Several errors.** `‹ 1 of 3 ›` steps through the state errors of the
current file in source order. The stepper only appears with more than
one error.
- **Badge.** The State Machine tab shows the number of state errors in
the current file. This is the number of **Show in state machine**
buttons under *Current file* in the Verification tab, and the `of 3` in
the stepper.
- **Back to the error.** **View error**, next to the stepper, returns to
that error in the Verification tab. The **Show all** / **Focus on
error** toggle from #158 now sits with the legend, since it changes the
diagram and not the error.
- **Way in.**
- The `type-hierarchy` icon on state errors is replaced by a labelled
**Show in state machine** button at the top of the error, below its
title.
- State errors also get a **Show in state machine** CodeLens in the
editor. It reuses `liquidjava.showView` with an optional `'fsm'` tab
argument.
- **Re-verification.**
- The shown error is matched again by position. If an edit moved it, it
is followed only when its call had exactly one error before and after,
so it never jumps to a sibling.
  - Fixed errors disappear.
- The diagram only re-renders when what it shows changed, so panning is
kept.
- **Walkthrough.** The text describes the new flow.

## Screenshots
A throwaway copy of the UDP chat client with two more state errors:
`bind` on a bound socket and `connect` after `close`. Taken after
rebasing on #160, with the DatagramSocket spec fix that drops `old()`
from the `closed(this)` preconditions.

**1. Verification tab.** **Show in state machine** at the top of each
state error, the badge on the tab, and the CodeLens in the editor
(`State Refinement Error | Show in state machine`, cut off at the editor
edge here).

<img width="900" alt="Verification tab with Show in state machine
buttons, tab badge and CodeLens"
src="https://raw.githubusercontent.com/liquid-java/vscode-liquidjava/pr-screenshots/159/1-verification.png?v=3"
/>

**2. Opening the State Machine tab** shows the first error. **3. The
next error.**

<img width="560" alt="First state error, 1 of 3"
src="https://raw.githubusercontent.com/liquid-java/vscode-liquidjava/pr-screenshots/159/2-first.png?v=3"
/> <img width="560" alt="Second state error, 2 of 3"
src="https://raw.githubusercontent.com/liquid-java/vscode-liquidjava/pr-screenshots/159/3-next.png?v=3"
/>

**4. After visiting Context and coming back,** the same error is still
shown.

<img width="560" alt="State Machine tab after coming back, still 2 of 3"
src="https://raw.githubusercontent.com/liquid-java/vscode-liquidjava/pr-screenshots/159/4-back.png?v=3"
/>

**5. View error** returns to the `bind` error in the Verification tab
and outlines it.

<img width="560" alt="Verification tab with the bind error outlined"
src="https://raw.githubusercontent.com/liquid-java/vscode-liquidjava/pr-screenshots/159/5-view-error.png?v=3"
/>

## Tests
Rebased on main after #160 (verifier 0.0.36, liquidjava-fsm 0.2.0, Spoon
11.5.0):
- `npm run lint` and `npm run test:typecheck`: clean.
- `npm run test:unit`: 89 passed. The new tests are in:
- `state-errors.spec.ts`: errors of the current file in source order,
re-finding after verification;
- `fsm.spec.ts`: stepper, badge, an error from another file, the focus
toggle in the legend;
- `script.spec.ts`: opening on the first error, the badge counting only
the current file, tab memory, stepping, cursor-following, View error,
opening from the editor, a new file, no re-render without changes, the
button at the top of the error.
- `npm test` (VS Code): passing, including the state-errors integration
test, which checks the CodeLens and the message it sends to the webview.
- Server `mvn test` and the local smoke test: passed.

Follow-ups stacked on this PR: #161 (errors the verifier cannot mark on
the diagram) and #162 (tab order).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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