pbakaus/impeccable · error
concept-seed: --candidate-count must be an integer from 5…
Error message
concept-seed: --candidate-count must be an integer from 5 to 7
What it means
Thrown by the concept-seed script when --candidate-count is not an integer between 5 and 7 inclusive. The value is read naively via args.indexOf('--candidate-count') followed by Number(args[i+1]), so a missing value yields Number(undefined) = NaN and the equals form --candidate-count=6 is not recognized at all. The 5-7 band is deliberate: fewer than 5 candidates starves the ranked roll, more than 7 bloats the model's consideration set. Default is 7 when the flag is omitted.
Solutions
- Pass a plain space-separated integer in range: `--candidate-count 6`.
- Omit the flag entirely to get the default of 7.
- If you used `--candidate-count=6`, rewrite it as `--candidate-count 6` — the equals form is silently parsed as NaN.
- When scripting, quote and default the variable: `--candidate-count "${COUNT:-7}"` after validating COUNT is 5, 6, or 7.
Example fix
# before node skill/scripts/concept-seed.mjs --scope direction --candidate-count=6 # NaN -> throws node skill/scripts/concept-seed.mjs --scope direction --candidate-count # value missing -> throws # after node skill/scripts/concept-seed.mjs --scope direction --candidate-count 6 node skill/scripts/concept-seed.mjs --scope direction # default 7
Defensive patterns
Strategy: validation
Validate before calling
const SEED_COUNT_RE = /^[5-7]$/;
function validCandidateCount(raw) {
return raw == null || (typeof raw === 'string' && SEED_COUNT_RE.test(raw.trim()));
}
// before shelling out:
if (!validCandidateCount(process.env.CANDIDATE_COUNT)) {
console.error('--candidate-count must be 5, 6, or 7 (space-separated)');
process.exit(2);
}
spawnSync('node', ['skill/scripts/concept-seed.mjs', '--scope', 'direction', '--candidate-count', COUNT]); Type guard
function isValidSeedCount(v) {
return v == null || (typeof v === 'number' && Number.isInteger(v) && v >= 5 && v <= 7);
} Prevention
- Always pass --candidate-count as a separate space-separated token; the parser does not understand --candidate-count=6.
- Default unset shell variables with ${COUNT:-7} before using them as the flag value.
- When wrapping the script, validate the count is one of 5/6/7 before spawning the child process.
When it happens
Trigger: Running `node skill/scripts/concept-seed.mjs --scope direction --candidate-count 4` (or 8, or 5.5, or 'six'); passing `--candidate-count` as the last argument (next token undefined -> NaN); using `--candidate-count=6` (the indexOf-based parser does not recognize the = form, so it reads the next token or undefined); passing a value like '6x' that Number() coerces to NaN.
Common situations: Agent or user tuning the seed hand size; copy-pasting a command template that used = syntax; truncating the command line so the value falls off; scripting the call and interpolating an empty variable (`--candidate-count $COUNT` with COUNT unset).
Related errors
- [impeccable live]
- serve-question: --start needs --payload
- serve-question: --stop needs --key
- serve-question: --update needs --key and --payload
- serve-question: --wait needs --key
AI-assisted analysis of pbakaus/impeccable@f88b2837a7 (2026-08-18).
Data as JSON: /api/errors/2b8d969a1c76e5a3.
Report an issue: GitHub.
Appendix: source
Thrown at skill/scripts/concept-seed.mjs:333
if (register !== null && reroll < 1) {
throw new Error('concept-seed: --register steers a re-roll round; pass --reroll <n> with it');
}
if (register !== null && scope !== 'direction') {
throw new Error('concept-seed: --register applies to direction rounds only');
}
if (mode !== null && !SEED_MODES.has(mode)) {
throw new Error('concept-seed: --mode must be persuade, operate, read, or experience');
}
// Grain needs no mode: how much of the product is in play is independent of
// which register of work it is.
if (grain !== null && !COMPOSITION_GRAINS.includes(grain)) {
throw new Error(`concept-seed: --grain must be one of ${COMPOSITION_GRAINS.join(', ')}`);
}
if (platform !== null && !COMPOSITION_PLATFORMS.includes(platform)) {
throw new Error(`concept-seed: --platform must be one of ${COMPOSITION_PLATFORMS.join(', ')}`);
}
if (!Number.isInteger(candidateCount) || candidateCount < 5 || candidateCount > 7) {
throw new Error('concept-seed: --candidate-count must be an integer from 5 to 7');
}
const unit = (salt) => {
const h = crypto.createHash('sha256').update(`${scope}:${salt}:${key}`).digest();
return h.readUInt32BE(0) / 0xffffffff;
};
const indexSalt = reroll === 0 ? 'index' : `index:reroll-${reroll}`;
const buildIndex = 3 + Math.floor(unit(indexSalt) * (candidateCount - 2)); // 3..candidateCount
// Surface scope deals a hand of three grounded structures: one card is not
// a choice, and the full ranked list would hand selection back to the
// model's taste. The dice pick all three; the primary index leads. The
// no-lineup rule stays direction-only, where it was written for worlds.
const dealtIndices = [buildIndex];
for (let draw = 0; scope === 'surface' && dealtIndices.length < Math.min(3, candidateCount); draw += 1) {
const idx = 1 + Math.floor(unit(`${indexSalt}:deal-${draw}`) * candidateCount);
if (!dealtIndices.includes(idx)) dealtIndices.push(idx);
if (draw > 64) { // hash repeats cannot stall the deal
for (let fill = 1; dealtIndices.length < Math.min(3, candidateCount); fill += 1) {
if (!dealtIndices.includes(fill)) dealtIndices.push(fill);View on GitHub (pinned to f88b2837a7)