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:
@@ -117,7 +117,8 @@ async def test_the_duplicate_gate_runs_before_anything_is_created():
|
||||
@pytest.mark.asyncio
|
||||
async def test_the_gate_compares_the_composed_document_not_the_raw_fields():
|
||||
"""What reaches the gate is the title and body a lesson will actually be
|
||||
stored as. Comparing `what` alone would miss that the trigger is half the
|
||||
stored as, plus the `data` its EMBEDDED title is built from (milestone
|
||||
427). Comparing `what` alone would miss that the trigger is half the
|
||||
document, and would judge two lessons alike that rank nothing alike."""
|
||||
_user_id_ctx.set(7)
|
||||
gate = AsyncMock(return_value=None)
|
||||
@@ -128,8 +129,9 @@ async def test_the_gate_compares_the_composed_document_not_the_raw_fields():
|
||||
await create_lesson(what=SUBJECT, when_to_apply=TRIGGER, insight="Look.")
|
||||
|
||||
title, body = gate.await_args.args[1], gate.await_args.args[2]
|
||||
assert title == f"{SUBJECT} — {TRIGGER}"
|
||||
assert title == SUBJECT
|
||||
assert body.startswith(f"**When to apply:** {TRIGGER}")
|
||||
assert gate.await_args.kwargs["data"]["when_to_apply"] == TRIGGER
|
||||
assert gate.await_args.kwargs["note_type"] == "lesson"
|
||||
|
||||
|
||||
@@ -157,9 +159,11 @@ def test_a_lesson_is_judged_at_the_trigger_dominated_bar():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_an_update_recomposes_both_halves_of_the_document():
|
||||
"""A new trigger has to reach the title AND the head of the body. Patching
|
||||
one would leave a lesson that reads correctly and ranks on the old
|
||||
situation — the failure mode with no symptom."""
|
||||
"""A new trigger has to reach the mirror AND the head of the body — the two
|
||||
places the embedded document reads it from (milestone 427). Patching one
|
||||
would leave a lesson that reads correctly and ranks on the old situation —
|
||||
the failure mode with no symptom. The title stays the subject, even when
|
||||
the stored one was an un-migrated composed title."""
|
||||
_user_id_ctx.set(7)
|
||||
stored = _stub_note(
|
||||
title=f"{SUBJECT} — {TRIGGER}",
|
||||
@@ -172,7 +176,7 @@ async def test_an_update_recomposes_both_halves_of_the_document():
|
||||
await lessons_svc.update_lesson(7, 1, when_to_apply="a guard goes red")
|
||||
|
||||
fields = updated.await_args.kwargs
|
||||
assert fields["title"] == f"{SUBJECT} — a guard goes red"
|
||||
assert fields["title"] == SUBJECT
|
||||
assert fields["body"].startswith("**When to apply:** a guard goes red")
|
||||
assert fields["data"]["when_to_apply"] == "a guard goes red"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user