{"record":{"id":"cf000e6ac6bd93bf","repo":"pbakaus/impeccable","slug":"concept-seed-every-challenger-tier-needs-at-least","errorCode":null,"errorMessage":"concept-seed: every challenger tier needs at least one approved concept","messagePattern":"concept-seed: every challenger tier needs at least one approved concept","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/skills/impeccable/scripts/lib/roll-selection.mjs","lineNumber":170,"sourceCode":"\nexport function* selectApprovedChallengers({ scope, key, reroll = 0, minRating = null, mode = null, concepts }) {\n  const approved = concepts.filter(concept => concept.status === 'approved');\n  // Direction chooses a durable identity, so it draws worlds; surface designs\n  // one page inside a committed identity, so it draws compositions. Duals serve\n  // both. A tier with no matching-strength approvals falls back to its full\n  // approved pool rather than starving the roll.\n  const wanted = scope === 'direction'\n    ? new Set(['world', 'dual'])\n    : new Set(['composition', 'dual']);\n\n  const approvedByTier = new Map();\n  for (const concept of approved) {\n    const tier = approvedByTier.get(concept.wellTier) || [];\n    tier.push(concept);\n    approvedByTier.set(concept.wellTier, tier);\n  }\n  if (WELL_TIERS.some(tier => !(approvedByTier.get(tier) || []).length)) {\n    throw new Error('concept-seed: every challenger tier needs at least one approved concept');\n  }\n\n  // Optional minimum-rating gate, applied per tier and skipped for any tier it\n  // would empty, so a thin tier degrades to its full approved pool.\n  if (minRating) {\n    for (const [tier, pool] of approvedByTier) {\n      const rated = pool.filter(concept => (concept.review?.rating || 0) >= minRating);\n      if (rated.length > 0) approvedByTier.set(tier, rated);\n    }\n  }\n  // Mode eligibility, per tier and skipped where it would empty a tier. Worlds\n  // used to be drawn with no mode awareness at all, so a build asking for an app\n  // UI could get six worlds that only make sense on a landing page. A world is an\n  // identity and identities transfer further than compositions do, so this is a\n  // ceiling the reviewer sets rather than a category assignment: eligible\n  // everywhere until someone says otherwise.\n  if (mode) {\n    for (const [tier, pool] of approvedByTier) {","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/pbakaus/impeccable/blob/d14711ae3d1a1dd62dee61a358d27f107c51ccd0/plugin/skills/impeccable/scripts/lib/roll-selection.mjs#L152-L188","documentation":"selectApprovedChallengers() builds a roll of challenger concepts for a design direction/surface. It requires EVERY well tier (WELL_TIERS = ['graphic', 'interaction', 'atmosphere']) to have at least one concept with status === 'approved', because each tier contributes two challengers per roll and an empty tier would starve the result. The guard throws before any minimum-rating or mode filtering, since those filters degrade gracefully only when each tier still has a base pool.","triggerScenarios":"Calling selectApprovedChallengers({ scope, key, concepts }) where the concepts array has zero approved entries in one or more of the graphic/interaction/atmosphere tiers — e.g. only graphic and interaction concepts were reviewed and approved, atmosphere was left in 'pending' or 'rejected'.","commonSituations":"Running a challenger roll before the concept-seed review cycle completed all three tiers; a reviewer approved concepts in two tiers and skipped the third; a filtered concept list that accidentally excluded a tier.","solutions":["Approve at least one concept in each missing tier (graphic, interaction, atmosphere) before re-running the roll.","If a tier genuinely has no concepts, generate/seed concepts for it in the concept-seed step first.","Verify concept.wellTier values are set correctly so approvals are not miscategorized."],"exampleFix":"// before — atmosphere has no approved concept\nselectApprovedChallengers({ scope: 'surface', key, concepts });\n\n// after — approve one atmosphere concept first\nconst atm = concepts.find(c => c.wellTier === 'atmosphere' && c.status === 'pending');\natm.status = 'approved';\nselectApprovedChallengers({ scope: 'surface', key, concepts });","handlingStrategy":"validation","validationCode":"import { WELL_TIERS } from './lib/roll-selection.mjs';\n\nfunction hasApprovedInEveryTier(concepts) {\n  const approved = new Set(\n    concepts.filter(c => c.status === 'approved').map(c => c.wellTier)\n  );\n  return WELL_TIERS.every(tier => approved.has(tier));\n}\n\nif (!hasApprovedInEveryTier(concepts)) {\n  // approve more concepts or seed missing tiers before rolling\n  throw new Error('Approve at least one concept in each tier: graphic, interaction, atmosphere');\n}","typeGuard":"function tiersCovered(concepts) {\n  const approved = new Set(concepts.filter(c => c.status === 'approved').map(c => c.wellTier));\n  return ['graphic', 'interaction', 'atmosphere'].every(t => approved.has(t));\n}","tryCatchPattern":null,"preventionTips":["Complete the review cycle across all three tiers (graphic, interaction, atmosphere) before rolling challengers.","Ensure every concept has a correct wellTier so approvals are counted in the right bucket.","If a tier is empty, seed/generate concepts for it in the concept-seed step first."],"tags":["validation","concept-seed","design"],"backgroundTag":null,"analyzedSha":"d14711ae3d1a1dd62dee61a358d27f107c51ccd0","analyzedAt":"2026-08-13T00:52:25.771Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}