✅ test(spec): the Fields tables must name fields that exist - #768
Conversation
Three spec sections have now been found describing fields the class does not have -- `Scale` (GalacticDynamics#750), `Shear` (GalacticDynamics#762), and `Tangent` here -- each by accident rather than by looking. This closes the class: every `!!! info` section with a **Fields** block is checked against `dataclasses.fields`. `Tangent` was the fifth stale entry. It listed a `manifold` field that has never existed; the manifold is reached through `M`, a property derived from the chart. Its "Post-init checks" were wrong too -- the hook is `__check_init__`, and it calls `M.check_chart(chart)`, not `manifold.has_chart(chart)`. Two deliberate limits: Sets, not sequences. `Translate` defines its own `__init__` whose parameter order is the useful one to document and differs from `dataclasses.fields`; enforcing order would fail a section that is right. Per-type sections only. The exported-objects table is a curated summary -- the `coordinax.charts` row omits 50-odd class names on purpose -- so it is not an `__all__` mirror and is left alone. Both spellings of a Fields block are parsed, bullet list and table, and a guard test asserts the parser still finds sections: a regex that quietly matches nothing would pass forever. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a regression test to keep docs/spec.md’s per-type Fields blocks in sync with actual dataclass fields, preventing spec drift in documented public APIs. Updates the Tangent spec section to remove a non-existent manifold field and to describe the correct init-time validation behavior (M derived from the chart; checks performed in __check_init__).
Changes:
- Introduce a unit test that parses
docs/spec.md!!! infosections with Fields blocks and asserts set equality withdataclasses.fields(...). - Fix the
Tangentspec section by removing the phantommanifoldfield and correcting the init-checks description.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| tests/unit/test_spec_fields_match_code.py | New test that enforces Fields blocks in the spec match real dataclass fields (membership, not order). |
| docs/spec.md | Correct Tangent documentation: remove non-field manifold, clarify M is derived, and fix init-checks text. |
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #768 +/- ##
==========================================
+ Coverage 96.57% 96.66% +0.08%
==========================================
Files 267 267
Lines 8963 9079 +116
==========================================
+ Hits 8656 8776 +120
+ Misses 307 303 -4 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
The follow-up I flagged on #762. Three spec sections have now been found describing fields
the class does not have —
Scale(#750),Shear(#762), andTangentbelow — every oneby accident rather than by looking. This closes the class.
Every
!!! infosection with a Fields block is now checked againstdataclasses.fields. Ten sections qualify, out of 140.It found a fifth stale entry immediately
Tangentdocumented amanifoldfield that has never existed —dataclasses.fields(Tangent)is(data, chart, basis, semantic, frame). The manifold isreached through
M, a property derived from the chart.The same section's "Post-init checks" were wrong in two more ways: there is no
__post_init__onTangentat all, and the check it names does not exist either.Corrected, including the note that
Mis derived rather than stored — which is exactlythe fact the phantom row obscured.
Two deliberate limits
Sets, not sequences.
Translatelooked like a second defect: the spec orders itsfields
(delta, chart, semantic_kind, right_add)whiledataclasses.fieldsgives(delta, chart, right_add, semantic_kind). It has a custom__init__, and the specmatches the constructor — the order a reader would actually use. Enforcing
dataclasses.fieldsorder would have failed a section that is right, so only membershipis checked.
Per-type sections only. The exported-objects table earlier in the spec is a curated
summary — the
coordinax.chartsrow omits 50-odd class names on purpose — so it is not an__all__mirror and is deliberately untouched. (I nearly built that check during #730before noticing.)
The test can actually fail
Verified in both directions rather than assumed:
Both spellings of a Fields block are parsed — bullet list and markdown table, both in use
— and a guard test asserts the parser still finds at least eight sections, since a regex
that quietly stops matching would pass forever and prove nothing.
tests/unit+docs: 3868 passed, 5 skipped.