Summary
When a module identifier resolves to nothing, suggest the single nearest known
module name instead of a bare "not found". This supersedes the original idea in
this issue (auto-trying plural/singular variants of the search terms) with a more
general, lower-risk approach: a non-binding "did you mean?" hint computed by edit
distance over the candidate names the surface already gathers.
The original report: start task modules/role/create fails because the real name
is module/role/create (singular). A nearest-name suggestion fixes that case and
every other near-miss — typos, a wrong path segment, a transposition — with one
mechanism, without making resolution itself fuzzy.
Why not auto-plural
+s/-s only handles regular plurals (it misses category/categories), and
auto-resolving a guessed variant could silently install or act on the wrong
module. Edit-distance suggestion keeps resolution strictly literal and
deterministic while covering far more slips, and a wrong suggestion costs nothing
because it never acts on its own.
Behaviour
- On a confirmed not-found (registry reachable), compute the edit distance from
the query to the in-scope candidate names and print the single closest if it is
within a threshold.
- Suggestion only. Nothing auto-resolves or auto-installs. Exit codes and
not-found semantics are unchanged; the literal resolution contract is untouched.
- Top-1, with a length-relative threshold and a deterministic (lexical) tie-break.
- Do not suggest when the registry was unreachable (the transient/retry path): the
candidate pool is incomplete and cannot be trusted.
- Skip suggestions for very short queries where edit distance is not meaningful.
Scope
This assumes the candidate-gathering unification (project
05-unify-candidate-gathering.md) is in place, so the suggester attaches once per
surface and covers every module-selecting surface: the resolution surfaces
(task, --role, --context, --agent, get/describe), uninstall /
config remove, config get, install, and update. search benefits too
wherever it returns zero results.
Implementation notes
- Edit distance via a copied-in copy of
agnivade/levenshtein. Case-fold both
inputs first (the library is case-sensitive). It is plain Levenshtein, so an
adjacent transposition costs 2 — size the threshold accordingly.
- License handling for the copied file is a maintainer action item, deliberately
deferred (the file is copied without its license header for now).
- The path separator
/ is an ordinary character to the metric, so a
segment-boundary slip like modules/role/create vs module/role/create is
distance 1 with no need to split on /.
Acceptance
start task modules/role/create prints a suggestion for module/role/create
and still exits as not-found.
- Garbage input with nothing within the threshold prints no suggestion.
- Successful resolution and all exit codes are unchanged.
Summary
When a module identifier resolves to nothing, suggest the single nearest known
module name instead of a bare "not found". This supersedes the original idea in
this issue (auto-trying plural/singular variants of the search terms) with a more
general, lower-risk approach: a non-binding "did you mean?" hint computed by edit
distance over the candidate names the surface already gathers.
The original report:
start task modules/role/createfails because the real nameis
module/role/create(singular). A nearest-name suggestion fixes that case andevery other near-miss — typos, a wrong path segment, a transposition — with one
mechanism, without making resolution itself fuzzy.
Why not auto-plural
+s/-sonly handles regular plurals (it missescategory/categories), andauto-resolving a guessed variant could silently install or act on the wrong
module. Edit-distance suggestion keeps resolution strictly literal and
deterministic while covering far more slips, and a wrong suggestion costs nothing
because it never acts on its own.
Behaviour
the query to the in-scope candidate names and print the single closest if it is
within a threshold.
not-found semantics are unchanged; the literal resolution contract is untouched.
candidate pool is incomplete and cannot be trusted.
Scope
This assumes the candidate-gathering unification (project
05-unify-candidate-gathering.md) is in place, so the suggester attaches once persurface and covers every module-selecting surface: the resolution surfaces
(
task,--role,--context,--agent,get/describe),uninstall/config remove,config get,install, andupdate.searchbenefits toowherever it returns zero results.
Implementation notes
agnivade/levenshtein. Case-fold bothinputs first (the library is case-sensitive). It is plain Levenshtein, so an
adjacent transposition costs 2 — size the threshold accordingly.
deferred (the file is copied without its license header for now).
/is an ordinary character to the metric, so asegment-boundary slip like
modules/role/createvsmodule/role/createisdistance 1 with no need to split on
/.Acceptance
start task modules/role/createprints a suggestion formodule/role/createand still exits as not-found.