Skip to content

Make backend-outage skips diagnosable - #97

Merged
Robbie1977 merged 6 commits into
mainfrom
diagnosable-outage-skips
Aug 30, 2026
Merged

Make backend-outage skips diagnosable#97
Robbie1977 merged 6 commits into
mainfrom
diagnosable-outage-skips

Conversation

@Robbie1977

@Robbie1977 Robbie1977 commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

What changed

"155 skipped: backend outage" — and equally "1 skipped" — gave a reader nothing to debug with and no basis for a decision to ignore. Whenever anything skips, the suite now writes skipped_tests_report.md/.json: every skipped test with its reason, grouped by reason with per-group test lists in details folds — an ordinary marker skip shows up just like an outage skip. When the circuit breaker tripped, the outage detail sits on top: the test that hit the backend first with the URL of the failing call (clickable) and how it failed, and each health probe's verdict (HTTP status or exception, with elapsed time). Skip messages carry the failing call or probe inline, and the existing skip report embeds the markdown — job summary, the neutral "Run completeness" check and the sticky PR comment all carry it.

Also rides along: the examples workflow broke on Python 3.8 after #96 because pytest errors at startup on ignore::<class> filters naming a warning class that old marshmallow lacks — the filter is now category+module based (ignore::DeprecationWarning:marshmallow.*), version-proof, with user-code DeprecationWarnings still shown. The example shape comparison treats numpy scalars (int64 counts out of pandas on that environment) as numbers. And the report's first catch is fixed rather than documented: test_the_public_entry_point_reaches_the_decorated_original skipped on every CI run because Run Tests pins VFBQUERY_CACHE_ENABLED=false — it now verifies the caching patch chain in a subprocess with caching enabled when the ambient import ran unpatched, so it passes everywhere and never skips. Steady state for Run Tests is now 0 skipped.

How to test

pytest tests/test_outage_reporting.py; for the full loop, run a file containing a ConnectionError-raising test and a @pytest.mark.skip test and read the generated skipped_tests_report.md — both appear, grouped by reason, with the backend failure's call URL linked.

'155 skipped: backend outage' gave a reader nothing to debug with and
no basis for deciding to ignore. The circuit breaker now records every
event to a shared per-run log: the test that hit the backend first,
with the URL of the failing call (pulled from the exception chain) and
how it failed; each health probe's verdict (HTTP status or exception,
with elapsed time); and every test the breaker fast-skipped. Skip
messages carry the failing call or probe inline, and at session end the
master aggregates the log into outage_report.md / outage_report.json.

The existing skip report embeds the markdown — job summary, the
neutral 'Run completeness' check, and the sticky PR comment all carry
it, with the failing URLs as clickable links and the skipped-test list
folded into a details block; the warning annotation gains a one-line
digest. Verified end to end with a simulated trigger under the real
conftest (during which the owl.virtualflybrain.org probe genuinely
timed out and was named in the fast-skip message — the feature
demonstrating itself).
'1 skipped' was as opaque as '155 skipped': the report only covered the
circuit breaker, so an ordinary marker skip (tests/test_preview_warm.py's
'caching disabled: no patch layer to verify') stayed invisible without
opening the Actions log. A pytest_runtest_logreport hook now records
EVERY skip with its reason (xfails excluded), the report groups them by
reason with per-group test lists in details folds, and the outage
sections (first failing call with clickable URL, probe verdicts) sit on
top when the breaker tripped. Renamed outage_report.* to
skipped_tests_report.* to match, written whenever anything skipped.
The examples workflow's move to pytest (PR #96) broke it on Python 3.8:
pytest resolves ignore::<class> filters at startup and exits 4 when the
class does not exist, and that job's older marshmallow predates
ChangedInMarshmallow4Warning. Both classes subclass DeprecationWarning,
so filter DeprecationWarning from the marshmallow module instead —
version-proof, and user-code DeprecationWarnings still show. Verified
the suite still runs with zero marshmallow warnings leaking.
The Python 3.8 examples job failed with 'recorded number, live is
int64': on that environment pandas hands counts back as numpy.int64,
which the coarse type bucket did not recognise as a number, while the
JSON recordings necessarily hold plain numbers. The environment's box
type is not a schema property — numpy scalars register with the
numbers ABCs (bool_/str_ matched by name), so int64 counts, float64
scores and numpy bools now land in the same bucket as their recorded
JSON forms. A recorded number turning into a string still fails.
A nodeid like test_the_public_entry_point_reaches_the_decorated_original
still forced the reader into the source tree to understand what went
unverified. Every recorded skip and trigger now carries the test's
location and the first line of its docstring; the report renders each
test as a link to the exact file and line at the run's commit (when the
GitHub Actions environment provides one) followed by that summary. Skips
are recorded from the makereport wrapper — which holds the item — rather
than a separate logreport hook.
test_the_public_entry_point_reaches_the_decorated_original skipped
whenever VFBQUERY_CACHE_ENABLED=false — which the Run Tests workflow
always sets, so CI never once verified the chain it exists to guard and
the skip sat unexplained in every run (it was the '1 skipped'). Caching
being off is a property of the test process, not of the code under
test: when the ambient import ran unpatched, the same assertions now
run in a subprocess that imports vfbquery with caching enabled — the
real import-time patch path, production's default. No backend is
contacted either way; the assertions only inspect bindings. The test
now passes in both modes and never skips.
@Robbie1977
Robbie1977 merged commit 73b363b into main Aug 30, 2026
6 checks passed
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