Skip to content

emrg: a cross-reference names a symbol the tree has - #2540

Merged
argszero merged 1 commit into
masterfrom
feature/cross-references-resolve
Oct 23, 2026
Merged

argszero merged 1 commit into
masterfrom
feature/cross-references-resolve

Conversation

@argszero

Copy link
Copy Markdown
Owner

Closes #2539

read_task_run_records's docstring sent a reader to Daemon._evolution_count. There is no Daemon class here — it is EmrgServer — so the pointer landed on nothing while the module around it stayed healthy. The same docstring's TaskHandler._load_task_runs is correct, so the shape was written right and one name drifted with the rename.

The guard

tests/test_docstring_cross_references_resolve.py holds Sphinx cross-reference roles — func, class, meth, data — against the names this tree binds: a def, a class, an assignment target or an import under emrg/, scripts/ or tests/, or a builtin.

A dotted name is decided on its head only: static resolution cannot follow os.path.expandvars, so the head must be imported in the citing file, bound in the tree, or a builtin. That is the decidable half — do not cite through a module the file never opened.

attr stays out of the scan. It names a member of an object, not a binding a module holds, so this tree's attr references are ctypes _fields_ entries; a rule reading them as module bindings would report three sites and be wrong three times. That exemption is measured in an arm, not asserted in prose.

Siblings, and why a third file

Two guards already read a pointer in prose — tests/test_check_citation_resolves.py for a tests/test_x.py::node citation that must collect, and tests/test_docstring_title_citations_resolve.py for a "see Title in the module docstring" citation that must land on a heading. This subject resolves by a third rule, so it gets a third file.

Measurement

On master @ d3c8807c: 251 role references across the three directories, 1 unresolved — the site fixed here. Every false positive the earlier, narrower rule produced (a cross-module class reference, three ctypes fields, two standard-library dotted names) is now silent, and each is a test arm.

Verification

  • Mutation, three arms, each printing its mutated line: reverting the fix reddens test_every_cross_reference_in_the_tree_resolves; emptying the tree-wide symbol set reddens test_a_name_bound_in_another_module_resolves and the tree reading; making dotted heads resolve unconditionally reddens test_a_dotted_reference_through_a_module_never_opened_is_reported.
  • Full suite 5787 passed, 35 skipped; import and --help clean.
  • Two guard failures found and fixed while checking: the walk now judges its skips on the path relative to its walk root (test_walk_skips_read_their_root.py — an absolute path's parts let an ancestor named node_modules silence the walk), and the new file is staged so the index-derived scans reach it.

What it does not measure

Whether the cited name is the right one — a reference to a real function that stopped doing what the sentence says is invisible. And it does not read a bare backticked name in prose, which is how the motivating defect was actually spelled: a backtick is not a declaration, and the tree holds hundreds naming files, config keys and protocol frames rather than code.

CI: pending.

@argszero

Copy link
Copy Markdown
Owner Author

Handled by #2540

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20261023-185410

Read the diff, not the page. The guard holds Sphinx cross-reference roles against the names this tree binds, and it earned its place on the first run: it fired on Daemon._evolution_count in scheduler.py, a class this tree renamed to EmrgServer — the pointer survived the rename and nothing else asked.

The four decisions I checked are the four that would have made a weaker guard report prose: the scope is tree-wide rather than the citing module (a cross-module class reference resolves), a dotted name is decided on its head rather than guessed at its tail, attr is outside the scan because it names a member rather than a binding (this tree's are ctypes fields), and the backticked-prose shape that started the work is written down as out of reach instead of quietly skipped.

check-merge-freshness.py reads FRESH — merge base d3c8807c is master's tip — so the green CI is about this merge's tree. test 3m41s, test-windows 4m7s.

One thing to carry forward rather than fix here: the guard's own new file tripped two tree-wide guards on first run (a walk judging absolute-path parts, and a staged-file index). Both are fixed in the commit, and they are the reason a new scan must be run against the full suite, not its own file.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20261023-185726

Second vote, on the landing tree rather than the checkout, because the head is now one commit behind the base I merged an hour ago: check-merge-plan-suite.py 2540 planned against master 450c3f0a, built tree 7c38ac00, and the suite is green there — 5797 passed, 36 skipped, which is master's 5787 plus the ten arms this PR adds.

check-merge-landing-diff.py makes the case cleanly: the landing change is two paths — emrg/server/scheduler.py (+1 −1, the stale Daemon → EmrgServer pointer) and the new tests/test_docstring_cross_references_resolve.py (+292). The 164 paths that read backwards are the base's own later commits, which this head does not contain; none of them is touched by the merge.

The guard itself I reviewed on the previous vote and stand by: tree-wide scope, dotted names decided on the head, attr excluded because it names a member rather than a binding, and the backticked-prose shape the work started from written down as out of reach rather than quietly skipped.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20261023-190416

Third vote, cast on the landing tree because this head is one commit behind master: check-merge-plan-suite.py 2540 planned against master 450c3f0a, built tree 7c38ac00, and the suite is green there — 5797 passed, 36 skipped in 263s. That is master's own count plus the ten arms this PR adds, which is how a suite count confirms the landing change is the change under review.

I re-read the change against its real merge base (d3c8807c) rather than trusting the PR page, and it is two paths: emrg/server/scheduler.py +1 −1, and the new tests/test_docstring_cross_references_resolve.py +292. The single edit is the defect the guard found on its first run — a docstring citing :meth:Daemon._evolution_count`` in a tree whose class is EmrgServer, a pointer that outlived the rename because nothing else asked. CI's merge base was `d3c8807c` while master is `450c3f0a`, so `check-merge-freshness.py` reads STALE and the fix is this measurement, not a refresh: a refresh would move the head and void the two votes already standing on it.

check-merge-landing-diff.py separates the landing change from the noise: of the 166 paths in diff(base, head), 164 read backwards because they carry the base's own later commits, which this head does not contain. The one path flagged as reading backwards inside the landing is emrg/server/scheduler.py, and that is exactly the file the single-line fix touches — the flag is about the base's later hunks on it, not about this edit.

The guard's own scope decisions were reviewed on the first vote and stand unchanged: tree-wide rather than citing-module resolution, dotted names decided on their head, attr outside the scan because it names a member rather than a binding, and the backticked-prose shape that started this work written down as out of reach rather than quietly skipped. Every one of those is a place where a weaker guard would have reported prose as a symbol.

@argszero
argszero merged commit 22e0111 into master Oct 23, 2026
2 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.

A cross-reference role can name a class the tree no longer has

1 participant