fix(lessons): build the rule-candidate query with trigger_title (#4631)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 15s
CI & Build / TypeScript typecheck (push) Successful in 1m0s
CI & Build / integration (push) Successful in 1m1s
CI & Build / Python tests (push) Successful in 1m53s
CI & Build / Build & push image (push) Successful in 27s

CI run 707 failed test_the_trigger_separator_is_spelled_in_exactly_one_place:
rule_candidates joined the lesson's claim and trigger with an inline " — ",
a second spelling of embeddings.TRIGGER_SEP (#3207). It now calls
trigger_title — the same join a rule's own document title is built with,
which was the point of the query shape in the first place.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 13:34:08 -04:00
co-authored by Claude Opus 5.5
parent f7d8dc2e55
commit 95be2512ab
+4 -3
View File
@@ -399,7 +399,7 @@ async def rule_candidates(
"""The rules a lesson most resembles, for the writer to judge against. """The rules a lesson most resembles, for the writer to judge against.
Searched with the lesson's claim and its trigger — the same two halves a Searched with the lesson's claim and its trigger — the same two halves a
rule's own document leads with (`{title} — {trigger}`), so like is rule's own document leads with (`trigger_title`), so like is
compared with like; the insight is the story and would dilute the vector. compared with like; the insight is the story and would dilute the vector.
Scoped as any project read is: global rules plus the lesson's project's Scoped as any project read is: global rules plus the lesson's project's
own. The bar is the explicit rule search's, since this is an explicit own. The bar is the explicit rule search's, since this is an explicit
@@ -409,10 +409,11 @@ async def rule_candidates(
caller can say "candidates unavailable" rather than "nothing resembles". caller can say "candidates unavailable" rather than "nothing resembles".
""" """
from scribe.services.embeddings import ( from scribe.services.embeddings import (
DEFAULT_SIMILARITY_THRESHOLD, semantic_search_rules, DEFAULT_SIMILARITY_THRESHOLD, semantic_search_rules, trigger_title,
) )
query = " — ".join(p for p in ((what or "").strip(), (when_to_apply or "").strip()) if p) # The rule document's own title join, so like is compared with like.
query = trigger_title(what, when_to_apply)
report: dict = {} report: dict = {}
found = await semantic_search_rules( found = await semantic_search_rules(
user_id, query, limit=CANDIDATE_LIMIT, user_id, query, limit=CANDIDATE_LIMIT,