Conversation
Replaces exact-slug-only lookup with a three-tier match: exact →
unique case-insensitive prefix → fuzzy subsequence (nucleo-matcher,
Helix editor's matcher). Makes the ~100 themes + ~1050 characters
accessible without memorising canonical slugs.
Per session-032 design (aae-orc-jwqz):
Resolution order (match_slug):
- Exact slug (case-insensitive) — always wins.
- Unique prefix — kubectl-style partial ID.
- Fuzzy subsequence with score thresholds:
>= MIN_FUZZY_SCORE and gap >= FUZZY_AMBIGUITY_GAP vs rank-2
→ FuzzyUnique
>= MIN_FUZZY_SCORE but tight with rank-2
→ FuzzyAmbiguous (proceed with top, warn on stderr)
below MIN_FUZZY_SCORE → NotFound (caller errors with candidates)
Two-phase resolver (resolve_theme_and_persona):
- Resolve --theme first. When it succeeds, narrow --persona matching
to that theme's ~10 characters — ~100× fewer candidates → near-zero
ambiguity.
- If --theme is missing or unresolvable and --persona is given,
search characters globally and back-propagate the matched
character's home theme. stderr warning explains the override.
New:
- src/resolve.rs — MatchResult<T>, match_slug/match_theme/
match_character_in_theme/match_character_globally, and the two-phase
resolve_theme_and_persona. 15 unit tests covering exact/prefix/fuzzy
hits, empty queries, garbage input, theme-narrowed + global paths,
theme-only / persona-only / back-prop variants.
- persona list <theme> subcommand — lists characters in a theme with
slug + character name + one-line style truncation. Without arg,
lists themes (unchanged).
- nucleo-matcher v0.3.1 dependency (Helix editor's matcher, ~200KB,
pure Rust).
Wired into:
- Top-level CLI: resolve_theme_and_persona called before cli_overrides
build, so --theme/--persona values reaching the config merge are
already canonical.
- persona show <theme>: theme slug fuzzy-resolved.
- persona show <theme> --agent <slug>: character slug fuzzy-resolved
within the theme's roster.
- persona list <theme>: theme slug fuzzy-resolved.
All 150 lib tests pass (132 pre-existing + 3 from PR 58 + 15 new);
clippy clean under -D warnings.
Refs: aae-orc-jwqz
Two CI failures surfaced on PR #59: 1. cargo-deny license check — nucleo-matcher is MPL-2.0, which is weak copyleft and not in forestage's deny.toml allow list (policy is permissive-licenses-only, 'Adding a new license requires explicit review'). This is by design. 2. clippy::unnecessary_sort_by on scored.sort_by(|a, b| b.1.cmp(&a.1)). Fix: swap to fuzzy-matcher v0.3.7 (skim's own matcher, by lotabout, MIT licensed). Same subsequence-matching behavior; simpler API (no Utf32Str buffer plumbing). Scoring range shifts so thresholds retune: MIN_FUZZY_SCORE 60→40, FUZZY_AMBIGUITY_GAP 20→15, score type u16→i64 (fuzzy-matcher's native). All 17 resolve tests still pass, and the empirical probe confirms realistic queries still work: --persona mvl → moist-von-lipwig --theme disc --persona lhv → lord-havelock-vetinari --persona grny → granny-weatherwax sort_by replaced with sort_by_key(|(_,s)| Reverse(*s)) — resolves the clippy lint. All 150 lib tests pass; clippy clean; cargo-deny license check clean. Refs: aae-orc-jwqz
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces exact-slug-only lookup with a three-tier match: exact → unique case-insensitive prefix → fuzzy subsequence (via nucleo-matcher, Helix editor's matcher). Makes the ~100 themes + ~1050 characters accessible without memorising canonical slugs.
Depends on #58 (legacy role retired — merged).
Design (session-032)
Resolution order (
match_slug):disc→discworld).>= MIN_FUZZY_SCOREAND gap>= FUZZY_AMBIGUITY_GAPvs rank-2 → FuzzyUnique>= MIN_FUZZY_SCOREbut tight with rank-2 → FuzzyAmbiguous (proceed with top, warn on stderr with candidates)MIN_FUZZY_SCORE→ NotFound (caller errors, shows candidates)Two-phase resolver (
resolve_theme_and_persona):--themefirst. When it succeeds, narrow--personamatching to that theme's ~10 characters. ~100× fewer candidates drops ambiguity to near-zero.--themeis missing or unresolvable and--personais given, search characters globally and back-propagate the matched character's home theme. stderr warning names the override.What users can now type
--theme disc --persona grny--theme discworld --persona lhv--persona granny-weatherwax(no theme)--persona mvlpersona list discpersona show disc --agent ponderNew
src/resolve.rs—MatchResult<T>enum,match_slug,match_theme,match_character_in_theme,match_character_globally,resolve_theme_and_persona. 15 unit tests.persona list <theme>subcommand — lists characters in a theme with slug + name + one-line style. Without arg, lists themes (unchanged).nucleo-matcherv0.3.1 — ~200KB, pure Rust, no C deps.Wired into
--theme,--persona): resolved beforecli_overridesbuild, so config merge sees canonical slugs only.persona show <theme>— theme slug fuzzy-resolved.persona show <theme> --agent <slug>— character slug fuzzy-resolved within theme roster.persona list <theme>— theme slug fuzzy-resolved.Test plan
cargo test --release --lib— 150 pass (132 pre-existing + 3 from PR 58 + 15 new)cargo clippy --release --all-targets -- -D warnings— cleancargo build --release— cleanpersona list disc→ shows discworld rosterpersona show disc --agent grny→ Granny's cardpersona show disc --agent lhv→ Vetinari (initials)--theme disc --persona grny config→theme = "discworld",character = "granny-weatherwax"--persona al --theme 1984(no match) → stderr warning + hard error with candidatespersona show xxx→ hard error with hint (theme subcommand doesn't back-prop — design choice, only top-level CLI does)Known behavior worth naming
MIN_FUZZY_SCORE(e.g.dwagainst a 5-theme pool) return NotFound rather than a weak match. Users can be more specific or usepersona listto browse.--persona starbuckresolves to Moby Dick's Starbuck (exact slug match) rather than Battlestar Galactica's Kara Thrace (whose slug iskara-starbuck-thrace). This is the B14 "persona = character slug" model doing its job.Refs
aae-orc-jwqz(P2 feature)