π€ Auto-generated by Claude Fable 5 (claude-fable-5) via Claude Code β NOT human-reviewed. Verify before acting.
self.voc_match(utterance, voc) answers "did any member of this .voc appear" β a boolean. During the skills QA campaign two patterns kept hitting its ceiling. The first is closed-list value recovery: a skill that matches an intent through an inline <name> vocabulary reference (INTENT-1 Β§3.7) gets tight routing but no captured value, since <name> never introduces a slot. The handler then has to re-find which member appeared, and today that means hand-rolled scanning in each skill.
The second is multiple occurrences of the same vocabulary in one utterance. Pokepedia's "who would win, bulbasaur or mewtwo" needs both names in order. voc_match collapses them into one yes. This is a known limitation, same family as adjacent capture groups needing a separating word β but unlike the grammar case, skill code could resolve it cheaply if the base class exposed the positions.
The proposal: add one method alongside voc_match, something like voc_match_all(utterance, voc_name, lang=None) -> list returning every matched vocabulary entry with its span in the utterance, ordered by position (longest-match-wins on overlaps). voc_match stays as-is; it could even become a thin wrapper. That single affordance covers ordered multi-value recovery ("X versus Y"), closed-list value extraction after <name> routing, and would also give fallback-style skills a principled longest-match rule instead of the fixed-order substring checks we found misfiring in fallback-unknown.
Not proposing an implementation here β the design questions are what's worth discussing: exact return shape (entries vs spans vs both), normalization/casefolding rules so matching agrees with what the intent engines do, and whether overlap resolution belongs in the method or the caller.
self.voc_match(utterance, voc)answers "did any member of this .voc appear" β a boolean. During the skills QA campaign two patterns kept hitting its ceiling. The first is closed-list value recovery: a skill that matches an intent through an inline<name>vocabulary reference (INTENT-1 Β§3.7) gets tight routing but no captured value, since<name>never introduces a slot. The handler then has to re-find which member appeared, and today that means hand-rolled scanning in each skill.The second is multiple occurrences of the same vocabulary in one utterance. Pokepedia's "who would win, bulbasaur or mewtwo" needs both names in order.
voc_matchcollapses them into one yes. This is a known limitation, same family as adjacent capture groups needing a separating word β but unlike the grammar case, skill code could resolve it cheaply if the base class exposed the positions.The proposal: add one method alongside
voc_match, something likevoc_match_all(utterance, voc_name, lang=None) -> listreturning every matched vocabulary entry with its span in the utterance, ordered by position (longest-match-wins on overlaps).voc_matchstays as-is; it could even become a thin wrapper. That single affordance covers ordered multi-value recovery ("X versus Y"), closed-list value extraction after<name>routing, and would also give fallback-style skills a principled longest-match rule instead of the fixed-order substring checks we found misfiring in fallback-unknown.Not proposing an implementation here β the design questions are what's worth discussing: exact return shape (entries vs spans vs both), normalization/casefolding rules so matching agrees with what the intent engines do, and whether overlap resolution belongs in the method or the caller.