From 35f5b3b6d335e7046aec31cca968efed34f510aa Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 25 Aug 2026 19:56:56 +0000 Subject: [PATCH] fix(deep-learning-book): narrow plural matching to -s, ending a false-refusal collision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Eighth review on PR #994 found that _matches()'s (?:s|es)? suffix reintroduced a smaller version of the substring bug it was written to fix: "rag" + "es" matches the standalone word "rages", so --goal "why overfitting still rages in large models" exited 3, refused as out-of-scope retrieval-augmented-generation work. Reproduced before fixing, then checked whether the -es branch earns its keep at all. It does not: every keyword in the table ending in s, x, z, ch or sh is already plural or non-count (basics, features, foundations, prerequisites, statistics, speech, mlops, fairness, mathematics, time series), so no token needs -es appended. Narrowed the auto-plural to plain -s and documented that irregular forms belong in SURFACE_FORMS, spelled out, the way fine-tuning, prompting and agentic already are. Verified: "rages" no longer matches while standalone "rag" still does; transformers, embeddings, autoencoders and agentic still match; the goal above is now correctly unroutable (exit 4) rather than confidently misrouted. RLHF, LoRA fine-tuning, RAG pipelines and prompt/agent goals still exit 3; sequence, vision, generative and practitioner routing unchanged. That makes two rounds of false out-of-scope refusals from the same root cause — approximate string matching standing in for a word list. The refusal path is the part of this tool users are least able to second-guess, so it is the wrong place to approximate. Gates green: 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 Claude-Session: https://claude.ai/code/session_01BswsZp5zrJWFAGU6KWNA1s --- .../deep-learning-book/scripts/reading_path_planner.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/engineering/deep-learning-book/skills/deep-learning-book/scripts/reading_path_planner.py b/engineering/deep-learning-book/skills/deep-learning-book/scripts/reading_path_planner.py index c3e7f651..436c7afb 100644 --- a/engineering/deep-learning-book/skills/deep-learning-book/scripts/reading_path_planner.py +++ b/engineering/deep-learning-book/skills/deep-learning-book/scripts/reading_path_planner.py @@ -204,7 +204,12 @@ def _matches(token: str, text: str) -> bool: inside "context" — each one producing a confident false refusal or a wrong lane. """ for form in SURFACE_FORMS.get(token, (token,)): - if re.search(rf"\b{re.escape(form)}(?:s|es)?\b", text): + # Plain -s only. An -es branch collided with unrelated words: "rag" + "es" + # matches the standalone word "rages", so a goal about overfitting was + # refused as out-of-scope RAG work. No token here needs an -es plural — + # every one ending in s/x/z/ch/sh is already plural or non-count — so any + # irregular form belongs in SURFACE_FORMS, spelled out. + if re.search(rf"\b{re.escape(form)}s?\b", text): return True return False