mirror of
https://github.com/alirezarezvani/claude-skills.git
synced 2026-08-28 04:24:58 +00:00
fix(deep-learning-book): break lane-scoring ties by keyword specificity
Second independent review on PR #994 observed that reading_path_planner.py's score_lanes() broke equal-hit ties alphabetically by lane key, so SKILL.md's own documented example "train a transformer" resolved to the practitioner lane rather than sequence. Reproduced: the goal hits practitioner on "train" and sequence on "transformer", one keyword each, and alphabetical ordering picked practitioner. Fixed the cause rather than the example. Ties now break on keyword specificity — the lane whose longest matched keyword is longest wins — because an equal hit count between a generic term and a discriminating one should not be settled by luck. Lane key remains the final tie-break so ordering stays deterministic. Regression battery over eight goals: "train a transformer" now routes to sequence; vision, generative, foundations, practitioner, complete, representation and sequence goals all route exactly as before. Refusal paths unchanged (out-of-scope exit 3, unroutable exit 4, sample exit 0). Gates green after the change: compileall, check_paths, check_frontmatter, check_dual_publish, check_model_freshness, smoke_scripts (696 passed), derive_counters --check, check_skill_names, check_plugin_json, book_skill_validator, and --help + --sample --output json on all four tools. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BswsZp5zrJWFAGU6KWNA1s
This commit is contained in:
parent
c75500f804
commit
1366714fdc
1 changed files with 14 additions and 6 deletions
|
|
@ -225,15 +225,23 @@ def order_path(chapters: list[int]) -> list[int]:
|
|||
|
||||
|
||||
def score_lanes(goal: str) -> list[tuple[str, int]]:
|
||||
"""Score every lane by keyword hits in the goal text, best first."""
|
||||
"""Score every lane by keyword hits in the goal text, best first.
|
||||
|
||||
Ties are broken by keyword specificity — the lane whose longest matched
|
||||
keyword is longest wins — because an equal hit count between a generic term
|
||||
and a discriminating one should not be settled by luck. "train a transformer"
|
||||
hits `practitioner` on "train" and `sequence` on "transformer", one each; the
|
||||
longer, more specific match is the one that names the subject. Lane key is the
|
||||
final tie-break so the ordering stays deterministic.
|
||||
"""
|
||||
text = goal.lower()
|
||||
scored = []
|
||||
for key, lane in LANES.items():
|
||||
hits = sum(1 for kw in lane["keywords"] if kw in text)
|
||||
if hits:
|
||||
scored.append((key, hits))
|
||||
scored.sort(key=lambda pair: (-pair[1], pair[0]))
|
||||
return scored
|
||||
matched = [kw for kw in lane["keywords"] if kw in text]
|
||||
if matched:
|
||||
scored.append((key, len(matched), max(len(kw) for kw in matched)))
|
||||
scored.sort(key=lambda row: (-row[1], -row[2], row[0]))
|
||||
return [(key, hits) for key, hits, _ in scored]
|
||||
|
||||
|
||||
def out_of_scope_hits(goal: str) -> list[str]:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue