# Why does Qwen3-Coder-Next fail at AILang Form-A? — ablation finding

**Date:** 2026-06-02  **Model:** Qwen/Qwen3-Coder-Next (IONOS, temp 0.2)
**Method:** try-and-error from a minimum upward. A ladder L0 (trivial) → L7
(full SMA), each level run independently with minimal few-shot context, single
shot. Two ladders: ladder 1 with a base few-shot that only *destructures*
(`match`); ladder 2 after adding one example that *constructs* (`term-ctor`).
Raw logs: `qwen-ablation-min.md` (ladder 1), `qwen-ablation-ctor.md` (ladder 2).
Driver: `qwen_ablation.py`.

## The two ladders

| Level | task | ladder 1 (min) | ladder 2 (+term-ctor example) |
|---|---|---|---|
| L0 | fn returns 42 | ✅ | ✅ |
| L1 | fn ×3 | ✅ | ✅ |
| L2 | main prints 7 | ✅ | ✅ |
| L3 | ADT + match | ❌ check | ✅ |
| L4 | build list + recursive length | ❌ `Cons` unbound | ❌ paren misplace |
| L5 | Series, print len | ❌ missing newline | ✅ |
| L6 | Series.at | ✅ | ✅ |
| L7 | full SMA | ❌ check | ❌ paren imbalance |

One example of the missing construct moved Qwen from 4/8 to **6/8**.

## The answer: it is NOT general incapacity — there are two distinct walls

**Qwen is not "stupid" at Form-A.** With minimal, *correct* few-shot context
it writes 6 of 8 tasks green — including ADTs, `match`, recursive functions,
and Series library use (`new Series`, `push`, `at`, `len`). The two failures
are specific and different in kind:

### Wall 1 — unfamiliar constructs (SOLVABLE by one example)

Qwen does not know constructs it hasn't seen, and guesses plausibly wrong:
- L4 ladder 1: it built a list with `(app Cons 1 (app Cons 2 …))` and bare
  `Nil` — calling the constructor like a function → `unbound-var: Cons`. It
  had only seen `match`/`pat-ctor` (destructuring), never `term-ctor`
  (construction).
- Adding ONE few-shot that uses `term-ctor` flipped L3 and L5 to green, and
  removed the `Cons`-as-function error in L4. The model generalises from a
  single example of a construct.

This is the cheap wall: feed the construct once and it clears.

### Wall 2 — paren/nesting discipline at depth (NOT solved by examples)

The two that stayed red (L4, L7) both fail on **S-expression bracketing**,
not on any missing knowledge:
- L4 ladder 2: the `length` function is flawless. `main` builds
  `(let xs (term-ctor … (term-ctor … (term-ctor … (term-ctor IntList Nil)))`
  — closing the nested `term-ctor` value one paren too early, so the `let`
  body slides inside the value. **Total paren count is balanced (43 open / 43
  close)** — the parens are merely *misplaced*. The model is not under-closing
  globally; it loses track of the nesting structure at depth.
- L7 (SMA): 49 open / 47 close — under-closed.

The grin/red split tracks **nesting depth**, not feature: every green task is
shallow (one or two levels), every red one is deeply nested (4× nested
`term-ctor` in a `let`; the SMA's stream-loop composition). This is a
mechanical limit on tracking deep paren nesting, and examples do not fix it —
consistent with the earlier full-SMA probes (run 2: correct ownership
threading, died on brackets; run 3: ~80k-token context tipped the same
weakness into a non-terminating `(seq (seq …))` repetition loop).

## Takeaway

The bottleneck for this model on Form-A is the **fully-parenthesised surface
itself** at depth, not the language's semantics or its vocabulary. Two
levers follow, both deliberate next steps, not run here:
1. Few-shot every non-obvious construct (cheap, clears Wall 1).
2. For Wall 2, the surface is the problem — the natural test is the
   **`.ail.json` authoring form**, which removes human-style paren-counting
   (structure is carried by JSON nesting the model is far more trained on).
   The cma harness already renders both cohorts; this is the obvious A/B.
