Appearance
Troubleshooting
A recipe that will not generate fails in one of a small number of recognisable ways. This page maps each failure to its usual causes.
Reading the failure
Generation reports one of five outcomes:
| Reason | Meaning |
|---|---|
invalid-options | The requested step count or start value is not acceptable. |
invalid-recipe | The recipe could not even be compiled — a structural problem, reported before any search. |
infeasible | Proven by the feasibility analysis: no valid sequence exists, with attribution to the rules at fault. |
exhausted | The whole reachable search tree was explored without finding a sequence. |
budget-exceeded | The search ran out of node/time budget. Not a proof of infeasibility. |
The distinction matters. infeasible is a mathematical statement about your recipe and always deserves a configuration change. budget-exceeded says only that the search gave up — retrying, or loosening the recipe slightly, may succeed.
The failure carries diagnostics worth reading before changing anything:
unsatisfiable— which rules' count requirements cannot be met, and by how much.rejectionHistogram— how many candidates each rule rejected, keyed by rule slug. A syntheticunclassifiedkey counts candidates that matched no pattern rule at all.minFeasibleSteps— the shortest step count that would have worked, when one exists.
A rule sitting at the top of the rejection histogram is the first place to look.
"Recipe is infeasible for the requested stepsCount"
The message names the rules whose count requirements could not be satisfied:
text
Recipe is infeasible for the requested stepsCount:
RULE-X cannot have its count requirements satisfied.Three causes account for most occurrences.
Cause 1: the rule's own transition structure cannot chain that far
An infeasible verdict on a rule that "looks correct" is very often arithmetic, not a broken expression.
Take a rule admitting only +80 when the tens digit is 2, 3, or 4:
current_value > 0 AND place = 10 AND formula = 8 AND digitBefore IN (2, 3, 4)Applying it maps the tens digit 4 → 2 → 0. After two applications the tens digit is 0, which the rule no longer admits. The rule sustains exactly two consecutive steps and goes infeasible at three or more, no matter how the rest of the recipe is configured.
Before debugging the expression, check the requested step count against what the rule's structure can actually chain. Count the digit transitions the rule permits and see how long a walk they support.
Cause 2: sumMax is too tight for the carry the rule needs
A rule conditioning on digitBefore implicitly requires the running sum to reach a certain magnitude, and then to have headroom for the result.
The same +80-at-digitBefore IN (2, 3, 4) rule needs prev_sum >= 20 before it can ever fire, and room up to roughly prev_sum + 80 afterwards. On a recipe with sumMax: 99 there is barely any slack; on a tighter ceiling the rule can never fire at all.
The infeasible report is correct in this case — the recipe genuinely has no solution. Raise sumMax (up to the limit of 1999) or relax the digitBefore set.
Cause 3: no rule admits an opening from an empty abacus
Generated exercises open from an empty abacus. That means prev_sum is 0 at step 0, so digitBefore is 0 at every place.
A recipe whose pattern rules all require a non-zero digitBefore has no legal first move. It reports infeasible, and that is the honest signal: the recipe cannot be worked from zero.
Plenty of canonical patterns do admit digitBefore = 0 — most Plain additions include 0 in their digit set (RULE-43, Plain (9) - Addition, admits digitBefore of 0 and nothing else), and so do several Rule 10 subtractions. The fix is to give the recipe a filler rule that can open from zero.
Check the structural message
If the failure message is the structural variant — "No admissible sequence exists for any candidate start value" — no individual rule could be blamed. That points at the constraints and the sum range rather than at any single pattern rule's quota.
A misspelled variable silently blocks everything
Variable names are snake_case
currentSum, prevSum, and stepIndex are not variables. They are unrecognised identifiers.
An unrecognised identifier resolves to undefined. Every comparison against undefined is false, so the rule fails on every candidate and silently blocks the entire recipe. Nothing warns you: unknown functions raise an error, but unknown variables do not.
Worse, the failure does not name the typo. It reports the pattern rule whose count requirement went unsatisfiable — an entirely different, correctly written rule:
text
Recipe is infeasible for the requested stepsCount:
RULE-X cannot have its count requirements satisfied.RULE-X is innocent. The constraint containing currentSum <= 19 is what emptied the candidate space.
The diagnostic habit: if a recipe worked and suddenly reports infeasible after an edit, check every newly added or edited expression for a stray camelCase variable before assuming the arithmetic is wrong. The correct spellings are prev_sum, current_value, current_sum, step_index, last_step_index, plus isLastStep, place, formula, and digitBefore — see Variables and Context variables.
A place constraint on a recipe with channels
If a recipe attaches rules to place-channels (place: 1, 10, 100, 1000) and also carries a constraint rule that compares the place context variable:
place = 1…then every composite step is silently rejected. place is null on a composite step — a step touching several decimal places has no single affected place — so the comparison fails for all of them.
Symptoms: the recipe generates, but produces only atomic steps and never the multi-place steps the channels were configured for. Or, if the channels were load-bearing, it reports infeasible. There is no error message pointing at the constraint.
The fix: restrict channel combinations with a per-place digit test instead of a bare place comparison:
digitAt(current_value, 1) != 0The same trap catches constraints written for single-digit work. A last-step rule requiring current_value > -6 AND current_value < 6, for example, cannot be satisfied by a tens-channel step and will make a channel recipe infeasible.
See Restricting places and Multi-place combo steps.
current_sum inside a place-scoped rule
A rule attached at a non-zero place that references current_sum is rejected at compile time with an invalid-recipe failure. This is not a bug to work around: inside a channel, current_sum would mean "prev_sum plus that one channel's digit", a state the exercise never actually passes through, since a composite step commits every channel together.
Move whole-step sum conditions to an ordinary place: 0, usage: constraint attachment. Written there they work unchanged on channel recipes.
Exceeding the 31 pattern-rule ceiling
Compilation fails with invalid-recipe when a recipe has more than 31 pattern-role attachments:
text
Recipe has more than 31 pattern rules;
the bitmask representation cannot address them.The ceiling counts attachments, not distinct rules — and channels multiply against it. N rules attached across C channels costs N × C slots, not N:
| Configuration | Pattern-role attachments |
|---|---|
| 18-rule Plain family, one channel | 18 |
| 18-rule family on ones + 2 rules on tens | 20 |
| 18-rule family on ones + 1 consolidated rule on tens | 19 |
| 18-rule family duplicated across two channels | 36 — will not compile |
| 1 consolidated rule on each of two channels | 2 |
Constraint-role attachments do not count toward this ceiling.
The escape hatch is the consolidated "(any)" rules — RULE-59 (Rule 5 (any)), RULE-60 (Rule 10 (any)), RULE-61 (Combo (any)), RULE-62 (Plain (any)). Each collapses a whole family into one rule and one slot. The cost is that a consolidated rule cannot carry a per-digit target/review/filler split.
Reach for consolidation on the channels where a per-digit quota split is not actually needed, and keep the full family on the one channel where it is. Worked examples shows both ends of this tradeoff.
Other structural rejections
These all surface as invalid-recipe, before any search runs:
| Problem | Rule of thumb |
|---|---|
A constraint-role rule attached with usage target/review/filler/forbidden | Only usage: constraint accepts a constraint-role rule. |
A pattern-role rule attached with usage: constraint | Constraint usage requires a constraint-role rule. |
A non-zero place on a constraint-role rule | Only pattern rules may be scoped to a channel. |
exactCount alongside minCount or maxCount | Use one style or the other. |
minCount greater than maxCount | Impossible by construction. |
| The same rule attached twice at the same place | Uniqueness is on (recipe, rule, place). |
A checklist
When a recipe stops generating, in order:
- Read the failure reason. Is it a proof (
infeasible) or a give-up (budget-exceeded)? - Read the rejection histogram. Which rule is rejecting everything?
- Scan every recently edited expression for camelCase variable names.
- Check whether the target rule's digit transitions can chain for the requested step count.
- Check
sumMaxagainst the largest running sum the rules imply. - Confirm at least one pattern rule admits
digitBefore = 0, so the exercise can open. - If the recipe uses channels, confirm no constraint compares
placedirectly. - Count the pattern-role attachments against the ceiling of 31.
See also
- Recipe concepts — usage/role compatibility and count quotas.
- Sum range —
sumMaxand narrower windows. - Restricting places — place expressions and their null behaviour.
- Common mistakes — expression-level pitfalls.