Skip to content

fix(find): resolve hyphenated/suffixed GPU spec strings (Modal convention) - #153

Merged
scttfrdmn merged 2 commits into
mainfrom
fix/130-hyphenated-gpu-tokens
Aug 19, 2026
Merged

fix(find): resolve hyphenated/suffixed GPU spec strings (Modal convention)#153
scttfrdmn merged 2 commits into
mainfrom
fix/130-hyphenated-gpu-tokens

Conversation

@scttfrdmn

Copy link
Copy Markdown
Contributor

Summary

Modal's documented GPU spec-string convention hyphenates multi-word card names and appends a trailing !/+ suffix — gpu="RTX-PRO-6000", gpu="A100-80GB", gpu="H100!", gpu="B200+". pkg/find's tokenizer only splits on whitespace, so each of these arrived as one token and matched no vocabulary entry. Confirmed both by the original report and its follow-up comment (the bug is general — not narrow to RTX-PRO — since whitespace-only tokenization is the actual root cause).

Two independent bugs, both fixed:

  1. pkg/find tokenizer: classifyTokens now falls back to normalizeHyphenatedToken for a word that failed every other single-word classification. It splits on hyphens and strips a trailing !/+, then re-runs classifyTokens on the resulting parts as if they'd been space-separated all along — so "rtx-pro-6000" resolves via the same matchPhrase alias lookup as "rtx pro 6000", and "a100-80gb" resolves as two tokens (GPU + memory) like "a100 80gb" already does. Guarded against infinite recursion (only reports "try splitting" when the word actually contains a hyphen or the suffix).

  2. CLI routing (cmd/find.go's looksLikePattern): even with (1), real truffle find invocations still failed, because looksLikePattern decides whether to route to the pattern matcher or the natural-language parser before ParseQuery ever runs. Two bugs there: + is one of looksLikeRegex's own indicator characters, checked before the vocabulary check, so "B200+" never reached vocabulary recognition at all; and the vocabulary check compared the raw (non-lowercased) query against lowercase-keyed metadata tables, which was masked for most single-word terms by an accidental fallback but not for a hyphenated query like "A100-80GB". Replaced the old isKnownVocabularyTerm with a new exported find.IsRecognizedTerm (lowercases, then classifies via the same tokenizer, including the new hyphen/suffix fallback) and moved the vocabulary check to run first, before any regex-indicator check. This also fixed a latent case-sensitivity bug: uppercase vocabulary like "AVX2" previously only avoided misrouting by accident.

Verification against live AWS

Ran truffle find end-to-end (AWS_PROFILE=spore-host-dev) for every string named in the issue and its follow-up comment — all now return the expected instance types instead of "No matching instance types found":

truffle find "A100-80GB"    → p4d.24xlarge, p4de.24xlarge
truffle find "RTX-PRO-6000" → g7e.*
truffle find "H100!"        → p5.48xlarge
truffle find "B200+"        → p6-b200.48xlarge, p6e-gb200.36xlarge
truffle find "a100-80gb"    → p4d.24xlarge, p4de.24xlarge (lowercase)
truffle find "rtx-pro-4500" → g7.*

Test plan

  • New pkg/find/hyphenated_test.go: TestResolveCard_HyphenatedSpecStrings (hyphenated form resolves to the same GPU/instance types as the equivalent space-separated form, for every case in the issue), TestResolveCard_HyphenatedFormResolves (full ResolveCard entry point), TestNormalizeHyphenatedToken (splitting helper, including the no-hyphen/no-suffix "don't split" guard), TestClassifyTokens_HyphenatedNoInfiniteRecursion (an unrecognized hyphenated word terminates as 3 TokenUnknown parts, doesn't loop), TestIsRecognizedTerm (the new exported helper, including the uppercase case that previously only worked by accident).
  • New cmd/helpers_test.go: TestLooksLikePattern_HyphenatedGPUSpecStrings — asserts every case above routes to the NL parser, not the pattern matcher, and that a real hyphenated instance family (m7i-flex) still correctly routes as a pattern (the fix doesn't swallow every hyphen).
  • Confirmed regression: stashing cmd/find.go + pkg/find/parser.go makes go vet fail to compile the new test file (undefined: normalizeHyphenatedToken) — the tests cannot pass without the fix.
  • go build ./..., go vet ./..., go test ./... all green
  • golangci-lint run ./... — only pre-existing findings in untouched files (app.go, gendocs.go, printer.go, root.go), none in pkg/find or the touched cmd/find.go/cmd/helpers_test.go
  • make check-docs clean (regenerated docs-gen/find.md for the updated --help text documenting hyphenated spec-string support)
  • CHANGELOG.md updated under ## [Unreleased]

Fixes #130

@codecov

codecov Bot commented Aug 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.65217% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
pkg/find/parser.go 95.00% 0 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

…tion)

Modal's documented GPU spec-string convention hyphenates multi-word card
names and appends a trailing "!"/"+" suffix — gpu="RTX-PRO-6000",
gpu="A100-80GB", gpu="H100!", gpu="B200+". pkg/find's tokenizer only
splits on whitespace, so each of these arrived as a single token and
matched no vocabulary entry: "rtx-pro-6000" never reached the alias
lookup that already resolves the space-separated "rtx pro 6000". This
wasn't narrow to RTX-PRO; any hyphenated or !/+-suffixed term fails
identically since whitespace-only tokenization is the root cause,
confirmed by the issue's own follow-up with A100-80GB/H100!/B200+.

Fix: classifyTokens now falls back to normalizeHyphenatedToken for a
word that failed every other single-word classification. It splits on
hyphens and strips a trailing !/+, then re-runs classifyTokens on the
resulting parts as if they'd been space-separated all along — so
"rtx-pro-6000" resolves via the same matchPhrase alias lookup as
"rtx pro 6000", and "a100-80gb" resolves as two tokens (GPU + memory)
like "a100 80gb" already does. Guarded against infinite recursion: the
helper only reports "try splitting" when the word actually contains a
hyphen or the suffix, so a plain unrecognized word doesn't loop back
into itself.

A second, independent bug in the CLI layer (cmd/find.go's
looksLikePattern) meant the parser fix alone wasn't enough for real
`truffle find` invocations:

1. "+" is one of looksLikeRegex's own indicator characters, checked
   BEFORE the vocabulary check — so "B200+"/"b200+" matched the
   regex-pattern branch and never reached vocabulary recognition at all.
2. The vocabulary check (the old isKnownVocabularyTerm) compared the
   raw query against lowercase-keyed metadata tables with no
   lowercasing — this was masked for most single-word terms by an
   accidental fallback (the digit-suffix regex also happened not to
   match), but not for a hyphenated query like "A100-80GB", which failed
   every branch.

Replaced isKnownVocabularyTerm with a new exported find.IsRecognizedTerm
(lowercases, then classifies via the same tokenizer pkg/find itself
uses — including the hyphen/suffix fallback above), and moved the
vocabulary check to run FIRST in looksLikePattern, before any
regex-indicator check. Also fixed a latent case-sensitivity bug this
uncovered: uppercase vocabulary like "AVX2" previously only avoided
misrouting by accident.

Verified end-to-end via `truffle find` against live AWS data for every
string named in the issue and its follow-up comment.

Fixes #130
@scttfrdmn
scttfrdmn force-pushed the fix/130-hyphenated-gpu-tokens branch from 0ec6e6d to 4cd3b6c Compare August 19, 2026 04:59
@scttfrdmn
scttfrdmn merged commit 76f920a into main Aug 19, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RTX-PRO-6000 / RTX-PRO-4500 (hyphenated spec-string form) don't resolve

1 participant