{"record":{"id":"5b1e6ed584f9e43c","repo":"affaan-m/ECC","slug":"unknown-evolution-log-type-logtype","errorCode":null,"errorMessage":"Unknown evolution log type: ${logType}","messagePattern":"Unknown evolution log type: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/lib/skill-evolution/versioning.js","lineNumber":52,"sourceCode":"  const skillFilePath = getSkillFilePath(skillPath);\n  if (!fs.existsSync(skillFilePath)) {\n    throw new Error(`Skill file not found: ${skillFilePath}`);\n  }\n\n  return skillFilePath;\n}\n\nfunction getVersionsDir(skillPath) {\n  return path.join(normalizeSkillDir(skillPath), VERSION_DIRECTORY_NAME);\n}\n\nfunction getEvolutionDir(skillPath) {\n  return path.join(normalizeSkillDir(skillPath), EVOLUTION_DIRECTORY_NAME);\n}\n\nfunction getEvolutionLogPath(skillPath, logType) {\n  if (!EVOLUTION_LOG_TYPES.includes(logType)) {\n    throw new Error(`Unknown evolution log type: ${logType}`);\n  }\n\n  return path.join(getEvolutionDir(skillPath), `${logType}.jsonl`);\n}\n\nfunction ensureSkillVersioning(skillPath) {\n  ensureSkillExists(skillPath);\n\n  const versionsDir = getVersionsDir(skillPath);\n  const evolutionDir = getEvolutionDir(skillPath);\n\n  ensureDir(versionsDir);\n  ensureDir(evolutionDir);\n\n  for (const logType of EVOLUTION_LOG_TYPES) {\n    const logPath = getEvolutionLogPath(skillPath, logType);\n    if (!fs.existsSync(logPath)) {\n      fs.writeFileSync(logPath, '', 'utf8');","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/skill-evolution/versioning.js#L34-L70","documentation":"Thrown by getEvolutionLogPath() when the requested logType is not in the EVOLUTION_LOG_TYPES allowlist (['observations','inspections','amendments']). The library writes one JSONL file per log type inside the skill's .evolution directory, so an unknown type would create a stray file and break tooling that reads those logs. The check is a hard gate before any path is computed.","triggerScenarios":"Calling appendEvolutionRecord(skillPath, 'audit', record) or getEvolutionLog(skillPath, 'feedback'); passing a plural/singular variant like 'observation' instead of 'observations'; passing a custom log type the caller assumed was registered; passing undefined/null/logType that fails Array.prototype.includes.","commonSituations":"Caller hard-codes a log type string and the API later adds a new bucket the caller does not know about; copy-paste from documentation that uses a different spelling; downstream tool tries to write 'reviews' or 'tests' logs that are not part of the schema.","solutions":["Use one of the three allowed values exactly: 'observations', 'inspections', or 'amendments'.","Import EVOLUTION_LOG_TYPES from the module and validate or iterate against it instead of hard-coding the string.","If you genuinely need a new log type, add it to EVOLUTION_LOG_TYPES in scripts/lib/skill-evolution/versioning.js and update consumers — do not catch and ignore the error.","Check for trailing whitespace or wrong casing in the value you pass; the comparison is case-sensitive."],"exampleFix":"// before\nappendEvolutionRecord(skillPath, 'observation', record);  // singular -> Unknown evolution log type\n\n// after\nconst { EVOLUTION_LOG_TYPES, appendEvolutionRecord } = require('scripts/lib/skill-evolution/versioning');\nconst logType = EVOLUTION_LOG_TYPES.includes(inputType) ? inputType : 'observations';\nappendEvolutionRecord(skillPath, logType, record);","handlingStrategy":"validation","validationCode":"const { EVOLUTION_LOG_TYPES } = require('scripts/lib/skill-evolution/versioning');\n\nfunction safeLogType(value, fallback = 'observations') {\n  return EVOLUTION_LOG_TYPES.includes(value) ? value : fallback;\n}\n\nappendEvolutionRecord(skillPath, safeLogType(inputType), record);","typeGuard":"const { EVOLUTION_LOG_TYPES } = require('scripts/lib/skill-evolution/versioning');\n\nfunction isEvolutionLogType(value) {\n  return typeof value === 'string' && EVOLUTION_LOG_TYPES.includes(value);\n}","tryCatchPattern":"try {\n  appendEvolutionRecord(skillPath, logType, record);\n} catch (error) {\n  if (/Unknown evolution log type/.test(error.message)) {\n    // fall back to a known log type or surface a config error to the caller\n    appendEvolutionRecord(skillPath, 'observations', record);\n    return;\n  }\n  throw error;\n}","preventionTips":["Never hard-code log type strings — import EVOLUTION_LOG_TYPES and index into it.","Treat the allowlist as part of the public API: a new log type requires a library bump.","Validate at the edge (CLI parser, config loader) so a bad value is rejected with context.","Document the three allowed values wherever you accept a logType parameter."],"tags":["skill-evolution","validation","allowlist","configuration"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}