Assert
YAML-driven test orchestration for hardware validation
Station Tools
Test Runner
Run tests, monitor live execution and step verdicts in real time
Test Results
This station's results, measurements and pass/fail trends
Packages
Discover and manage installed test packages and runner capabilities
YAML Validator
Validate and preview test definition YAML before deploying
Station Config
View and manage this station's runtime configuration
Central Services
APIs
AI Assistant (MCP)
Connect your AI assistant to this station
Select your AI client below for setup instructions.
Run this command once in your terminal to register this station with Claude CLI:
mcp add --transport http assert-demo-station https://api.demo.esharp.se:7004/mcp
Assert 2.7.1
What's new
2.7.1
2026-09-23
- ### The connectivity banner stops polling when it is disposed (UI 1.30.1)
- Leaked banner timers filled the disk** (Trace bug #35). The banner created its polling timer
- after the first awaited connectivity probe, so a banner disposed during that probe (a prerender
- pass, an early circuit teardown) started a timer nothing ever stopped. On the demo about 1,500
- leaked timers polled every 15 s, and their HttpClient log lines filled the disk. Polling is now a
- `PeriodicTimer` loop cancelled on dispose that only runs on a live circuit, and HttpClient logging
- drops to Warning.
2.7.0
2026-09-23
- ### Sub-sequences are groups in the step list, and the progress bar no longer drops back (Contracts 1.26.0, UI 1.30.0, MCP 2.26.0)
- The progress bar went back to 0% whenever a sub-sequence started** (bug #23). A sub-sequence's
- steps run through the same step pipeline as the test's own, and their StepProgress events carried
- only the sub-sequence's numbering ("step 1 of 3"), which the Test Monitor and the Station Monitor
- showed as the test's progress. The events now also carry the test's own top-level position
- (`overallStep` / `overallTotalSteps`) and an `overallProgress` fraction: a sub-sequence counts as its
- calling step and fills that step's share in proportion to its own progress, recursively, and the
- value never decreases within a run. Both monitors show "Step k of N" at the top level and, while a
- sub-sequence runs, its name and its own step n of m underneath. What goes to Orchestra was already
- top-level (only the test's own steps call the heartbeat hook); a test now pins that.
- Sub-sequences are collapsible groups in the Test Monitor** (feature request #3). The step list
- was flat, and the only cue that a step belonged to a sub-sequence was a second spinner. Each
- sub-sequence is now a group under the step that calls it, its steps indented, nested sub-sequences
- nested the same way. The calling step's row is the group header: the sub-sequence's name and file,
- its verdict (running/pass/fail/aborted/skipped), steps finished of steps declared (a terminated
- sub-sequence shows e.g. 2/5), and duration, so a collapsed group still shows its result. A group
- opens when its sub-sequence starts and closes when it passes and the run moves on; one that failed
- or aborted, or holds a failed step, stays open. Once the operator opens or closes a group by hand,
- that group is left as they set it for the rest of the run. The finished run on screen and the
- Station Monitor's slot detail use the same component and group the same way. Aborted steps are now
- coloured as such rather than left unstyled.
- Step events say where a step sits.** Additive, all null from an older station, so older clients
- and older stations keep working: StepProgress gains `parentStepExecutionId`, `depth`, `sequencePath`
- (every enclosing sub-sequence, outermost first: calling step id, name and start time, sub-sequence
- name and file, position and step count) and the overall fields above; StepCompleted gains
- `parentStepExecutionId` and `depth`. The whole path rides on every nested step, so a monitor that
- joins mid-run rebuilds the enclosing groups from the next event, although the calling steps' own
- start events went out before it connected and are not stored until their sub-sequence finishes.
- Stored steps are grouped too, derived from their run intervals.** `StepExecution` has a
- `ParentStepExecutionId` column, but the station cannot fill it: a calling step is stored only when
- its sub-sequence finishes, after its children, so the children's foreign key would name a row
- Orchestra does not have yet. The steps' start and end times are stored, and a sub-sequence's steps
- run strictly inside their calling step's interval, so the station derives the link from them
- (`StepHierarchy`). `GET /api/test-results/{id}/steps` (and so `get_step_results` /
- `get_test_report_full`) fills `parentStepExecutionId` and `depth` when the response holds the whole
- of a finished run (unfiltered, one page); the Test Monitor places rows it reloads after a reconnect
- the same way. A stored parent link, once Orchestra keeps one, takes precedence.
- MCP 2.26.0: `poll_test_progress` step events add `overallStep`, `overallTotalSteps`,
- `overallProgress`, `depth`, `parentStepExecutionId` and `subSequence`.
2.6.0
2026-09-23
- ### Fixed
- Concurrent executions shared their test variables** (bug #20). A test's `variables:` block was
- written to the station-global variable scope (`global:{name}`), with no execution id, and every
- read fell back to it. On a parallel station two runs declaring the same name overwrote each other,
- and any run could read a value an earlier run of another test had declared: nothing ever removed
- them. The block is now written to the execution's own scope (`exec:{executionId}:{name}`); lookups
- go local → execution → global, and both per-execution scopes are removed when the run ends,
- whatever its verdict. Within one run nothing changes: templates, runner variables, the debugger's
- variable view and edits, sub-sequence parameters and .NET/Python hand-over see the same values as
- before. The station clears the leftover `global:*` keys once at startup (Redis persists them).
- A step whose method threw published the previous invocation's readings as its own** (bug #19).
- In a sub-sequence invoked once per connector, a thrown CON4 read still emitted every declared
- measurement, resolved against variables holding CON3's values, under CON4's group. Two causes,
- both fixed:
- A failed step's measurement whose `value:` reads a variable the step did not write is now
- recorded **not acquired**: FAIL, with no value (all value fields null, so it stays out of the
- statistics; the report and live monitor show "not acquired"), and listed in the step's error.
- A value the failing step did write is still shown and FAILED, as before (bug #3). A measurement
- whose template never resolved is now also recorded without a value, instead of a fabricated
- midpoint. A failed step's `outputs:` no longer copy a variable it did not write.
- A sub-sequence file declared its `variables:` only when "not already in scope", so from the
- second invocation on it kept the previous invocation's values, and everything its steps had
- created stayed readable. Each invocation now starts afresh: what the file itself brought into
- scope returns to its declared default or is cleared. Variables the caller owns - declared by the
- test, set before the file was first invoked - are inherited exactly as before.
- Contracts 1.25.0: `MeasurementPointBase.Acquired` (default true) carries the not-acquired state
- over SignalR; `MeasurementValueEntity.GetFormattedValue()` shows "not acquired" for a value-less row,
- and `MeasurementPointDto.Acquired` (set by the step-results endpoint from `IsAcquired()`) carries it
- to the report.
- UI 1.29.2: the Test Monitor rebuilt a reloaded not-acquired numeric measurement as `0`
- (`NumericValue ?? 0`); it now takes `Acquired` from the DTO and shows "not acquired", as live.
2.5.0
2026-09-23
- ### The fleet sees every slot, and the assistant knows the station has more than one (Contracts 1.24.0, MCP 2.25.0)
- A parallel station no longer reports Idle while a test is still running** (bug #21). The status
- sent to Orchestra held one execution: each start overwrote the previous one, step progress came
- from whichever run reported last (the hook did not even know which run it was), and the first run
- to finish set the station Idle and cleared everything while another slot was still driving
- hardware. The station now tracks every running execution by id, stays `Running` while any slot is
- busy, and attributes each step to the run that reported it. Concurrent runs push one at a time,
- each push built from a single snapshot, so the last push to reach Orchestra is always the latest.
- The heartbeat carries `activeExecutions` and `slotCount`.** One entry per busy slot - slot index,
- execution id, test name, serial number, step index/total/name, start time - ordered by slot, and
- the number of slots (`MaxParallelExecutions` clamped to the runner pool). Both are additive: an
- Orchestra that predates them ignores them. The single-execution fields are still sent and now
- describe the lowest busy slot, so a single-slot station reports exactly what it always did. The
- list is always present (empty when idle), so Orchestra can tell an idle station from one too old
- to report slots.
- `start_test` no longer tells the assistant the station runs one test at a time** (bug #22). It
- said parallel execution was not supported and that start_test must never be called while another
- run is active, so an assistant never used the slots a parallel station has. It now says the station
- takes up to its configured slots, that a 409 means every slot is busy (or MES rejected the start),
- and that repeats run one after another only when the user asks for that or there is one slot.
- `get_station_info` reports the slots**: `slots.slotCount`, `poolCeiling`, `busy` and
- `activeExecutions`. The 409 from `POST /api/testexecution/run` at capacity now also lists
- `activeExecutions` (slot, test, serial number, progress) next to `activeExecutionIds`.
2.4.1
2026-09-23
- ### Fixed
- The Test Monitor's run inputs stayed editable while a test ran** (bug #17). The test file, serial
- number, operator, tags, MES option and the debug toggle could all be changed mid-run, so the form
- could show a serial or test that was not the one under test. While an execution is active -
- running, paused, waiting on a prompt, or parked in a debug session - they are now disabled as one
- group, with a note saying so, and become editable when the run finishes. Abort stays available.
- After a reload or reconnect the form shows what the station is running**, not what it last held.
- A monitor that joins a run (reload, a new circuit, a run started from MCP/REST/another tab) reads
- the execution's own test file, serial number, operator and tags from the station.
- UI 1.29.0 -> 1.29.1.