{"record":{"id":"3c8f2ed7ad61f534","repo":"can1357/oh-my-pi","slug":"unknown-extraction-tier-json-stringify-tier-v","errorCode":null,"errorMessage":"unknown extraction tier ${JSON.stringify(tier)}; valid tiers: ${EXTRACTION_TIERS.join(\", \")}","messagePattern":"unknown extraction tier (.+?); valid tiers: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/mnemopi/src/core/extraction/diagnostics.ts","lineNumber":91,"sourceCode":"\nfunction errorRepr(exc: unknown): string {\n\tif (exc instanceof Error) {\n\t\treturn `${exc.name}: ${exc.message}`;\n\t}\n\treturn String(exc);\n}\n\nexport class ExtractionDiagnostics {\n\tprivate tierStats: Record<ExtractionTier, MutableTierStats> = emptyTierStats();\n\tprivate totalCalls = 0;\n\tprivate totalSuccesses = 0;\n\tprivate totalFailures = 0;\n\tprivate totalEmpty = 0;\n\tprivate createdAt = new Date().toISOString();\n\n\tprivate validateTier(tier: string): asserts tier is ExtractionTier {\n\t\tif (!isTier(tier)) {\n\t\t\tthrow new Error(\n\t\t\t\t`unknown extraction tier ${JSON.stringify(tier)}; valid tiers: ${EXTRACTION_TIERS.join(\", \")}`,\n\t\t\t);\n\t\t}\n\t}\n\n\trecordAttempt(tier: ExtractionTier): void {\n\t\tthis.validateTier(tier);\n\t\tthis.tierStats[tier].attempts += 1;\n\t}\n\trecordSuccess(tier: ExtractionTier, _factCount = 0): void {\n\t\tthis.validateTier(tier);\n\t\tthis.tierStats[tier].successes += 1;\n\t}\n\trecordNoOutput(tier: ExtractionTier): void {\n\t\tthis.validateTier(tier);\n\t\tthis.tierStats[tier].no_output += 1;\n\t}\n\trecordFailure(tier: ExtractionTier, exc?: unknown, reason?: string): void {","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/mnemopi/src/core/extraction/diagnostics.ts#L73-L109","documentation":"ExtractionDiagnostics.validateTier asserts the tier string is one of the known EXTRACTION_TIERS before recording an attempt/success/failure/no-output event. Unknown tier strings throw an Error listing the valid tiers, keeping diagnostics counters type-safe.","triggerScenarios":"Calling recordAttempt/recordSuccess/recordNoOutput/recordFailure with a hand-written tier string that is misspelled, differently cased, or from a newer tier list than the running build supports.","commonSituations":"Custom pipelines logging diagnostics with their own tier names, typos like \"fastt\"/\"Deep\", or persisting old tier labels that no longer exist after an upgrade.","solutions":["Use only tier names from EXTRACTION_TIERS (import the constant and iterate it instead of hardcoding).","Type the tier parameter as ExtractionTier so invalid strings fail at compile time.","Map/upgrade legacy tier labels before calling the diagnostics methods."],"exampleFix":"// before\ndiag.recordAttempt(\"fast\"); // suppose valid is \"fast-path\"\n// after\nimport { EXTRACTION_TIERS } from \"./tiers\";\nif (EXTRACTION_TIERS.includes(tier as ExtractionTier)) diag.recordAttempt(tier);","handlingStrategy":"type-guard","validationCode":"import { EXTRACTION_TIERS } from \"./diagnostics\";\nfunction isTier(t: string): t is ExtractionTier {\n  return (EXTRACTION_TIERS as readonly string[]).includes(t);\n}\nif (!isTier(tier)) tier = normalizeTier(tier);","typeGuard":"function isTier(t: string): t is ExtractionTier {\n  return (EXTRACTION_TIERS as readonly string[]).includes(t);\n}","tryCatchPattern":"try {\n  diag.recordAttempt(tier);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith(\"unknown extraction tier\")) {\n    logger.warn(\"dropping diagnostics for unknown tier\", { tier });\n  } else throw e;\n}","preventionTips":["Type tier variables as ExtractionTier end-to-end so bad strings fail at compile time.","Derive tier labels from the EXTRACTION_TIERS constant, never string literals.","When renaming a tier, add a mapping for persisted historical labels."],"tags":["validation","enum","diagnostics","api-usage"],"backgroundTag":"invalid-enum-value","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}