Chapter 26 of 30

Diversity Without More Models

Concepts

CHAPTER 26 — Diversity Without More Models

STATUS

Editorial enhancement pass 2026-09-14. Two false claims corrected (rows cannot attribute stance; experiment never estimated counterfactual@3 vs normal@3). Per-stance results now recomputed from frozen rows via input-token signature, matching the report exactly. Exporter fixed in CodeAI (arm suffixes/labels + per-call prompt_variant; regression test; suite 451). No frozen evidence altered; no model call.

CENTRAL QUESTION

Does a portfolio of prompt stances beat the same number of normal draws?

THESIS

Discovery != promotion. The preregistered portfolio lost (9/12 vs 10/12, x1.22 tokens, no portfolio rescue, drop rule fired) while passing more candidates (53 vs 51). Inside it, counterfactual led at matched 3-draw exposure (9 vs normal@3 7 tasks), but its two extra tasks are both solved by normal@12, and normal itself lost 3 tasks going from 12 to 3 draws: a signal for a matched replication, not a better prompt.

LOAD-BEARING CLAIMS

  1. P2C 10/12, 51/144 (51 pass, 92 fail, 1 TIMEOUT with check id), 28,273 tokens; P2S 9/12, 53/144, 34,594 (x1.2236); premium -0.0833; rescue C-only registry-pollution (3/12). 288 calls/candidates/checks. [measured]
  2. Frozen export: arm configs identical except name; prompt_version seeded-code-v1 on all 288; no stance field. Ledger records variant on call.requested; export dropped it. [measured + source]
  3. Token signature: P2C input tokens constant per task; P2S deltas {0, +32, +37, +44} x36 each. Mapping 0 normal (empty suffix), 32 minimality (185 chars), 37 assumption_challenge (220), 44 counterfactual (290); +44 corroborated by P3’s constant counterfactual delta. assumption/minimality split rests on length order only. [measured, inferred attribution]
  4. Recomputed per-stance: passes 11/11/15/16 of 36 (0.306/0.306/0.417/ 0.444); solve sets 7/7/7/9; normal/assumption/minimality identical sets; CF superset; P(CF solves | other stance fails) = 6/15 = 0.40; premise: PRESERVE 2/2 v 2, REMOVE 3/3 v 3, REDEFINE 3/4 v 3, RELOCATE 2/3 v 1. All match P2-results.md. [measured recomputation]
  5. Per-task table (P2C x12 | normal, assumption, minimality, CF x3): env-timing 11|1,3,3,3; dt-roundtrip 10|2,2,1,2; half-up 7|3,2,1,2; splitlines 6|1,1,2,1; lsp-square 4|1,1,2,2; stable-priority 4|0,0,0,2; unsound-cache 3|2,1,3,2; registry-pollution 3|0,0,0,0; strip-query 2|0,0,0,1; single-append 1|1,1,3,1; retry-once 0; size-format 0.
  6. CF’s extra tasks (stable-priority, strip-query) both solved by normal@12; normal 12->3 draws lost 3 tasks (10->7). Two readings (rate vs favorable draw among four stances) unresolvable in P2. [measured + argued]
  7. Prereg H1/H2/H3/Null + drop rule + synthesis ban; report H2 partial, H3 no support. [reported]
  8. Self-Consistency / Self-Refine as design contrasts; mappings ours.

EDITORIAL CORRECTIONS

  • “no recomputation from rows alone can attribute a candidate to a stance” -> false; token signature attributes.
  • “never designed to estimate counterfactual-at-3 against normal-at-3” -> false; portfolio contains normal x3 (7/12).
  • Opening reframed with normal@3 and normal@12 so exposure confound is shown with the same wording.
  • H2/H3 figures upgraded from reported to recomputed.

CODE CHANGE (CodeAI working tree, uncommitted; shared with Ch27)

  • analysis.collect_experiment: join call.requested variant.prompt_variant onto exported call rows.
  • analysis.export_experiment: arms export prompt_suffixes, stance_labels.
  • tests/test_stances.py::test_export_carries_the_prompt_variable_of_each_arm.
  • 26 targeted + 451 full passed.

EVIDENCE

p-series/p2/p2-export.json (calls input_tokens, candidates outcomes, experiment.arms); p-series/p3 (+44 corroboration); p-series-analysis TABLES.md; P2-prereg.md; P2-results.md; stances.py; analysis.py.

CONTROLS / LIMITATIONS

Inferred attribution; 3 draws per stance; 12 tasks one model; one wording per stance; within-corpus; cost as tokens/latency only; synthesis untested.

DEPENDENCIES

Ch25 (coverage vs candidate reliability; rescue discipline), Ch24 (denominators, matched comparisons), Ch23 (sealed fan-out; blind != diverse), Ch18 (reported vs measured), Ch13 (token counts as observations).

FORWARD BRIDGE

Matched 12 v 12 replication of normal vs counterfactual with a frozen rule (Ch27). Result not previewed.

OPEN ITEMS

  • CodeAI export change awaits user review/commit.
  • Ch27 must not re-derive the token signature at length (it references +44).

DIAGRAM (2026-09-14)

Added one-model to four-stances to sealed-candidates to verifier flowchart. Stance names and the variant-per-call record match the chapter’s stance machinery section. No Mermaid for results: the chapter keeps its tables.

Explain this chapter with AI

Copy this prompt into ChatGPT, Claude, Gemini, a local model, or another AI.

Apply this chapter with AI

Copy this prompt into ChatGPT, Claude, Gemini, a local model, or another AI.

Part 5 — More Intelligence Is Not Automatically Better

The subgroup that almost rewrites the chapter

Start with the temptation, because the discipline only means something if the temptation is real. Inside a failed experiment sits this: one wording — counterfactual — with three draws per task covered 9 of 12 tasks. The normal wording, given three draws per task in the same portfolio, covered 7. Read quickly, that is a better prompt.

Now add one more number from the same run. The normal wording, given twelve draws per task in the control arm, covered 10. Same model, same tasks, same words — three extra tasks bought by nothing except more draws. Whatever counterfactual’s two-task lead at three draws means, it is the same size as the effect of simply sampling more.

That gap between interesting and established is the chapter.

Does a portfolio of prompt stances beat the same number of normal draws?

Discovery ≠ promotion

The chapter’s distinction is discovery ≠ promotion, and underneath it sits the denominator lesson Chapter 25 established: more passing candidates ≠ more solved tasks.

The preregistered product question was narrow. Normal wording twelve times per task, against a portfolio of four wordings three times each: 144 calls per arm, one local model, twelve tasks. The portfolio lost. That is the tested result, and nothing later in the chapter revises it.

The discovered hypothesis lives inside the loss. Counterfactual wording produced the widest task coverage of any stance in the portfolio. That is a question to preregister next, not a default to adopt.

Two lines of research frame the design without supporting the outcome. Self-consistency samples many reasoning paths from one model and aggregates them — variation without changing model identity, which is what the portfolio attempted with wording instead of raw draws (Wang et al., 2023). It says nothing about whether stance prompts improve coverage. Self-refine is the contrast: same-model feedback and revision, sequential and exposed to earlier output, where these stances were blind, parallel branches (Madaan et al., 2023). Both mappings onto P2 are the book’s.

What CodeAI does

The stance machinery is a dictionary of four fixed suffixes appended to the unchanged base prompt:

_SUFFIXES = {
    NORMAL: "",
    ASSUMPTION_CHALLENGE: "\n\nBefore modifying the code, identify any existing assumptions, ...",
    MINIMALITY:           "\n\nPrefer the smallest semantic repair. Before adding state, ...",
    COUNTERFACTUAL:       "\n\nIgnore the existing implementation strategy for a moment. ...",
}

def stance_prompt(base_prompt: str, stance: str) -> str:
    return base_prompt + stance_suffix(stance)

Assumption-challenge asks the model to name architectural assumptions that may themselves be wrong. Minimality asks it to prefer removing machinery over adding it. Counterfactual asks it to design from the observable contract before comparing with the existing code. Only the wording was meant to vary. An arm expresses a portfolio by cycling suffixes across its draws, and the ledger records each call’s variant on call.requested. 1 2

One model in, four wordings out, one verifier over all of it:

    flowchart TD
    M["same model<br/><i>wording is the only variable</i>"] --> N["normal<br/><i>unmodified prompt</i>"]
    M --> A["assumption challenge<br/><i>name what may be wrong</i>"]
    M --> I["minimality<br/><i>smallest repair first</i>"]
    M --> C["counterfactual<br/><i>design from the contract</i>"]
    N --> S["sealed candidates<br/><i>variant recorded per call</i>"]
    A --> S
    I --> S
    C --> S
    S --> V["verifier<br/><i>coverage, not candidate counts</i>"]
  

The preregistration, frozen before any model call, asked whether manufactured error diversity inside one model could replace heterogeneous-model diversity. H1: the portfolio covers more verified tasks than matched normal sampling. H2: stance diversity decorrelates failures even if it does not convert them into solves. H3: gains concentrate where the repair lives in the abstraction (REMOVE, RELOCATE, REDEFINE labels). A drop rule: if the portfolio does not beat normal, drop stance framing rather than invent elaborate personas. It also forbade any conclusion about synthesis. 3

The task set was built to give stances their best chance: the four tasks every P1.1 arm failed, plus eight near-misses where earlier arms disagreed. Twelve tasks, one model (qwen-local in the report, qwen2.5-coder:latest in every frozen call row), 288 calls, 288 checks. 3 4

The preregistered result first

Recomputed from frozen rows: 5

Arm Tasks covered Candidate passes Tokens
Normal × 12 10/12 (0.833) 51/144 (0.354) 28,273
Stance portfolio 9/12 (0.750) 53/144 (0.368) 34,594 (×1.22)

Coverage premium −0.083. No rescue for the portfolio: nothing it solved had been missed by normal. The one rescue in the run belongs to normal — v2-registry-pollution, solved on 3 of 12 normal draws and missed by every stance. The portfolio cost about 22% more tokens and won less, so the drop rule fires: stance diversification as a portfolio strategy is dropped. 5 6

Then the awkward second row. The losing portfolio passed more candidates, 53 against 51, while covering fewer tasks. Its passes piled up on tasks already solved while one more task went uncovered. In P1.1 the heterogeneous portfolio had better coverage with worse candidates; here the stance portfolio has more passing candidates with worse coverage. Coverage and candidate competence are different quantities, and they can come apart in either direction. 5

Recovering the stance from the rows

The per-stance story lives in the P2 report, and the first draft of this chapter left it there because the frozen export carries no stance field — both arms export identical configurations apart from their names, with every call row showing the same prompt version, even though the ledger recorded each call’s variant and the exporter simply never copied it out. 4 7

The rows still carry a signature, because every normal-arm call on a given task used the same number of input tokens, so subtracting that baseline from each portfolio call on the same task leaves exactly four values, 36 calls each:

base = {task: input_tokens for every P2C call}            # constant per task
delta = portfolio_call.input_tokens - base[task]
# observed deltas: 0, +32, +37, +44 — exactly 36 calls each
stance = {0: "normal", 32: "minimality",
          37: "assumption_challenge", 44: "counterfactual"}[delta]

The mapping is an inference, and it rests on three things. A zero delta can only be the empty normal suffix. The other three order the same way as the suffix lengths (185, 220, and 290 characters). And the counterfactual assignment has an independent check: in the next chapter’s matched replication, where counterfactual is an entire arm, every counterfactual call carries exactly +44 input tokens over normal. The assignment between assumption-challenge and minimality rests on length order alone. 4 8

Attributed that way, the frozen rows reproduce the report’s per-stance figures exactly — candidate passes 11, 11, 15, 16 out of 36; solve sets of 7, 7, 7, and 9 tasks — so the stance numbers below are recomputed from rows by token signature, not merely quoted. This recomputation was done while editing the chapter; it is not part of the analysis verifier. 4

The exporter is repaired in the current CodeAI working tree: exported arms include their prompt suffixes and stance labels, and exported call rows carry each call’s prompt variant, with a regression test. The frozen exports are unchanged, which is why the signature was needed. 7 9

The subgroup, honestly labeled

Per task, passing draws out of twelve for the control arm and out of three for each stance:

Task Normal × 12 Normal × 3 Assumption × 3 Minimality × 3 Counterfactual × 3
env-timing 11 1 3 3 3
dt-roundtrip 10 2 2 1 2
half-up-rounding 7 3 2 1 2
splitlines-cr 6 1 1 2 1
lsp-square 4 1 1 2 2
stable-priority 4 0 0 0 2
unsound-cache 3 2 1 3 2
registry-pollution 3 0 0 0 0
strip-query 2 0 0 0 1
single-append 1 1 1 3 1
retry-once-accepted 0 0 0 0 0
size-format 0 0 0 0 0
Tasks covered 10 7 7 7 9

4

The hypotheses read off the same rows. H2, decorrelation: normal, assumption-challenge, and minimality solve exactly the same seven tasks, so among those three there is no decorrelation at all. Counterfactual’s nine contain all seven. Of the fifteen (stance, task) pairs where another stance failed, counterfactual solved six — the report’s 0.40. H3, premise concentration: against the control arm, the portfolio matches on PRESERVE (2/2) and REMOVE (3/3), ties on REDEFINE (3/4 each), and loses RELOCATE (1/3 against 2/3). Neither supporting branch survived. 4 6

Now look at counterfactual’s two extra tasks: stable-priority and strip-query. Both are tasks the normal wording solves when given twelve draws, four times and twice. Counterfactual did not reach beyond normal’s competence boundary. It reached two tasks within that boundary at three draws, where normal at three draws did not.

That admits two readings, and P2 cannot choose between them. Counterfactual may have a genuinely higher per-draw success rate on some tasks. Or twelve tasks with three draws each simply produced a favorable draw for one of four wordings — which, with four stances competing, is not an unlikely thing to happen to one of them. The honest statement is the narrow one: among the portfolio’s stances, counterfactual produced the widest coverage and the highest candidate rate (16/36) at matched three-draw exposure, in one twelve-task sample. That is enough to ask a matched question. It is not enough to call counterfactual the better prompt. 4

And the comparison that looks strongest is the least fair. Counterfactual’s 9 from three draws beside normal’s 10 from twelve compares different exposures, as the normal-at-three column shows: the same words lost three tasks when their draws were cut to a quarter.

One model, twelve tasks, one wording per stance: that scope stays attached to every exploratory sentence.

Checking it without trusting it

The analysis verifier covers P2 at arm level — 10/12 against 9/12, token totals, negative premium, no portfolio rescue — and catches its seeded corruption; the export verifier checks all four frozen bundle hashes. 5

The per-stance table is outside both verifiers. It is recomputed from frozen rows through an inferred attribution, and it matches the historical report on every per-stance figure the report gives. That is two independent routes to the same numbers — the report from recorded variants at run time, the recomputation from token counts afterward — which is stronger than either alone, and still weaker than a recorded field. 4 6

The report’s limits are kept whole: one local model, twelve tasks, one arbitrary wording per stance, cloud-model generality untested, cost known only as tokens and latency. The drop rule fired as written, and no personas were invented to rescue the portfolio. 6

What this is not

  • Not a stance victory — the tested portfolio lost on coverage at higher token cost.
  • Not a counterfactual finding, because a two-task lead at three draws in one twelve-task sample, on tasks normal also solves with more draws, cannot carry that weight.
  • Not prompt science — one wording per stance cannot separate the idea of a stance from its phrasing.
  • Not synthesis — no debate or combination was tested, and the preregistration forbids conclusions about it.

Where it is still weak

  1. Stance attribution is inferred. Token signatures reproduce the report exactly, but assumption-challenge versus minimality rests on suffix length order. 4
  2. Three draws per stance. Every per-stance comparison is a small-sample reading of twelve tasks. 4
  3. One wording per stance. Idea and phrasing are confounded by design. 10
  4. Tiny and local. Twelve tasks, one model; significance and generality are unavailable. 6
  5. The attractive direction is untested. Counterfactual at matched twelve-draw exposure exists nowhere in these rows.

Do this now

Thirty minutes. Separate what you tested from what you noticed.

  1. Write down the comparison your experiment preregistered — arms, counts, primary metric — before opening results. Score that question first, in one sentence, win or lose.
  2. Only then break results down by subgroup, and put each subgroup’s exposure next to its outcome. If the same treatment at a different exposure is available, as normal-at-three was here, put it in the table too.
  3. Check whether your exported rows can attribute each subgroup. If they cannot, look for a signature (token counts, request hashes) before accepting a report-only number — and fix the export so the next run does not need one.
  4. Write the next experiment as a frozen question with matched exposure and a promotion rule. Freeze it before running.

If you are building with an assistant:

Preregister the product comparison before running: arms, draw counts,
primary metric, drop rule. Score the preregistered question first and let
a loss stand. Break results down by subgroup only afterward, with each
subgroup's exposure beside its outcome, and include the same treatment at
other exposures where the data has it. Make sure exported rows record the
manipulated variable per call; where old exports do not, recover attribution
from a verifiable signature and label it as inferred. Turn the most
attractive subgroup into the next frozen, matched question instead of a
default.

Failure modes

  • Promoting the subgroup. A two-task lead at three draws is a question about per-draw rates, not an answer.
  • Comparing across exposures. Nine from three against ten from twelve measures draws as much as wording.
  • Spending candidate counts. Fifty-three passes on nine tasks lose to fifty-one on ten.
  • Accepting “report-only” too early. The rows may carry the attribution the export dropped.
  • Trusting an inferred label like a recorded one. A signature that reproduces a report is strong; it is still an inference.
  • Inventing personas after the loss. The drop rule exists for the morning after a null.

What this chapter established

  • The preregistered stance portfolio lost: 9/12 tasks against normal’s 10/12 at ×1.22 tokens, with no portfolio rescue, and the drop rule fired. 5
  • More candidate passes (53 against 51) accompanied fewer tasks covered. 5
  • Stance attribution is recoverable from frozen rows by input-token signature and reproduces the report’s per-stance figures exactly; the exporter that dropped it is repaired in current source. 4 11
  • Counterfactual led at matched three-draw exposure (9 against normal’s 7 tasks), on two tasks normal also solves with twelve draws — a signal that earns a matched replication and nothing more. 4

Next

The portfolio is dropped and the signal is fenced. What remains is one clean question: give normal and counterfactual wording the same exposure — twelve draws per task each, same tasks, one variable changed — freeze the rule, and see whether counterfactual’s lead survives.

Continue with Replicate Before You Believe.

References

  • Xuezhi Wang, Jason Wei, Dale Schuurmans, Quoc Le, Ed Chi, Sharan Narang, Aakanksha Chowdhery, and Denny Zhou. Self-Consistency Improves Chain of Thought Reasoning in Language Models. ICLR, 2023. arXiv:2203.11171.
  • Aman Madaan, Niket Tandon, Prakhar Gupta, Skyler Hallinan, Luyu Gao, Sarah Wiegreffe, Uri Alon, Nouha Dziri, Shrimai Prabhumoye, Yiming Yang, Shashank Gupta, Bodhisattwa Prasad Majumder, Katherine Hermann, Sean Welleck, Amir Yazdanbakhsh, and Peter Clark. Self-Refine: Iterative Refinement with Self-Feedback. arXiv:2303.17651, 2023. Paper.

Implementation sources: P2 ran on the P-series CodeAI lineage, with stance texts frozen at a348010 (src/codeai/stances.py: _SUFFIXES, stance_suffix, stance_prompt; src/codeai/experiments.py: ArmDef, run_arm; src/codeai/analysis.py: arm_metrics, unique_rescues, build_report). The suffix excerpt abbreviates the source strings. The exporter repair (collect_experiment joins each call’s prompt_variant; export_experiment writes arm prompt_suffixes and stance_labels) and its regression test are uncommitted in the CodeAI working tree on top of a1b562a; the full suite passed (451). The token-signature attribution and per-stance table were recomputed from frozen rows during editing. Evidence: experiments/applied-ai/evidence/p-series/ (frozen exports, hashes verified), experiments/applied-ai/evidence/p-series-analysis/ (analysis.json, TABLES.md, analyze_pseries.py, verify_analysis.py), C:/Projects/codeai/experiments/P2-prereg.md and P2-results.md. Nothing was rerun and nothing frozen was modified.


  1. Source inspection: src/codeai/stances.py (_SUFFIXES, stance_prompt). ↩︎

  2. Source inspection: src/codeai/experiments.py (ArmDef). ↩︎

  3. Report: C:/Projects/codeai/experiments/P2-prereg.md↩︎ ↩︎

  4. Measured run: experiments/applied-ai/evidence/p-series/p2↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  5. Measured run: experiments/applied-ai/evidence/p-series-analysis↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  6. Report: C:/Projects/codeai/experiments/P2-results.md↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  7. Source inspection: src/codeai/analysis.py (collect_experiment, export_experiment). ↩︎ ↩︎

  8. Measured run: experiments/applied-ai/evidence/p-series/p3↩︎

  9. Source inspection: tests/test_stances.py (test_export_carries_the_prompt_variable_of_each_arm). ↩︎

  10. Source inspection: src/codeai/stances.py↩︎

  11. Source inspection: src/codeai/analysis.py (export_experiment). ↩︎