Harden test and release quality gates - #33
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a release artifact validation gate by adding a validate_distribution.py script that builds and tests the wheel in an isolated environment. It also updates documentation, examples, and tests to adopt the HandlerArgs and guard conventions, raises the test coverage threshold to 90%, and treats warnings as errors. The code review feedback suggests improving the robustness of the distribution validation script by capturing both stdout and stderr during failures and using globbing to locate the built wheel to handle PEP 440 version normalization. Additionally, it recommends removing a redundant signature definition in _StateInGuard since it is now inherited from _ComposableGuard.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| details = (completed.stderr or completed.stdout).strip() | ||
| if details: | ||
| print(details, file=sys.stderr, flush=True) |
There was a problem hiding this comment.
In run_checked, the error reporting logic uses completed.stderr or completed.stdout to extract the command output details. If a command prints useful diagnostic information to stdout but also emits something to stderr, the stdout content will be completely swallowed and omitted from the error message.
It is safer and more robust to capture and print both stdout and stderr if they are present, ensuring no diagnostic output is lost during CI failures.
| details = (completed.stderr or completed.stdout).strip() | |
| if details: | |
| print(details, file=sys.stderr, flush=True) | |
| details = [] | |
| if completed.stdout: | |
| details.append(completed.stdout.strip()) | |
| if completed.stderr: | |
| details.append(completed.stderr.strip()) | |
| if details: | |
| print("\n".join(details), file=sys.stderr, flush=True) |
| def built_wheel(version: str) -> Path: | ||
| wheel = DIST / f"xstate-{version}-py3-none-any.whl" | ||
| if not wheel.is_file(): | ||
| fail(f"expected built wheel {wheel}; run 'poetry build' first") | ||
| return wheel |
There was a problem hiding this comment.
Constructing the wheel filename directly using f"xstate-{version}-py3-none-any.whl" can be fragile if the version string in pyproject.toml contains prerelease tags or local version identifiers (e.g., 0.7.0-alpha.1). Tools like Poetry normalize these version strings according to PEP 440 when building the wheel (producing filenames like xstate-0.7.0a1-py3-none-any.whl or xstate-0.7.0_alpha.1-py3-none-any.whl), which would cause this exact match to fail.
Falling back to globbing the dist/ directory when an exact match is not found makes the validation script much more resilient.
def built_wheel(version: str) -> Path:
normalized_version = version.replace("-", "_")
wheel = DIST / f"xstate-{normalized_version}-py3-none-any.whl"
if not wheel.is_file():
wheels = list(DIST.glob("xstate-*.whl"))
if len(wheels) == 1:
return wheels[0]
fail(f"expected built wheel {wheel}; run 'poetry build' first")
return wheel| __signature__ = inspect.Signature( | ||
| [ | ||
| inspect.Parameter( | ||
| "args", | ||
| inspect.Parameter.POSITIONAL_OR_KEYWORD, | ||
| ) | ||
| ] | ||
| ) |
There was a problem hiding this comment.
Since _ComposableGuard now defines __signature__, all subclasses (including _StateInGuard) will automatically inherit this attribute. The explicit definition of __signature__ on _StateInGuard (around line 172) is now redundant and can be safely removed to clean up the codebase and avoid duplication.
Summary
HandlerArgscontractsetup()fixtures and canonical examples toHandlerArgsand XState v5guardscripts/everywhere contributor and CI commands are documentedWhy
The suite passed while emitting 17 warnings from stale strict-setup fixtures and an unregistered test action. Canonical examples also still used legacy
condkeys and legacy registered handler forms.A 50% coverage floor did not reflect the repository's actual 92% coverage, and the release path tested the checkout but never proved that the built wheel could be installed and run without source-tree shadowing.
This adopts the artifact-validation pattern used successfully in the neighboring projects: validate what will actually ship, not only the source workspace.
Installed-wheel validation
scripts/validate_distribution.py:pyproject.toml--no-index --no-depsPYTHONPATHand disables user-site importspy.typedmarkerTest policy
Release behavior
The release workflow now builds the distribution, validates those exact artifacts, and then runs
poetry publish. It no longer rebuilds a different artifact during the publish command.Validation
poetry run python -m pytest tests/ --ignore=tests/test_scxml.py(413 passed, zero warnings)poetry run python -m pytest tests/test_scxml.py(54 passed, zero warnings)poetry run pytest tests/ --ignore=tests/test_scxml.py --cov --cov-report=xml(413 passed, 92.04%)poetry run mypy src/xstate/poetry run ruff format --check src/ tests/ scripts/ docs/examples/poetry run ruff check src/ tests/ scripts/ docs/examples/poetry check --lockpoetry buildpoetry run python scripts/validate_distribution.pyHEADused as both target and master referencegit diff --check