Soft Assertions — Aggregate Failures at Block End

assertion.assert_all takes a pre-built list of spec dicts up front. There is no scoped accumulator you sprinkle check() calls into across interleaved actions and that raises everything at once on exit — the JUnit5 assertAll / Playwright expect.soft / AssertJ SoftAssertions pattern, the standard ergonomics for verifying many fields of a form without stopping at the first failure.

Pure-stdlib context manager; imports no PySide6.

Headless API

from je_auto_control import SoftAssertions

with SoftAssertions() as soft:
    soft.check(title == "Invoice", "wrong title")
    soft.check_equal(total, "$42.00", "wrong total")
    soft.check(date_field_is_visible(), "date field missing")
# on exit, raises once listing EVERY failed check (or nothing if all passed)

check(condition, message) records a pass/fail and never raises (it returns the bool, so you can branch on it); check_equal(actual, expected, message) is the equality shortcut. failures lists the failed messages, passed counts the passes, and assert_all() raises AutoControlActionException aggregating them. The context manager calls assert_all on a clean exit (and never masks an exception already propagating). Pass raise_on_exit=False to collect without auto-raising.

Executor command

AC_soft_assert evaluates a list of checks (each {value, op, expected, message} with op = eq / ne / gt / lt / contains / truthy) and returns {ok, passed, failures} — reporting all failures, not just the first; set raise_on_fail to raise instead. It is exposed as the MCP tool ac_soft_assert and as a Script Builder command under Flow.