Skip to content

docs(language): a comparison on a relation is false where the relation has no row, whatever its operator - #947

Merged
FBumann merged 2 commits into
mainfrom
claude/gallant-franklin-6ndbd1-relation-no-row
Oct 23, 2026
Merged

FBumann merged 2 commits into
mainfrom
claude/gallant-franklin-6ndbd1-relation-no-row

Conversation

@FBumann

@FBumann FBumann commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Prompt: What would we change for stage 2? […] Yes

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 its NOT is 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): a RelationComparison compares the joined column, which is null at a key with no row. falsy_if_null reads that as false, and Not is ~falsy_if_null(...), which turns it into true. A RelationPairComparison compares 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 on e74f061 plus this commit.

  • pytest -q -n auto: 3063 passed, 3 skipped. That includes tests/test_reading_page.py, which runs reading.md.
  • python -m zensical build --strict: no issues.
  • prettier --check and typos --force-exclude on the two pages: clean.
  • compile-tex was not run. The PR changes no spec.

No test was added. I wrote one for the case checker: NOT end_of == 'b1' and NOT end_of overlap 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:

  1. A refusal on the safe side. end_of != 'x' and NOT end_of are 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.
  2. A missed overlap. NOT ends[bus0] == ends[bus1] and NOT ends[bus0] != ends[bus1] load as disjoint. At a line that ends (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 strict xfail first. 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 that connection leaves out, and where: "NOT connection == 'input'" keeps every one of them.


Generated by Claude Code

…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
@read-the-docs-community

Copy link
Copy Markdown

Documentation build overview

📚 mathspec | 🛠️ Build #35346658 | 📁 Comparing b6d15a2 against latest (e74f061)

  🔍 Preview build  

3 files changed
± reference/changelog/index.html
± reference/reading/index.html
± reference/language/expressions/index.html

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.

2 participants