fix: date prose by its citations, not its wording

A note reworded around unchanged citations took the rewording commit as its writing revision. That commit's pin is current, so citations a bump had left behind stopped being reported. A sentence end now separates a project word from the citation before it, like a comma.
This commit is contained in:
Abdessamad Derraz committed 2026-10-19 05:31:57 +02:00
1 parent f19dcba545
commit 44ac56b4d6
2 files changed
+48 -3

No files matched your search

+26 -3
View File
@@ -383,8 +383,9 @@ def _walk_document(
# What separates one citation from the next in prose. lynx-emu writes
# "...:112; mednafen src/lynx/system.cpp:86-93": without the semicolon the
# project word read as prose and the citation was charged to the fork.
_PROSE_LIST_DELIMITERS = ",;:("
# project word read as prose and the citation was charged to the fork. A
# sentence end separates them the same way.
_PROSE_LIST_DELIMITERS = ",;:(."
def _prose_external(
@@ -2845,6 +2846,26 @@ def _pin_of(document: dict, field: str, mode: str = "") -> str | None:
return value if isinstance(value, str) and value else None
_CITATION_RUN_RE = re.compile(
PROSE_CITE_RE.pattern + r"(?:, *\d+(?:-\d+)?)*"
)
def _scalar_citations(text: str | None) -> tuple[str, ...] | None:
"""The citations a scalar carries, in order, without the prose around them.
A note reworded around unchanged citations was still written under the
pin those citations describe: comparing whole texts moved the writing
revision to the rewording commit, whose pin is current, and the stale
citations were never offered for realignment again.
"""
if text is None:
return None
return tuple(
_citation_key(m.group(0)) for m in _CITATION_RUN_RE.finditer(text)
)
def _writing_pins(
revisions: list[tuple[str, dict]], intro_sha: str, field: str, mode: str = ""
) -> list[str]:
@@ -3098,7 +3119,9 @@ def realign_prose(
for field in fields:
if not alive[field]:
continue
if values.get(field) == current_values.get(field):
if _scalar_citations(values.get(field)) == _scalar_citations(
current_values.get(field)
):
intro[field] = sha
else:
alive[field] = False
+22
View File
@@ -3141,6 +3141,7 @@ class TestCollectCitations(unittest.TestCase):
for line in (
"see Lynx.emu/src/lynx/system.cpp:112; mednafen src/lynx/system.cpp:86-93",
"see Lynx.emu/src/lynx/system.cpp:112, mednafen src/lynx/system.cpp:86-93",
"see Lynx.emu/src/lynx/system.cpp:112. mednafen src/lynx/system.cpp:86-93",
):
with self.subTest(line=line):
start = line.index("src/lynx/system.cpp:86")
@@ -3718,6 +3719,27 @@ class TestRealignProse(unittest.TestCase):
)
self.assertEqual(self.path.read_text(), before)
def test_rewording_around_citations_keeps_the_writing_pin(self):
"""Punctuation edited in a note after a bump is not a new writing.
Keyed on the whole text, the rewording commit became the writing
revision, its pin was current, and the bump that had left the
citations behind was no longer reported.
"""
self._repo_with_advanced_pin()
self._commit(PROSE_SAMPLE, "advance the pin")
self._commit(
PROSE_SAMPLE.replace("on boot.", "at boot."), "reword the note"
)
self.files[("oldpin", "a.c")] = ["x"] * 9 + ["subject"]
self.files[("pin", "a.c")] = ["x"] * 13 + ["subject"]
self.files[("oldpin", "b.c")] = list("pqrstuvwx")
self.files[("pin", "b.c")] = list("pqrstuvwx")
messages = profile_sync.realign_prose(self.path, self.tmp.name, dry_run=True)
self.assertTrue(
any("pin moved under this text" in m for m in messages), messages
)
def test_a_citation_in_an_unmoved_upstream_needs_no_reading(self):
"""nethersx2 cites AetherSX2 files that only its upstream carries,
at an upstream pin that never moved. The port's pin did move under