fix(tests): the round-trip guard needs fake_lesson, not fake_note (#4272)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / integration (push) Successful in 45s
CI & Build / TypeScript typecheck (push) Successful in 52s
CI & Build / Python tests (push) Successful in 1m34s
CI & Build / Build & push image (push) Successful in 21s

Run 7208 failed 5 of 23 in the new file, all with a `**Learned from:** #1`
that no shape asked for.

`lesson_sources` falls back to `arose_from_id` when neither the mirror nor
the body names a source. `fake_note` leaves that field to MagicMock, which
auto-creates it truthy and coerces to 1 — so every no-sources shape
recomposed with a provenance line and the round trip failed for a reason
with nothing to do with the trigger. `fake_lesson` pins `arose_from_id` to
None and its docstring says why; it is also the truthful stand-in, since
these are lessons.

Worth recording separately: the local harness that cleared this change used
a plain stub class, so it was kinder than the real fixture and could not
reproduce the truthiness. The stub has been given the same None. A
stand-in that is more forgiving than the one the suite uses will verify a
change that CI then rejects — note #2109's point, arriving from the other
direction.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
This commit is contained in:
2026-09-21 16:39:31 -04:00
co-authored by Claude Opus 5
parent 9883b010b3
commit b47dc97ca8
+15 -7
View File
@@ -48,7 +48,7 @@ from __future__ import annotations
import pytest import pytest
from scribe.services import lessons as lessons_svc from scribe.services import lessons as lessons_svc
from tests.helpers import fake_note from tests.helpers import fake_lesson
WHAT = "A column written once at create time is a snapshot, not a field" WHAT = "A column written once at create time is a snapshot, not a field"
@@ -92,10 +92,18 @@ IDS = [s[0] for s in SHAPES]
def _stored(trigger: str, insight: str, sources: list[int]): def _stored(trigger: str, insight: str, sources: list[int]):
"""A lesson exactly as `create_lesson` writes it — title, body and mirror """A lesson exactly as `create_lesson` writes it — title, body and mirror
composed together, which is the only way a real row is ever written.""" composed together, which is the only way a real row is ever written.
`fake_lesson` rather than `fake_note`, and the difference is load-bearing
here: `lesson_sources` falls back to `arose_from_id`, which on a bare
MagicMock auto-creates truthy and coerces to `1`. A no-sources shape then
recomposes with `**Learned from:** #1` and the round trip fails for a
reason that has nothing to do with the trigger. `fake_lesson` pins that
field to None — note #2109's point, which is why the fixture exists.
"""
title, body = lessons_svc.lesson_document(WHAT, trigger, insight, sources) title, body = lessons_svc.lesson_document(WHAT, trigger, insight, sources)
data = lessons_svc.compose_data(WHAT, trigger, sources) data = lessons_svc.compose_data(WHAT, trigger, sources)
return fake_note(title=title, body=body, data=data) return fake_lesson(title=title, body=body, data=data)
def _edit(note): def _edit(note):
@@ -149,7 +157,7 @@ def test_ten_edits_do_not_grow_the_record(_name, trigger, insight, sources):
first = note.body first = note.body
for _ in range(10): for _ in range(10):
title, body = _edit(note) title, body = _edit(note)
note = fake_note(title=title, body=body, data=note.data) note = fake_lesson(title=title, body=body, data=note.data)
assert note.body == first, ( assert note.body == first, (
f"body grew by {len(note.body) - len(first)} characters over ten no-op edits" f"body grew by {len(note.body) - len(first)} characters over ten no-op edits"
) )
@@ -180,7 +188,7 @@ def test_the_insight_is_derived_from_the_row_not_from_the_body_alone():
note = _stored(MANY_PARAGRAPHS, INSIGHT, []) note = _stored(MANY_PARAGRAPHS, INSIGHT, [])
assert lessons_svc.lesson_insight(note) == INSIGHT.strip() assert lessons_svc.lesson_insight(note) == INSIGHT.strip()
# The same body with the mirror removed cannot reach the same answer. # The same body with the mirror removed cannot reach the same answer.
bare = fake_note(title=note.title, body=note.body, data=None) bare = fake_lesson(title=note.title, body=note.body, data=None)
assert lessons_svc.lesson_insight(bare) != INSIGHT.strip() assert lessons_svc.lesson_insight(bare) != INSIGHT.strip()
@@ -190,7 +198,7 @@ def test_without_a_mirror_a_one_paragraph_trigger_still_strips():
correctly for the common shape — degrading to the old behaviour rather correctly for the common shape — degrading to the old behaviour rather
than to nothing.""" than to nothing."""
_, body = lessons_svc.lesson_document(WHAT, ONE_LINE, INSIGHT, [4199]) _, body = lessons_svc.lesson_document(WHAT, ONE_LINE, INSIGHT, [4199])
bare = fake_note(title="t", body=body, data=None) bare = fake_lesson(title="t", body=body, data=None)
assert lessons_svc.lesson_insight(bare) == INSIGHT.strip() assert lessons_svc.lesson_insight(bare) == INSIGHT.strip()
@@ -203,7 +211,7 @@ def test_a_stale_mirror_falls_back_rather_than_cutting_the_wrong_thing():
the insight, so the removal happens only on an exact match and the the insight, so the removal happens only on an exact match and the
line-wise fallback takes over otherwise. Nothing authored is lost.""" line-wise fallback takes over otherwise. Nothing authored is lost."""
_, body = lessons_svc.lesson_document(WHAT, ONE_LINE, INSIGHT, []) _, body = lessons_svc.lesson_document(WHAT, ONE_LINE, INSIGHT, [])
stale = fake_note( stale = fake_lesson(
title="t", body=body, title="t", body=body,
data={"what": WHAT, lessons_svc.TRIGGER_KEY: "a trigger that is not in this body"}, data={"what": WHAT, lessons_svc.TRIGGER_KEY: "a trigger that is not in this body"},
) )