Results
Table with columns: Vorarbeiter, Obscura | Vorarbeiter | Obscura |
|---|
| prose_distance (mean of 5 runs) | 1.020 ± 0.059 | 1.140 ± 0.146 |
| tool use (47-case bench) | 41/47 | 40/47 |
| longest verbatim span vs source corpus | 9 words | 9 words |
| passages flagged (≥20w verbatim) | 0/40 | 0/40 |
Prose distance is the mean |z| of eight surface features against a human reference
distribution; lower is closer to human prose.
The difference is +0.120 with a standard error of 0.071 — 1.70 standard errors, 95% CI
−0.018 to +0.258. That interval crosses zero, so "worse" is not established either. What is
established is that it is not better: the threshold for improvement was set at ≤0.950 before
the numbers were seen, and 1.140 fails it.
A human reader given ten blind A/B pairs split roughly 50/50 and could not tell them apart.
Two independent assessments, one statistical and one human, agree on no detectable difference.
What the adapter actually did
Three signals point the same way, and none of them is "better prose":
- Run-to-run variance rose 6.2× (sd 0.059 → 0.146). Output became less consistent.
- Self-repetition got worse —
distinct4 z-score −0.36 → −1.04.
- It moved the wrong way on its strongest training signal. The training pairs separated most
cleanly on lexical variety: the human chapter had higher
ttr than the model's attempt on
218 of 220 pairs. After training, ttr moved from −1.69 to −1.97, i.e. further from human.
That is the profile of an intervention perturbing the model rather than steering it. The most
likely cause is simply too little training: 220 pairs at effective batch 8 for 2 epochs is
54 optimizer steps, over which the ORPO loss stayed flat at ~2.6. The odds-ratio term pushes
away from the rejected response — the model's own prose — without enough signal to pull it
toward the chosen one, so it drifts rather than arrives.
The dataset was capped at 220 pairs for a real reason: the model saturates at ~1,600 words per
generation regardless of the requested length, so pairs had to be drawn from human chapters
already inside that band, or length alone would separate chosen from rejected and the run
would learn "write longer" instead of anything about prose. Lifting that cap needs a two-pass
generation stage, not looser selection.
Memorization
The training corpus is in-copyright fiction, so this was checked directly rather than assumed.
Forty passages from the corpus were used as prompts — the opening 50 words each — with the model
continuing under greedy decoding, which is the worst case for exposing memorization
(sampling hides it, argmax does not). Generated text was then compared against each source
book's full text, after stripping any span that merely echoes the prompt back.
Table with columns: untrained base, Obscura | untrained base | Obscura |
|---|
| median longest verbatim span | 5 words | 5 words |
| p90 | 7 words | 7 words |
| max | 9 words | 9 words |
| max 8-gram overlap | 0.009 | 0.007 |
| flagged ≥20 words | 0/40 | 0/40 |
Identical to the untrained model on every measure. A 9-word maximum is ordinary English
phrasing. Training shifted the weights without memorizing source text.
The training data itself is not published and will not be.
MTP head
peft merge_and_unload() silently drops the 15 mtp.* tensors, and current llama.cpp then
refuses to load the model (missing tensor 'blk.64.attn_norm.weight'). They are grafted back
here from the pre-merge base and verified bit-identical — exact rather than approximate, since
a language-model LoRA never touches that head.
This architecture has 1,199 tensors (850 language, 333 vision, 15 MTP, 1 lm_head). If you
merge adapters into a Qwen3.6 model yourself, check mtp.* survived.
llama-server -m Obscura-Q8_0.gguf -ngl 99 -c 8192 --jinja -fa on -np 1 \
--spec-type draft-mtp --spec-draft-n-max 4
Note that MTP speculation is not bit-identical in practice: on a 47-case tool-use bench, one
decision flipped between speculative and non-speculative decoding at temperature 0. The cause
appears numerical — batched verification and sequential decoding produce slightly different
logits, which flips near-ties — not a logic error.
The adapter's effect depends on the base
The same adapter was evaluated on two bases. It improves the one it was not trained on and
degrades the one it was:
Table with columns: config, prose_distance, tool use (47 cases)| config | prose_distance | tool use (47 cases) |
|---|
| Qwen3.6-27B-TIES | 0.980 ± 0.027 | 35/47 |
| TIES + Federkiel | 0.926 ± 0.026 | 35/47 |
| Vorarbeiter | 1.020 ± 0.026 | 41/47 |
| Vorarbeiter + Federkiel (this model) | 1.140 ± 0.065 | 40/47 |
Neither individual effect clears significance (1.70 and 1.43 standard errors), but the
interaction does: +0.174, se 0.080, 2.17 se, 95% CI +0.017 to +0.330, which excludes zero.
The base changes the sign of the effect.
The likely reason is that the training data is self-referential. Each rejected response was
generated by Vorarbeiter, and ORPO's odds-ratio term pushes away from rejected — so
applying the result back to Vorarbeiter pushes that model away from its own distribution. That
matches the other symptoms: variance up 6.2x, self-repetition worse, and no such damage on TIES,
where tool use is unchanged at 35/47 and prose improves.
If you want the prose effect, apply the adapter to a base that did not generate the rejected
samples. This model is the configuration that does not work; it is published because the
measurement is the useful part.
Scale sweep: one working operating point
Both bases were swept across adapter strengths. Only one configuration improves anything.
Table with columns: base, scale, prose_distance, run-to-run sd| base | scale | prose_distance | run-to-run sd |
|---|
| TIES | 0.0 (stock) | 0.980 ± 0.027 | 0.060 |
| TIES | 1.0 | 0.926 ± 0.026 | 0.059 |
| TIES | 1.5 | 1.093 ± 0.079 | 0.177 |
| TIES | 2.0 | 1.074 ± 0.071 | 0.159 |
Vorarbeiter @0.5 is 3.53 se worse than stock — the only individually significant mean
difference in the sweep, and it shows the harm is not a matter of applying too much: halving the
adapter made it worse, and 0.5 vs 1.0 differ by only 1.50 se. There is no dose-response on the
base the adapter was trained against.
The variance is the cleaner signal. Run-to-run sd is 0.059-0.060 for every neutral or
helpful configuration and 0.146-0.177 for every harmful one — a 2.7x ratio with no overlap,
across two bases and four scales. Where the means are ambiguous (four of six comparisons miss
significance), the spread classifies every configuration correctly. What this adapter does is
inject instability; the mean distance rises because erratic generation drifts from the reference
in both directions.
Tool use is untouched by all of it: on TIES the bench reads 35/47 at every scale including
stock, and Vorarbeiter @0.5 matches stock at 41/47 while its prose is significantly worse. The
perturbation is specific to generation style, not general capability.
Limitations
- No prose improvement. If you want better writing than Vorarbeiter, this is not it.
- Less consistent output — variance 6.2× the base. This is the clearest measured effect.
- Two restraint cases lost on the tool-use bench: it calls
web_research on opinion
questions where the base answers directly.
- Everything Vorarbeiter carries forward: single-turn tool use, delegation bound to egirl's tool
schema, and a persistent Chinese-language gap on the censorship axis.
Method notes
The evaluation harness was recalibrated during this work, which changed what the numbers mean:
- prose_eval originally used 8 prompts and one pass. Scoring identical weights twice gave
1.045 and 0.893 — a 0.15 spread, larger than every model-to-model difference then being
reported with it. It now uses 40 prompts with 5 repeats and prints its own resolution floor.
Differences below ~0.07 are not measurable.
- The reference distribution matters. The default is 25 public-domain novels, which are
Victorian; a reference fitted to modern fiction differs substantially (sent_len_cv
0.735 → 0.663, em_dash_rate 6.02 → 3.51). A model tuned to score well against the first is
being pushed toward 19th-century habits.