Appearance
Restricting places
There is no placeFilter field on a recipe. "Ones only", "ones and tens", "everything except ones" — all of it is expressed through rules you attach to the recipe.
This page is the practical catalogue of those expressions. It assumes you already know what place, formula, and digitBefore mean; if not, read Decimal places first.
The basic place restriction
Attach a rule with role: constraint, scope: step, usage: constraint, and leave the count fields null — counts do not apply to constraints.
| Intent | Expression |
|---|---|
| Ones only | place = 1 |
| Tens only | place = 10 |
| Hundreds only | place = 100 |
| Ones and tens | place IN (1, 10) |
| Tens and hundreds | place IN (10, 100) |
| Everything except ones | place NOT IN (1) |
These are evaluated inside the same classifier the feasibility analysis calls, so they prune candidates with the full power a dedicated structural filter would have had. The only difference is that an out-of-place candidate is generated and then rejected, rather than never generated — one extra memoized rule evaluation per distinct state.
The generator's operand alphabet comes from sumMax alone (every power of ten up to the ceiling), so a place constraint is how you narrow it. See Sum range.
A bare place constraint silently kills every composite step
place is null on a multi-place composite step such as +47 — a composite step does not have one affected place. A constraint like place = 1 therefore rejects every composite step the recipe could otherwise produce, with no error and no diagnostic. The recipe simply generates atomic steps only, or reports infeasible.
If your recipe uses place channels, do not restrict combinations with a bare place comparison. Use a per-place digit test instead:
digitAt(current_value, 1) != 0Restricting to a specific operand set
Values like 10, 20, 30, 50 are atomic — exactly one non-zero digit — so they are already in the generator's candidate alphabet. Restricting a recipe to them needs no special mechanism, just a narrower expression:
place = 10 AND formula IN (1, 2, 3, 5)Since formula = abs(current_value) / place, this matches the operands ±10, ±20, ±30, ±50.
formula uses abs, so both signs are admitted by default. Pin the sign explicitly when you want only additions:
current_value > 0 AND place = 10 AND formula IN (1, 2, 3, 5)An expression this specific usually belongs on the pattern rule itself — the target or filler rule the recipe is built around — rather than as a separate global constraint.
Conditioning on the running sum
digitBefore is the digit of prev_sum at the place current_value affects. It is the key input for pattern classification, and it lets a rule describe the position a technique applies from:
current_value > 0 AND place = 10 AND formula = 8 AND digitBefore IN (2, 3, 4)Read: "add 80, but only when the tens digit is currently 2, 3, or 4."
A rule like this needs a sumMax with enough headroom for the resulting carry. digitBefore >= 2 at the tens place implies prev_sum >= 20, and +80 needs room up to roughly prev_sum + 80. A recipe whose sumMax is too tight for its own rules reports infeasible — correctly, not spuriously.
Pinning the opening value
Place and sum-range rules constrain transitions. They say nothing about prev_sum at step 0 unless a rule explicitly references step_index.
This matters more than it sounds. A recipe pinning place = 10 can still open on a value whose ones digit is non-zero, because nothing in place = 10 constrains where the exercise starts. To pin the opening digit at a given place:
IF step_index = 0 THEN digitAt(prev_sum, 1) = 0digitAt(value, place) returns the digit of abs(value) at the given decimal place — useful for inspecting a place other than the one current_value itself affects. See Digit functions and the function reference.
When opening rules matter
Every exercise the API generates opens from an empty abacus (prev_sum = 0 at step 0), so a step_index = 0 guard is often already satisfied. It becomes load-bearing when a caller supplies an explicit opening value as an authoring probe, since such a value is seated as prev_sum for step 0 without passing through the classifier — no pattern rule and no constraint applies to it.
Quick reference
| Want | Expression | Attach as |
|---|---|---|
| Steps only in the ones | place = 1 | constraint role, step scope, usage: constraint |
Steps only ±10, ±20, ±30, ±50 | place = 10 AND formula IN (1, 2, 3, 5) | pattern role, on the target or filler rule |
| Only additions of that set | current_value > 0 AND place = 10 AND formula IN (1, 2, 3, 5) | pattern role |
| Tens digit conditioned on the sum | place = 10 AND formula = 8 AND digitBefore IN (2, 3, 4) | pattern role, step scope |
| Pin the opening digit | IF step_index = 0 THEN digitAt(prev_sum, 1) = 0 | constraint role, step scope |
| Restrict a channel combination | digitAt(current_value, 1) != 0 | constraint role, step scope, place: 0 |
A note on conflicting restrictions
A rule combination that admits nothing — two mutually exclusive place constraints on the same recipe, say — is not detected when you save the recipe. Feasibility is computed by the rule engine at generation time, not by the editor.
The practical workflow is to generate a preview batch after editing and check that it still produces results. An empty or degraded batch is the signal; Troubleshooting covers reading the failure.
See also
- Decimal places —
place,formula,digitBefore, and their null behaviour. - Multi-place combo steps — producing steps that touch several places at once.
- Worked examples — these expressions inside complete recipes.
- Common mistakes — expression-level pitfalls.