Repository navigation
docs(language): a comparison on a relation is false where the relation has no row, whatever its operator - #947
Merged
Conversation
…n has no row, whatever its operator Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0113aUbLChfQVBrVR5FVQnJq
…sing row Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0113aUbLChfQVBrVR5FVQnJq
This was referenced Oct 23, 2026
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note
The following content was generated by AI.
What this changes
The conditions table and the engine guide now state that a comparison on a relation is false where the relation has no row,
!=included, so itsNOTis true there. specsolve already does this. The docs did not say it.What was checked, gates, and two findings in the case checker
What specsolve does (
src/specsolve/_engine/predicates.py): aRelationComparisoncompares the joined column, which is null at a key with no row.falsy_if_nullreads that as false, andNotis~falsy_if_null(...), which turns it into true. ARelationPairComparisoncompares two joined columns, so it is also null, and false, where either side has no row.Gates. pixi is not installed in this container, so the gates ran in a uv venv on Python 3.13, with
zensical==0.0.63. They ran one74f061plus this commit.pytest -q -n auto: 3063 passed, 3 skipped. That includestests/test_reading_page.py, which runsreading.md.python -m zensical build --strict: no issues.prettier --checkandtypos --force-excludeon the two pages: clean.compile-texwas not run. The PR changes no spec.No test was added. I wrote one for the case checker:
NOT end_of == 'b1'andNOT end_ofoverlap at a line with no row. It also passed with the checker's missing-row reading flipped to true. So it tested something else, and I dropped it. The case checker does not model this rule exactly, in two ways:end_of != 'x'andNOT end_ofare refused as overlapping, although they cannot overlap. The checker treats the column's value and the row's existence as independent, so it tries the combination "the value is anything else, and there is no row", which cannot happen.NOT ends[bus0] == ends[bus1]andNOT ends[bus0] != ends[bus1]load as disjoint. At a line thatends(missing: absent) leaves out, both comparisons are false, so both negations are true, and both cases claim the line. The checker reads a two-column comparison as only "equal" or "not equal", with no cell for "no row".Both are in
src/mathspec/_exclusivity.py, and neither is fixed here. The second is a bug, and it needs a strictxfailfirst. That belongs in a PR of its own.Why
A parameter's mask reads relations (#945), so this rule decides which rows a parameter has.
where: "connection != 'input'"keeps no pair thatconnectionleaves out, andwhere: "NOT connection == 'input'"keeps every one of them.Generated by Claude Code