refactor(notes): a snippet's and lesson's stored title is its name; the trigger joins it only in the embedded document (milestone 427)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 14s
CI & Build / integration (push) Successful in 52s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / Python tests (push) Successful in 1m35s
CI & Build / Build & push image (push) Successful in 32s
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 14s
CI & Build / integration (push) Successful in 52s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / Python tests (push) Successful in 1m35s
CI & Build / Build & push image (push) Successful in 32s
The title was `subject — trigger` because the stored title WAS the embedded one, and the join is what makes these kinds rank on the situation they apply to (#2485). Every surface that shows a title then showed the trigger too -- menus, lists and search rows ran to kilobytes. - embeddings.document_title(title, note_type, data, body) joins the trigger from `data` (body fallback) at embed time. Idempotent: an un-migrated composed title comes out the same, never doubled. The embed path, the startup backfill and the dedup gate's semantic signal all use it, so the embedded text -- and every vector -- is unchanged. - Writers store the subject: snippet create/update (service, REST, MCP) and lesson_document. Both compose_title helpers are removed. - Readers: dedup takes `data`; the menus strip the embedded title from a passage; list rows project `when_to_use`, which SnippetListView reads. - 0108 rewrites existing rows on an exact `' — ' || <own trigger>` suffix with raw SQL, leaving updated_at alone so the backfill does not re-embed the corpus for identical vectors. Downgrade recomposes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -164,11 +164,11 @@ def _lesson_body(trigger, insight="Read the job log.", sources=None):
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_a_body_write_moves_a_lessons_trigger_with_it():
|
||||
from scribe.services.lessons import TRIGGER_KEY, compose_title
|
||||
from scribe.services.lessons import TRIGGER_KEY
|
||||
|
||||
what = "Read the job log before waiting longer"
|
||||
note = fake_lesson(
|
||||
title=compose_title(what, NEW_TRIGGER),
|
||||
title=what,
|
||||
data={TRIGGER_KEY: "a CI run is slow", "what": what},
|
||||
project_id=None,
|
||||
)
|
||||
@@ -183,13 +183,16 @@ async def test_a_body_write_moves_a_lessons_trigger_with_it():
|
||||
@pytest.mark.asyncio
|
||||
async def test_a_subject_containing_an_em_dash_still_splits():
|
||||
"""Why `untrigger_title` is given the trigger instead of splitting on the
|
||||
separator: a subject may legitimately contain one."""
|
||||
from scribe.services.lessons import TRIGGER_KEY, compose_title
|
||||
separator: a subject may legitimately contain one. The title here is an
|
||||
UN-MIGRATED one, still carrying its trigger (milestone 427), because that
|
||||
is the row the inverse still has to read correctly."""
|
||||
from scribe.services.embeddings import trigger_title
|
||||
from scribe.services.lessons import TRIGGER_KEY
|
||||
|
||||
what = "A wait with no deadline — the shape, not the symptom"
|
||||
trigger = "you are about to await something crossing a process boundary"
|
||||
note = fake_lesson(
|
||||
title=compose_title(what, trigger), data=None, project_id=None,
|
||||
title=trigger_title(what, trigger), data=None, project_id=None,
|
||||
)
|
||||
await _update(note, body=_lesson_body(trigger))
|
||||
assert note.data["what"] == what
|
||||
@@ -202,10 +205,10 @@ async def test_dropping_the_provenance_line_drops_it_from_the_mirror():
|
||||
the failure this recompose exists to prevent, not a courtesy — the
|
||||
opposite call from a snippet's `verification`, which is carried because it
|
||||
was never in the body to delete."""
|
||||
from scribe.services.lessons import SOURCES_KEY, compose_title
|
||||
from scribe.services.lessons import SOURCES_KEY
|
||||
|
||||
note = fake_lesson(
|
||||
title=compose_title("Something learned", "a situation"),
|
||||
title="Something learned",
|
||||
data={SOURCES_KEY: [999]},
|
||||
project_id=None,
|
||||
)
|
||||
@@ -229,7 +232,7 @@ async def test_an_explicit_data_wins_for_a_lesson_too():
|
||||
async def test_a_lesson_title_change_reaches_the_mirror():
|
||||
"""A lesson's subject lives in its title, so a title edit is a trigger for
|
||||
recomposition exactly as it is for a snippet's name."""
|
||||
from scribe.services.lessons import TRIGGER_KEY, compose_title
|
||||
from scribe.services.lessons import TRIGGER_KEY
|
||||
|
||||
trigger = "two absolute siblings overlap"
|
||||
note = fake_lesson(
|
||||
@@ -237,7 +240,7 @@ async def test_a_lesson_title_change_reaches_the_mirror():
|
||||
data={TRIGGER_KEY: trigger, "what": "the old subject"},
|
||||
project_id=None,
|
||||
)
|
||||
await _update(note, title=compose_title("the new subject", trigger))
|
||||
await _update(note, title="the new subject")
|
||||
assert note.data["what"] == "the new subject"
|
||||
assert note.data[TRIGGER_KEY] == trigger
|
||||
|
||||
|
||||
Reference in New Issue
Block a user