fix(deep-learning-book): narrow plural matching to -s, ending a false-refusal collision

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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BswsZp5zrJWFAGU6KWNA1s
This commit is contained in:
Claude 2026-08-25 19:56:56 +00:00
parent 5f5d84f469
commit 35f5b3b6d3
No known key found for this signature in database

View file

@ -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