{"record":{"id":"a71c8c17f3f7682f","repo":"can1357/oh-my-pi","slug":"ambiguous-family-for-model-tied-0-and","errorCode":null,"errorMessage":"ambiguous family for `${model}`: `${tied[0]}` and `${tied[1]}` tie","messagePattern":"ambiguous family for `(.+?)`: `(.+?)` and `(.+?)` tie","errorType":"exception","errorClass":"AmbiguousIdentityError","httpStatus":null,"severity":"critical","filePath":"packages/catalog/src/compat/taxonomy.ts","lineNumber":106,"sourceCode":"\treturn count;\n}\n\nfunction classifyFamily(cls: CompiledClass, bare: string, model: string, lenient: boolean): string | undefined {\n\tlet winner: { rank: readonly [number, number]; id: string } | undefined;\n\tlet tied: readonly [string, string] | undefined;\n\tfor (const family of cls.families) {\n\t\tif (!globMatch(family.glob, bare)) continue;\n\t\tconst rank = [family.priority, nonWildcardBytes(family.glob)] as const;\n\t\tif (winner && winner.rank[0] === rank[0] && winner.rank[1] === rank[1] && winner.id !== family.id) {\n\t\t\ttied = [winner.id, family.id];\n\t\t} else if (!winner || winner.rank[0] < rank[0] || (winner.rank[0] === rank[0] && winner.rank[1] < rank[1])) {\n\t\t\twinner = { rank, id: family.id };\n\t\t\ttied = undefined;\n\t\t}\n\t}\n\tif (tied) {\n\t\tif (lenient) return undefined;\n\t\tthrow new AmbiguousIdentityError(model, tied[0], tied[1], \"family\");\n\t}\n\treturn winner?.id;\n}\n\nfunction extractRevision(cls: CompiledClass, bare: string): string | undefined {\n\tif (cls.skipBare.includes(bare)) return undefined;\n\tfor (const rule of cls.revisionPrefixes) {\n\t\tlet tail: string | undefined;\n\t\tif (rule.anywhere) {\n\t\t\tconst start = bare.indexOf(rule.prefix);\n\t\t\tif (start !== -1) tail = bare.slice(start + rule.prefix.length);\n\t\t} else if (bare.startsWith(rule.prefix)) {\n\t\t\ttail = bare.slice(rule.prefix.length);\n\t\t}\n\t\tif (tail === undefined) continue;\n\t\tconst digit = tail.search(/[0-9]/);\n\t\tif (digit === -1) return undefined;\n\t\tconst revision = parseRevisionPrefix(tail.slice(digit));","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/catalog/src/compat/taxonomy.ts#L88-L124","documentation":"AmbiguousIdentityError from classifyFamily: two family selectors in the taxonomy both match a model name with the same (winning) rank, so family classification cannot pick one. In lenient mode it returns undefined instead of throwing; strict mode surfaces the two tied family ids in the message.","triggerScenarios":"classifyModel/classifyFamily on a bare model string where two family regex/prefix patterns in taxonomy/*.kdl both match at equal priority — e.g. overlapping families like \"gpt\" and \"gpt-5\" both matching with the same rank.","commonSituations":"Adding a new family KDL rule whose pattern overlaps an existing family without distinguishing specificity; upstream model names colliding with broad family wildcards.","solutions":["Tighten one family's selector (anchor/word-boundary the pattern) so only one matches.","Give one family a higher rank/priority so the tie breaks deterministically.","Run `bun run gen:compat` after editing the taxonomy KDL and re-test classifyModel on the colliding id."],"exampleFix":"// before: two families both match \"gpt-5-mini\"\nfamily \"gpt\" { match \"gpt\" }\n// after: anchor so only the specific family matches\nfamily \"gpt-5-mini\" { match \"gpt-5-mini\" }","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"null","tryCatchPattern":"try {\n  const facts = classifyModel(id);\n} catch (err) {\n  if (err instanceof AmbiguousIdentityError && err.kind === \"family\") {\n    // err names the two tied families; fall back to unknown-family behavior\n    return defaultFacts(id);\n  }\n  throw err;\n}","preventionTips":["Anchor/word-boundary family patterns so broad and specific families don't both match.","Give specific families higher rank than wildcards.","Add classifyModel assertions in tests for ids at collision risk."],"tags":["catalog","taxonomy","classification","kdl"],"backgroundTag":"ambiguous-model-family-classification","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}