# Experiment 005 run 1 — PREREG (protocol v1.3)

**FROZEN 2026-07-11 · tag `labs-005-prereg-v1` · amended 2026-07-11 per the
round-3 audit → **v1.1**, tag `labs-005-prereg-v1.1` · amended 2026-07-11
per the round-4 audit → **v1.2**, tag `labs-005-prereg-v1.2` · amended
2026-07-11 per the round-5 audit → **v1.3**, tag `labs-005-prereg-v1.3`
(design.md alignment only — no operative rule in this document changed) ·
lineage v1 → v1.1 → v1.2 → v1.3, all pre-call · changes hereafter require
an entry in `artifacts/deviations.md`**

Status: **v1.3 — amended per the round-5 audit (`audit-round-5.md`,
finding R5-M01: three stale design.md passages contradicted the v1.2
two-branch admission standard; design.md aligned, no PREREG rule
changed), following the round-4 wave (`audit-round-4.md`, findings
R4-B01..B02, R4-M01..M03) and the round-3 wave (`audit-round-3.md`,
findings R3-B01..B08, R3-M01..M03, R3-m01..m02).
All amendments are pre-call: no forecast call has been made, and every
amendment is logged in `artifacts/deviations.md`. Audit rounds 3–5
are archived in-repo (`audit-round-3.md` … `audit-round-5.md`).**
(R3-m01: the earlier "DRAFT … pending the freeze tag" status line was
stale at the v1 tag and is removed.)
Spec: `docs/labs-forecasts-2026-07-11/design.md` (v3, post-re-audit). This
document pins every value design.md v3 leaves open; where the two could be
read differently, design.md governs intent and this document governs
execution. Five execution findings were decided at the 2026-07-11
checkpoint; each is marked `[DECISION-<letter> — DECIDED 2026-07-11]`
inline. Everything else in this file is executable as written: an
implementer of Plans 2 and 3 needs no value that is not in this
document.

**Freeze rule:** this file is frozen by commit and tag
`labs-005-prereg-v1` (Task 7). Changes after the freeze tag require a
deviations-log entry in `artifacts/deviations.md` (date, section,
deviation, reason). No RUN forecast call happens before the freeze (the
design §6 pilot, whose outputs are discarded, is exempt and already
executed); the round-3 and round-4 audits of the frozen snapshot are the
gate. Analytic choices may
depend on the mechanically known final sample size, never on forecasts,
outcomes, or score patterns.

## Table of contents (the round-2 readiness list, item → section)

| # | Readiness item (audit-round-2.md) | Section |
|---|---|---|
| 1 | Immutable protocol, timestamp, deviations | Header, §0 |
| 2 | Event birth, multi-source eligibility, merge exclusions, horizons, sensitive exclusion, sampling/stopping | §1 |
| 3 | Event window versus latest deadline | §1.2 |
| 4 | Corpus membership, boundaries, order, clipping, sorter/cap, merges, hashes | §2 |
| 5 | Drafting model, cutoff, prompt, parameters, call count, deduplication, generation | §3 |
| 6 | Keep/edit/strike rubric and full decision log | §4 |
| 7 | Complete question template and resolution contingencies | §5 |
| 8 | Complete packet to forecasters | §5.3 |
| 9 | Contestant identities, provider, prompts, parameters, randomness, concurrency, timestamps | §6 |
| 10 | Retries, provider/parse failures, endpoints, rationale mismatch, denominators | §7 |
| 11 | Status-quo baseline | §7.1 (removed) |
| 12 | Crowd matching, odds, retrieval, thresholds, priority, missingness | §8 |
| 13 | Resolver blinding, second review, disagreements, VOID sensitivity | §9 |
| 14 | Primary estimand, snapshot, contrast, weighting | §10.1 |
| 15 | Brier/log formulas, orientation, bounds, ties | §10.2 |
| 16 | Murphy implementation, grouping, bias, uncertainty | §10.4 |
| 17 | Calibration bins, x-value, minimum n, interval method, bootstrap | §10.3 |
| 18 | Signed updating and no-new-article treatment | §10.5 |
| 19 | Aggregate/paired CIs, bootstrap seed/replicates, multiplicity | §10.6 |
| 20 | Class and crowd-subset claims | §10.7 |
| 21 | Tables, figures, filters, headline rules | §11 |
| 22 | Reproducibility bundle | §12 |

§13 (budget and execution channels) pins the pilot-measured cost figures
and the manual-channel conventions, which sit outside the 22 items.

## 0. Freeze mechanics (item 1)

- Protocol version: `005-run1-prereg-v1.3` (v1 frozen by commit at tag
  `labs-005-prereg-v1`, freeze timestamp = that tagged commit's committer
  date, UTC; v1.1 = the round-3 pre-call amendment wave, tag
  `labs-005-prereg-v1.1`; v1.2 = the round-4 pre-call amendment wave, tag
  `labs-005-prereg-v1.2`; v1.3 = the round-5 design.md alignment wave,
  tag `labs-005-prereg-v1.3`; every change logged in the deviations
  file).
- Deviations log: `docs/labs-forecasts-2026-07-11/artifacts/deviations.md`
  (created empty at the freeze; columns Date / Section / Deviation /
  Reason). Any post-tag change to this file, to
  `apps/pipeline/test/forecastEval/scoring.ts`, or to the predicates and
  prompts pinned here requires an entry.
- Order of operations after the freeze [amended per round-3 audit R3-M01,
  pre-call]: round-3 audit → manifest regeneration under §2.1 (mechanical,
  no new decisions) → **sensitive screen (§1.4), applied to ALL eligible
  events before any ranking, reviewers blind to rank** → run-corpus
  ranking (DECISION-E, top 45 of the screened set) → drafting (§3) →
  vetting (§4) → forecast calls (§6) → resolution (§9) → scoring (§10).
  The vetting rubric in §4 is frozen with this document, before any draft
  exists. The v1.1 manifest regeneration (2026-07-11, R3-M01) produces the
  canonical manifest; any later re-execution validates the frozen
  predicate fields (birth, earliestIngest-derived anomaly flag,
  birthDomains and birthArticleCount at birth+1h) only; ranking is
  computed on the canonical committed manifest (screen strikes re-rank
  offline via `eligibleEvents.ts --from`, never from a live prod query —
  see DECISION-E). Predicate mismatches require a deviations-log entry.

## 1. Event eligibility (item 2)

### 1.1 Mechanical predicates

An `events_all` event is **eligible** iff all of the following hold
(predicates verbatim from the plan's Global Constraints, evaluated by
`apps/pipeline/test/forecastEval/scripts/eligibleEvents.ts`):

- `lang = 'en'`.
- Birth window: `created_at >= '2026-06-01T00:00:00Z' AND created_at <
  '2026-06-21T00:00:00Z'` (birth := `events_all.created_at`, UTC).
- Multi-source: `birthDomains >= 2`, where `birthDomains` = count of
  distinct `pipeline_articles.domain` among associated articles with
  `created_at <=` the **birth snapshot instant** defined in §2.1
  (DECISION-A).
- Anomaly exclusion (R-04, mechanical, no discretion): excluded iff
  `min(article created_at) < birth - interval '48 hours'`.
- Not excluded by the sensitive-casualty rule (§1.4).

Sampling/stopping: no discretionary curation. All window events are
published in the complete eligible-and-excluded manifest with per-event
predicate values (`artifacts/event-manifest.json`); the events actually
run are the mechanical top-45 down-selection of the **screened** eligible
set per DECISION-E below, marked `runCorpus: true` in the manifest.
[amended per round-3 audit R3-M01, pre-call] Sensitive-screen exclusions
are recorded on manifest rows as `sensitive: true` (with the review log
per §1.4); the screen runs before ranking, so there is no backfill and
the former `struckReason`/`backfilledFor` fields are withdrawn.

> **[DECISION-A — DECIDED 2026-07-11: birth + 1 hour] Birth-snapshot
> grace window.** The at-birth-instant corpus filter
> (`pa.created_at <= birth`) returns 0 articles for ~98% of events: the
> event row is committed ~75 ms before its first article rows (Task 3
> finding; `birthDomains = 0` for 2789/2852 window events), so the
> predicate measured insertion order, not at-birth source diversity.
> **Decided:** birth snapshot instant := **event birth + 1 hour**
> (`pa.created_at <= birth + interval '1 hour'`), the pilot-validated
> value, pinned. The SAME instant is used for (a) the `birthDomains`
> eligibility predicate and (b) the birth drafting/forecasting corpus
> (§2.1). The midpoint snapshot is unaffected (§2.2 is computed from raw
> birth). `event-manifest.json` was regenerated with the frozen value at
> the checkpoint, BEFORE the freeze and before any drafting: events =
> 2852, eligible = 1667, anomaly-excluded = 18, single-source = 1167.
> The previously committed manifest (eligible = 20 under the broken
> at-birth predicate) is **superseded** and kept only as an audit
> artifact (git history). At eligible N = 1667 the manual paste count
> far exceeded the design §6 expectation; the run-corpus question is
> **resolved by DECISION-E** below (top-45 down-selection, decided
> 2026-07-11 at the checkpoint), which supersedes the
> `birthDomains >= 3` tightening option (1043 eligible) previously
> recorded here as the only permitted lever.

> **[DECISION-E — DECIDED 2026-07-11: run corpus = top 45 by birth
> diversity; RE-PINNED 2026-07-11 per round-3 audit R3-M01, pre-call]
> Corpus down-selection.** All 2852 window events stay in
> `event-manifest.json` with their predicate values. The sensitive screen
> (§1.4) is applied FIRST, to all eligible events, on birth-corpus
> material only, reviewers blind to rank; then, from the **screened**
> eligible events, the **RUN CORPUS = the top 45 ranked by `birthDomains`
> descending, ties broken by `birthArticleCount` descending, then `id`
> ascending (code-unit compare)**, where `birthArticleCount` = count of
> the event's articles with `created_at <= birth + interval '1 hour'`
> (the DECISION-A snapshot instant). [amended per round-4 audit R4-B01,
> pre-call: the v1.1 "outcome-blind by construction" claim is WITHDRAWN
> as an overclaim.] The ranking quantities filter on article INGEST
> TIMES, which are immutable; but event-to-article MEMBERSHIP is read
> from the present-day DB and is not provably the as-of-birth state (the
> §2 corpus limitation). The selection is therefore outcome-blind with
> respect to ingest timing only, conditional on present-day membership;
> this inherited limitation is disclosed in the estimand statement and
> the paper's limitations (§11).
> Present-day `articleCount` is REMOVED from the rule (R3-M01: it grows
> after birth and made the v1 tie-break outcome-aware); it remains in the
> manifest as a descriptive field only. Estimand limitation, restated
> [amended per round-4 audit R4-B01, pre-call]: the estimand population
> is "the June events Pollar covered most broadly at birth, minus
> sensitive-screened events", where "covered most broadly at birth" is
> measured on ingest-time-filtered, present-day membership; selection is
> outcome-blind with respect to ingest timing only, conditional on
> present-day membership (not provably the as-of-birth state), and the
> screen precedes ranking so screen decisions cannot be rank-aware.
> Selected
> rows carry `runCorpus: true` in the manifest, emitted by
> `eligibleEvents.ts` (frozen rule in the script); drafting (§3) and
> every downstream step read run-corpus events only. The ranking is
> computed on the canonical committed manifest; it is never re-derived
> from a live prod query. Screen exclusions are recorded by adding
> `sensitive: true` to the canonical manifest in a reviewed commit and
> re-ranking offline via `eligibleEvents.ts --from` (the script excludes
> `sensitive` rows before ranking). The v1 backfill rule is DELETED as no
> longer needed — the screen runs before selection, so the top 45 of the
> screened set needs no backfilling. The v1.1 manifest (regenerated
> 2026-07-11 with `birthArticleCount`) is the new canonical; the v1
> top-45 is superseded pre-call (3 of 45 boundary events changed; git
> history retains the v1 manifest as an audit artifact).
> Resulting arithmetic: 45 events → 45 drafting calls yielding 90 draft
> questions (2 per event), ~90 event × snapshot corpora, and 90 Fable 5
> console pastes (45 events × 2 snapshots × 1 console model); the
> harness budget returns to the §13 extrapolation, $2–7 (R3-m02
> recompute). [SIGNED OFF by Jakub, 2026-07-11]

### 1.2 Horizons and closure (item 3)

- Question horizons: deadline in `[birth + 7 days, birth + 30 days]` AND
  deadline `<= 2026-07-10T23:59:00Z`. A June 20 event can carry only
  7–20-day horizons; the estimand explicitly covers this truncated
  population (R-06), the birth-date × horizon distribution is published,
  and horizon bands 7–13 / 14–20 / 21–30 days are a preregistered
  descriptive stratification.
- Closure (R-07): a question is eligible only if its deadline AND every
  correction/grace window its template defines expire strictly before
  **2026-07-13T00:00:00Z**. The resolution pass (§9) begins no earlier
  than that instant; the actual pass date is recorded in the resolution
  log. "Closed by construction," not "resolvable today."

### 1.3 Data-quality note (no decision)

Some `events_all.lang = 'en'` rows carry Polish titles (pipeline
data-quality artifact). Drafting eligibility is unaffected — all
currently-eligible titles are English — but this is recorded here as a
known corpus impurity; if a regenerated manifest admits an event with a
non-English title, it stays eligible (the predicate is `lang='en'`, not
title language) and the fact is noted in the manifest's review log.

### 1.4 Sensitive-casualty exclusion (pre-drafting eligibility rule)

Predicate: **an event is ineligible if its birth-snapshot articles report
deaths or injuries from an ongoing violent act or disaster as the event's
primary subject.** Applied mechanically at manifest time by a title/lead
keyword screen plus dual human review of every exclusion; excluded events
are listed in the manifest with `sensitive: true`. [amended per round-3
audit R3-M01, pre-call] The screen runs BEFORE run-corpus ranking, on all
eligible events, using birth-corpus material only (title plus first 500
characters of each birth-snapshot article), with reviewers blind to rank;
DECISION-E then selects the top 45 of the screened set. There is no
backfill rule.

Mechanics (pinned):

- Screen input: each birth-snapshot article's title plus the first 500
  characters of content, case-insensitive.
- Keyword list (a hit flags the event for review; it does not by itself
  exclude): `killed, kill, dead, death, died, dies, fatal, casualt,
  injur, wounded, massacre, shooting, stabbing, bombing, blast,
  airstrike, earthquake, flood, wildfire, hurricane, landslide, famine,
  crash`.
- Review: both reviewers (Jakub + the executing agent) apply the predicate
  sentence above to every flagged event; exclusion requires agreement that
  casualties from an ongoing violent act or disaster are the event's
  primary subject. Flagged-but-kept events are logged too, so the screen
  is auditable in both directions. Disagreements are published.

## 2. Corpus rule (item 4)

### 2.1 Snapshot definition

For a given event and snapshot instant `X`:

- Membership: articles now associated with the event
  (`event_articles` join, `ea.event_id::text = e.id`), filtered by
  `pipeline_articles.created_at <= X` (inclusive). Honest definition per
  design §1 (M-03): membership is read from today's DB and is NOT provably
  the as-of pipeline state; published as "articles now associated with the
  event, filtered by ingest time."
- Ordering and cap: order by `created_at` ascending; keep **the last 8**
  (most recent) — the production sorter cap.
- Serialization: production-style, ascending `created_at` among the kept
  articles, indices from 0:
  `[Article i] Source: <source display name> | Published: <ISO timestamp>`
  then title then content clipped to **2,500 characters**. The article
  line uses the source DISPLAY NAME (`pipeline_articles.source`), matching
  the production writer serialization. The wrapUntrusted wrapper IS
  REQUIRED in all run call files and harness prompts (per design §1). The
  pilot call files predate this pin and lack the wrapper; they are pilot
  artifacts, not the reference format. The reference format is this
  section.
- Prompt date: `Today is <YYYY-MM-DD>` where the date renders the snapshot
  instant in Europe/Warsaw (006 convention).
- Corpus manifest: per question × snapshot, the article ids, timestamps,
  and a **sha256 of each article's clipped content**, shipped in the
  bundle.

Snapshot instants:

- **Birth snapshot:** `X = birth + 1 hour` per DECISION-A (§1.1).
- **Midpoint snapshot (§2.2).**

### 2.2 Midpoint instant

Pinned here (design.md v3 leaves per-question vs per-event midpoint
ambiguous while requiring per-event call bundling): the midpoint is
**event-level**, `X = floor_to_hour_utc(birth + (Dmin − birth)/2)` where
`Dmin` is the **earliest** `deadlineUtc` among the event's kept (post-
vetting) questions. Rationale: guarantees the midpoint snapshot precedes
every deadline of the bundle and preserves one call per event × snapshot.
The grace window of DECISION-A does not shift this computation (raw birth
is used).

### 2.3 No-new-articles stratum

A question × midpoint belongs to the "no new articles" stratum iff the
midpoint corpus manifest's article-id set equals the birth corpus
manifest's set (mechanical, from the manifests).

## 3. Drafter (item 5)

- Model: `google/gemini-3.5-flash` (OpenRouter, harness channel); cutoff
  documented January 2025, OpenRouter listed 2026-05-19
  (`artifacts/contamination-evidence.md`); the question set is labeled
  outcome-exposed regardless.
- Parameters: temperature 0.2, max_tokens 2000, response_format
  `json_object`. One call per RUN-CORPUS event (DECISION-E; 45 events),
  reading that event's birth snapshot (§2.1) only.
- Output contract: **exactly 2** binary questions per event (R-05). A
  response that is not valid JSON, misses a template field, or contains a
  number of questions other than 2 is a **generation-failure
  (shortfall)**, and generation-failure is **ATOMIC** [amended per
  round-3 audit R3-B01, pre-call]: one retry; if the retry is also a
  generation-failure, the event yields **ZERO drafts** — no per-question
  salvage from either attempt — and the 2-draft shortfall is counted in
  the question-flow diagram. (Distinct from the §4 strike reason
  `malformed`, which applies only at vetting.)
- Near-duplicate rule: over each event's 2 drafts, tokenize the `text`
  field (lowercase; split on any non-alphanumeric run; token **sets**);
  if Jaccard similarity > 0.6, keep the first draft, log the second as
  struck with reason `duplicate` at drafting time (counted as shortfall).
- Question ids: `q-<first 8 hex chars of event id>-<1|2>` in draft order
  (e.g. `q-d3142989-1`).
- Drafter prompt (system message; [amended pre-call per the wave-1
  vetting outcome, deviations row 22 — supersedes the checkpoint-FINAL
  wording, which omitted the §5.1 field constraints; every wave-1 draft
  consequently failed KEEP criterion (a) and the full wave is published
  as struck]):

> You draft forecasting questions for a research benchmark. From the
> articles below (as of {DATE}), draft exactly 2 binary questions about
> how this story develops, resolvable by public sources between
> {MIN_DEADLINE} and {MAX_DEADLINE}. Each must use the template fields:
> text, yesCondition, noCondition, primarySource, fallbackSource,
> deadlineUtc, announcementRule (announcement vs occurrence), graceRule,
> voidConditions (exhaustive), classTag (one of: deal-closes,
> leadership-change, policy-decision, indicator-threshold,
> competition-outcome, record-stands, event-recurs, legal-ruling).
> primarySource and fallbackSource must each be a specific URL plus a
> one-line retrieval rule: what to read on that page and how it decides
> YES or NO. graceRule must state its expiry as an ISO-8601 UTC instant;
> if there is no grace window, state the deadline instant. Questions
> must be answerable YES or NO with no judgment calls, about the
> story's future, not restatements of reported facts. Output JSON:
> {questions: [...]}.

- Mechanical §5.1-constraint check at draft time [added pre-call,
  deviations row 22]: a draft whose `primarySource` or `fallbackSource`
  is a bare URL (no retrieval-rule prose) or whose `graceRule` contains
  no ISO-8601 instant is a **generation-failure**, subject to the same
  atomic retry rule; vetting criterion (a)/(c) review is unchanged on
  top of it.

- Placeholders: `{DATE}` = birth snapshot date (Europe/Warsaw rendering);
  `{MIN_DEADLINE}` = `birth + 7 days`; `{MAX_DEADLINE}` =
  `min(birth + 30 days, 2026-07-10T23:59:00Z)`, both ISO 8601 UTC.

## 4. Vetting rubric (item 6) — the load-bearing instrument

Frozen with this document, before any draft exists (B-02). [wording
FINAL, checkpoint 2026-07-11]; after the freeze tag it is immutable.

- **KEEP** iff all of:
  - (a) resolution decidable from the primary/fallback source **as the
    drafter named it** [amended per round-3 audit R3-B02, pre-call]: a
    draft whose named source cannot resolve the question is STRUCK
    `ambiguous-resolution` — vetters never substitute or sharpen a
    source;
  - (b) threshold/comparison fully numeric or categorical with named
    entities;
  - (c) deadline explicit UTC, within the horizon rule (§1.2), and every
    grace/correction window expires before 2026-07-13T00:00:00Z;
  - (d) YES and NO conditions exhaustive and mutually exclusive;
  - (e) not sensitive per §1.4;
  - (f) not already decided in the birth corpus — checked against the
    birth snapshot only; the vetter may not consult any post-birth source
    while vetting.
- **TIGHTEN** (allowed edits only) [amended per round-3 audit R3-B02,
  pre-call: "naming a more specific source" is REMOVED — source
  tightening was an outcome-aware discretionary channel]: adding
  timezone/units; replacing a vague entity reference with the exact name
  already present in the birth corpus. Nothing else. Never: changing the
  source, threshold value, direction, deadline, or subject. Every edit is
  a published diff. The `classTag` is never edited (§5.2).
- **STRIKE** (enumerated reasons only): `ambiguous-resolution` /
  `non-binary` / `sensitive` / `duplicate` / `already-decided-at-birth` /
  `malformed`. Reason logged per strike. Criterion-to-reason mapping:
  failing (a) or (d) → `ambiguous-resolution`; failing (b) →
  `non-binary`; failing (c) → `malformed`; failing (e) → `sensitive`;
  failing (f) → `already-decided-at-birth`. When multiple KEEP criteria
  fail, the recorded reason is the first failing criterion in (a)–(f)
  order.
- **Deterministic inclusion:** every draft that passes the rubric enters
  the question set; no stopping at a target count.
- **Order of work:** rubric committed (this freeze) → drafts generated →
  vetting in **one sitting**; drafts are first sorted by question id
  (code-unit ascending), then shuffled by Fisher–Yates driven by
  `mulberry32(20260711)` (iterate i = n−1..1, j = floor(rng()·(i+1)),
  swap); all decisions logged before any forecast call. The vetting log
  (every original draft, every edit diff, every strike reason) is a
  bundle artifact.

## 5. Question template and packet (items 7–8)

### 5.1 Template JSON schema

Every kept question is exactly this object (all fields required):

```json
{
  "id": "q-<8 hex>-<1|2>",
  "eventId": "<events_all.id>",
  "text": "<binary question>",
  "yesCondition": "<YES condition — exhaustive conditional on no VOID>",
  "noCondition": "<NO condition — exhaustive conditional on no VOID>",
  "primarySource": "<named, URL-addressable page or endpoint + one-line retrieval rule>",
  "fallbackSource": "<named, URL-addressable page or endpoint + one-line retrieval rule>",
  "deadlineUtc": "<ISO 8601 UTC>",
  "announcementRule": "announcement | occurrence",
  "graceRule": "<correction/grace window; MUST state an ISO-8601 expiry instant>",
  "voidConditions": ["<subset of the frozen V1/V2/V3 taxonomy below>"],
  "classTag": "<one codebook value>"
}
```

Resolution contingencies (item 7) [amended per round-3 audit R3-B03,
pre-call]: YES/NO/VOID only per this template. The YES and NO conditions
are exhaustive **conditional on no VOID condition holding** — jointly
they must cover every non-VOID state of the world, and VOID may be
declared on no other ground (§9). [amended per round-4 audit R4-M01,
pre-call] Every VOID condition is an observable check; V3 in particular
is a narrowed source-publication check on the two named sources, not a
discretionary indeterminacy catch-all, so conditional exhaustiveness
cannot be defeated by absorbing difficult cases into V3. The VOID
taxonomy is frozen to exactly
three conditions; each question's `voidConditions` instantiate one or
more of them, concretely, and nothing outside them:

- **V1** — the resolution source (primary and fallback both) is
  unavailable or discontinued at the resolution pass date.
- **V2** — the question premise dissolved: a presupposed entity or
  process ceased to exist before the deadline.
- **V3** [narrowed per round-4 audit R4-M01, pre-call] — neither the
  named primary source nor the named fallback source has published the
  specific datum the resolution criterion names, by the resolution pass
  date (checked and screenshot/URL-logged for both sources).

Field constraints (R3-B03): `primarySource` and `fallbackSource` must
each be a **named, URL-addressable page or endpoint plus a one-line
retrieval rule** (what to read there, and how); `graceRule` must state an
**ISO-8601 expiry instant**. Drafts violating these constraints fail
KEEP criterion (a) or (c) at vetting.

### 5.2 Class codebook (m-01; descriptive-only in run 1)

Mutually exclusive; assigned by the drafter; vetters never change it (a
plainly wrong tag stays and is noted in the vetting log — tags carry no
analytic weight in run 1). If more than one definition could apply, the
first matching in this order governs:

1. `legal-ruling` — a named court or tribunal issues a decision in a named case.
2. `leadership-change` — a named person gains or leaves a named office or role.
3. `deal-closes` — a named transaction or agreement is signed, completed, or closed.
4. `policy-decision` — a government or institution formally adopts, rejects, or enacts a named measure.
5. `indicator-threshold` — a published numeric indicator crosses a stated threshold.
6. `competition-outcome` — a named competitor wins, loses, or advances in a named contest.
7. `record-stands` — a stated record or extreme remains unbroken through the deadline.
8. `event-recurs` — a named type of occurrence happens again within the window.

### 5.3 Packet to forecasters (item 8)

Forecasters receive the complete frozen packet **verbatim** — the full
template JSON of every question in the bundle, not bare question text —
followed by the snapshot corpus (§2.1 serialization). No forecaster is
scored against resolution detail it never saw. Message layout is the
pilot call-file format: parameter header, `## SYSTEM` (the §6 prompt),
`## USER` = `Questions:` block (template JSON array, ascending question
id) then `Articles:` block.

## 6. Forecaster prompt and run identities (item 9)

Forecaster system prompt (identical for every arm; [wording FINAL,
checkpoint 2026-07-11]; {SNAPSHOT DATE} rendered per §2.1):

> You are a careful probabilistic forecaster. Today is {SNAPSHOT DATE}.
> Using only the articles below and general knowledge from before today,
> estimate the probability that each question resolves YES by its
> deadline. You cannot browse. Output JSON: {"forecasts": [{"id": "...",
> "probability": <0-1, two decimals>, "rationale": "<max 2 sentences>"}]}.

Arms table (contamination verdicts verbatim from
`artifacts/contamination-evidence.md`):

| Arm | Model ID | Channel | Family | temperature | max_tokens | response_format |
|---|---|---|---|---|---|---|
| Claude Fable 5 | `anthropic/claude-fable-5` | manual (console) | primary | 0.2 | 2000 | json_object |
| production writer | internal; **PINNED** [R3-B04, pre-call]: the `WRITER_MODEL` constant in `apps/pipeline/src` (`agenticSummarization.ts`) at the repo commit of tag `labs-005-prereg-v1.1`, recorded verbatim (with routing suffix and provider policy) in the contamination dossier's NOT-FOR-PUBLICATION section; never in published artifacts | harness (OpenRouter) | primary (stable-alias release-date evidence, indirect but strong, per the dossier; vendor cutoff NOT DOCUMENTED; alias-to-weights immutability ASSUMED, not verifiable — R4-M02) | 0.2 | 2000 | json_object |
| Kimi K2.6 | `moonshotai/kimi-k2.6` | harness (OpenRouter) | descriptive (tier ladder), screened | 0.2 | 8000 — see DECISION-C | json_object |
| GLM-4.6 | `z-ai/glm-4.6` | harness (OpenRouter) | descriptive (tier ladder), screened | 0.2 | 2000 | json_object |
| 0.5 reference | none (computed) | none | uninformative reference | — | — | — |

- **Production-arm identity assertion (Plan-2 implementation
  requirement; R3-B04, pre-call):** the harness MUST assert at startup
  that its runtime-resolved production-writer model id **string-equals**
  the pinned `WRITER_MODEL` constant recorded in the dossier's
  NOT-FOR-PUBLICATION section, and abort otherwise. No environment
  override (`PROD_WRITER_MODEL` or any other) may substitute a different
  id after the freeze. Public text stays redacted. [clarified per
  round-4 audit R4-M02, pre-call] The assertion establishes which ALIAS
  was requested; it cannot verify that the provider-served weights
  behind that alias remained unchanged — alias-to-weights immutability
  is a disclosed assumption (§10.1, §11). Routing note: the `:floor`
  suffix permits provider routing variance within the pinned provider
  policy; disclosed.
- **Bundling:** all of an event × snapshot's questions in ONE call
  (they share the corpus), question order = ascending question id, in
  every channel, so the harness bundles identically to the console.
- **Randomness:** the only protocol randomness is `mulberry32(20260711)`
  (vetting shuffle §4, bootstrap §10.6). `Date.now()`/`Math.random()` are
  banned from analysis code. Model-side sampling at temperature 0.2 is
  the arms' own stochasticity and is not seeded.
- **Concurrency and timestamps:** harness calls run sequentially (one
  request in flight); every request and attempt is logged with its
  timestamp in the harness ledger. Console runs are timestamped via the
  saved-output records in the manual ledger (§13).
- **Retry/attempt rule:** harness: initial attempt plus up to 2 retries
  (3 requests max per call). Manual: one attempt; on parse failure one
  retry (2 pastes max); both saved; first parseable attempt scores; all
  attempts logged; copy-repairs logged, never silent (006 lesson).
- The 0.5 reference arm makes no calls: every question is scored at
  p = 0.5 analytically.

> **[DECISION-B — DECIDED 2026-07-11: Sol removed from run 1 entirely]**
> GPT-5.6 Sol is not a contestant in run 1 — not a primary-family arm,
> not a sensitivity arm. Reasoning: the undocumented ~5-month
> post-training window between Sol's documented knowledge cutoff
> (Feb 16, 2026) and its release (2026-07-09) fails the spirit of the
> contamination screen, and removal was chosen over a
> contamination-sensitivity arm. The manual channel is therefore
> Fable 5 only; the primary contrast — Fable 5 minus the production
> writer (§10.1) — is unchanged.

> **[DECISION-C — DECIDED 2026-07-11] Kimi K2.6 max_tokens.** In the
> pilot, kimi-k2.6 consumed all 2000 max_tokens on reasoning and returned
> empty content (HTTP 200, billed, unusable); the retry rule cannot fix a
> deterministic cap overrun. **Decided:** a per-arm
> max_tokens table — `moonshotai/kimi-k2.6` gets **8000**; every other
> arm keeps 2000; all other parameters identical across arms (as in the
> table above). The asymmetry is disclosed in the paper's methods table.

## 7. Failure and gate rules (item 10)

Verbatim from design §3:

- **Numeric treatment of failed calls (R-03):** the primary paired
  contrast is complete-case — a question where either arm lacks a
  parseable forecast drops from that pair, with the count published;
  per-writer **failure rate is a first-class reported metric**; a
  preregistered sensitivity re-scores failed calls at 0.5. Failed calls
  stay visible in the ledger.
- **Provider errors and duplicate requests are treated identically to
  parse failures.**
- **The coherence gate is mechanical only** — parseable, in [0, 1];
  rationale/number consistency is reported descriptively, never used to
  exclude a valid probability.

Pinned refinements:

- Parse rule per question: a question's forecast is valid iff the
  response is parseable JSON and contains an entry with that question's
  id and a numeric probability in [0, 1]. A parseable response missing
  some of the bundle's questions is a failed call **for the missing
  questions only**. "Two decimals" and "max 2 sentences" are
  instructions, not gates.
- Malformed-id rules [amended per round-3 audit R3-B05, pre-call]:
  - **Duplicate ids:** a response containing the same question id more
    than once (whatever the probabilities) makes that question a FAILED
    forecast for that arm — no first-entry or agreement salvage.
  - **Unknown ids:** entries whose id is not in the packet are ignored
    and logged in the harness ledger.
  - **Plan-2 gate:** both rules must be covered by harness unit tests
    before any forecast call.
- Denominators: failure rate per arm = failed question × snapshot calls /
  total question × snapshot calls assigned to that arm; published per arm
  and per snapshot.

### 7.1 Status-quo baseline (item 11)

Removed (pinned as removed, design M-07). The constant arm is an
**uninformative 0.5 reference**, not an empirical baseline; run 1 has no
outcome-blind empirical baseline and the paper says so. The sample base
rate appears on figures as a descriptive reference line labeled as
computed from outcomes.

## 8. Crowd anchors (item 12) — matched case studies, not a benchmark

- **Matching:** same subject + same threshold + deadline within ±24h,
  human-confirmed; near-miss matches discarded, never approximated; every
  match decision logged. Automated matcher: Adjacent News semantic search
  (docs.adj.news), fallback Gamma text search.
- **Venue priority:** Polymarket > Metaculus > Kalshi > Manifold; the
  highest-priority venue with a qualifying match is used, one anchor per
  question.
- **Thresholds:** Polymarket lifetime volume ≥ $10,000; Metaculus ≥ 20
  forecasters; Kalshi volume ≥ $10,000; Manifold always labeled
  play-money.
- **Odds field:** Polymarket = last `prices-history` point ≤ snapshot
  instant (fidelity 60), YES token; Metaculus = community median at the
  snapshot instant; Kalshi = close of the last hourly candlestick ending
  ≤ snapshot instant; Manifold = `probAfter` of the last bet at or before
  the snapshot instant (reconstructed from `/v0/bets`).
- **Missing data = discard, logged** (no interpolation, no nearest-later
  point).
- **Retrieval:** anchors are retrieved after the freeze during the
  resolution/analysis phase; each record logs its retrieval timestamp.
  Record schema: venue · matched ID · match note · snapshot timestamp
  UTC · value · price basis (last/mid/community median).

## 9. Resolution (item 13)

[amended per round-4 audit R4-B02, pre-call: the second reviewer is no
longer Jakub, who is forecast-exposed as the manual-console operator
(§13) and could previously create score-excluding VOIDs through
disagreement. The review structure below is between two forecast-blind
reviewers.]

- Resolver: Claude, **forecast-blind**: the resolution pass completes
  before any scoring ingestion — the resolver never receives any
  forecast, ledger entry, or arm output.
- YES/NO/VOID strictly per the question's own template; VOID only on its
  pre-listed `voidConditions`.
- Second reviewer: a **fresh Claude instance**, spawned with ONLY the
  question packet (§5.3 template JSON) and the named resolution sources
  (primary and fallback exactly as the question names them). It never
  receives any forecast, ledger entry, or arm output — **blind by
  construction**. Scope of second review: every VOID, every exclusion of
  any kind, and every close call. **"Close call"** = the fallback source
  was used, the grace rule was invoked, or either reviewer was initially
  uncertain.
- Jakub's role is reduced to **process disputes** (channel and logistics
  problems, e.g. a source page failing to load or a missing log file)
  that never touch YES/NO/VOID determinations.
- Disagreement rule [amended per round-3 audit R3-B06, pre-call;
  reviewer identities re-pinned per round-4 audit R4-B02]: resolver and
  second reviewer attempt **one documented reconciliation**; if
  disagreement persists, the final status is **VOID** (the conservative
  disposition), logged with both positions — now between two
  forecast-blind reviewers, so persistent disagreement cannot be
  forecast-informed attrition. Every disagreement — reconciled or not —
  is published.
- Ordering gate (mechanical, stated): the **complete resolution log is
  sha256-hashed and committed BEFORE any scoring executes**; scoring
  reads only the committed, hashed log.
- Resolution pass date: **2026-07-13 or later** (§1.2 closure guarantees
  every question and grace window is expired by then); actual date in the
  resolution log.
- VOIDs are excluded from scores, counted publicly, and bounded per
  §10.6's stress bound.
- Disclosed limitation (also in §11's paper-limitations list): both
  reviewers are model instances of the same family; their independence
  is architectural (context isolation), not institutional; the published
  resolution log lets any reader re-adjudicate every determination.

## 10. Estimands and statistics (items 14–20)

Scoring library: **`apps/pipeline/test/forecastEval/scoring.ts` at the
`labs-005-prereg-v1.1` tag revision (v1 lacked binOutcomeCIs; change
logged in the deviations log) is the pinned analysis code.**
Its unit tests (`apps/pipeline/test/unit/forecastScoring.test.ts`) are
part of the pinned revision. Edits after the tag require a deviations-log
entry.

### 10.1 Primary estimand and contrast (item 14)

- Primary estimand: **question-weighted mean Brier score at the birth
  snapshot** (lower is better). Event-weighted means reported alongside.
- Primary contrast (R-02, exactly one): the paired per-question Brier
  difference **Claude Fable 5 minus the production writer** (negative
  favors Fable), complete-case (§7), with event-clustered bootstrap 95%
  percentile interval (§10.6).
- Preregistered fallback: if the production writer's contamination
  evidence had failed (it did not — release-date evidence, **indirect
  but strong**, see dossier [wording amended per round-3 audit R3-M02,
  pre-call: a release date is not proof of non-exposure]), the primary
  contrast would be Fable vs the 0.5 reference and every
  writer-vs-writer comparison demoted to the sensitivity arm. Eligible
  contestants are named in §6. Reconciliation (Task 6 finding): the
  production writer enters the primary family on the **release-date
  branch** of the admission standard [restated per round-4 audit R4-M02,
  pre-call; this supersedes the v1.1 "verified immutable release"
  wording, which overclaimed]: **documented pre-2026-06-01 training
  cutoff OR pre-2026-06-01 release of a stable model alias;
  alias-to-weights immutability is an ASSUMPTION the provider does not
  let us verify, disclosed as a residual contamination channel for the
  production arm** (§11 paper-limitations list). The design §4 fallback
  therefore does not fire: the primary contrast is RETAINED under the
  weakened, disclosed standard. The R3-B04 identity pin (§6) enforces at
  run time that the requested ALIAS string never changes; it cannot
  verify the weights served behind that alias. Routing note: the
  `:floor` suffix permits provider routing variance within the pinned
  provider policy; disclosed.
- Everything else — midpoint scores, Murphy components, calibration bins,
  class splits, tier ladder, crowd case studies — is labeled exploratory.

### 10.2 Formulas (item 15)

- Brier: `(p − y)²`, y ∈ {0, 1}, standard orientation, lower is better.
- Log score: `−[y·ln(clip(p)) + (1−y)·ln(1−clip(p))]`, with
  `clip(p) = min(0.99, max(0.01, p))` (ε = 0.01); secondary metric;
  unclipped endpoint forecasts (p ∈ {0, 1}) reported separately.
- Ties/determinism: forecasts are sorted by p with ties broken by
  question id in code-unit order (locale-independent), as implemented.

### 10.3 Reliability diagram bins (item 17)

Equal-count bins per writer over that writer's birth-snapshot forecasts,
k = 5, minimum bin size 5, as **implemented in the frozen
`equalCountBins`**:

> **[DECISION-D — DECIDED 2026-07-11: ratified] Bin rule wording.** design.md
> v3's "a bin under 5 questions merges with its adjacent bin" is
> mathematically unsatisfiable for equal-count bins (Task 2 finding: with
> n = 10, k = 5, minBin = 5, no sequence of whole-bin merges can produce
> bins that are both ≥ 5 and more than one in number). **Decided
> (ratified; what the frozen library implements):** re-split instead of
> merge — sort forecasts by p (ties by question id, code-unit order) and
> split into `k' = max(1, min(k, floor(n / minBin)))` equal-count bins,
> so every bin has ≥ minBin members whenever n ≥ minBin, single bin
> otherwise. PREREG states this implemented rule as binding; design.md §4
> carries a matching one-line wording amendment flagged "[amended after
> Task 2 finding, pre-freeze]".

- x = per-bin mean forecast; per-bin n printed; title "Reliability
  diagram, run 1 (descriptive)". No writer is called "calibrated."
- Per-bin CI [amended per round-3 audit R3-B07, pre-call]: event-cluster
  percentile bootstrap (seed/replicates per §10.6) of the **per-bin mean
  OUTCOME**, with bin **membership fixed at the point estimate** — bins
  are computed once on the full sample and are NOT re-derived per
  replicate. Stated simplification: re-binning variability is not
  captured. Implemented as `binOutcomeCIs` in the pinned scoring library;
  the function and its unit tests must be in `scoring.ts` before any
  forecast call (Plan-2 gate; landed with the v1.1 amendment wave — the
  scoring.ts edit is itself a logged deviation).

### 10.4 Murphy decomposition (item 16)

Standard binned estimator, reliability − resolution + uncertainty,
computed on the same equal-count grouping as §10.3 (the frozen `murphy`
implementation). [amended per round-3 audit R3-B07, pre-call] Murphy
components are reported as **POINT diagnostics only — no confidence
intervals** (the earlier bootstrap-interval promise is withdrawn: no
component-bootstrap implementation was frozen, and at this n the
components are unstable); labeled an unstable exploratory diagnostic.
Low empirical resolution at this n is not evidence of a behavioral
trait.

### 10.5 Updating (item 18)

Primary update metric = signed paired change in Brier loss, birth →
midpoint (negative = improvement), event-cluster intervals, separate
stratum for questions whose midpoint corpus gained no new articles
(§2.3). [amended per round-3 audit R3-B07, pre-call] The analysis is
**complete-case on questions with a parseable forecast at BOTH
snapshots**; questions failing at either snapshot drop from the updating
analysis, with the count published; the **0.5-imputation sensitivity**
(failed snapshot forecasts scored at p = 0.5) is reported separately.
Framed as "midpoint score change," not a causal effect of evidence.

### 10.6 Uncertainty, seed, multiplicity, VOID bound (item 19)

- Event-clustered percentile bootstrap: resample events with replacement,
  clusters intact; **seed 20260711; 10,000 replicates; 95% percentile
  intervals** (`eventClusterBootstrap` in the frozen library; PRNG
  `mulberry32`).
- Multiplicity: none claimed — no confirmatory family beyond the single
  primary contrast exists.
- VOID sensitivity bound (R-08) [amended per round-3 audit R3-B06,
  pre-call]: for each declared contrast, the exact minimum and maximum
  over all **common** binary assignments to VOID questions (same assigned
  outcome for every writer; the contrast is additive over questions, so
  per-question extremes give the exact bound). The bound is computed
  **complete-case**: only over pairs where BOTH arms have parseable
  forecasts (for resolved pairs and for the VOID questions entering the
  bound); denominator = complete-case resolved pairs + complete-case
  VOIDs, stated. The **0.5-imputation variant** (unparseable forecasts
  scored at p = 0.5) is computed and reported separately; both numbers
  appear together. Labeled a stress bound where VOID has no coherent
  binary truth (`voidBound` in the frozen library).

### 10.7 Class and crowd-subset claims (item 20)

Pinned: exploratory only. Class tags are descriptive; crowd anchors are
matched case studies; no ranking, calibration, or superiority claim is
made from either.

## 11. Output set (item 21) — frozen

[amended per round-3 audit R3-B08, pre-call: the five outputs promised
elsewhere in this protocol are added below, each with its location, so
the output set is complete.]

- **Headline line (above Table 1):** the primary paired-contrast
  estimate (question-weighted mean per-question Brier difference, Fable 5
  minus production writer, per §10.1) with its event-clustered bootstrap
  95% CI.
- **Table 1:** arm × {mean Brier (question- and event-weighted), 95% CI,
  log score, failure rate, n}.
- **Fig 1:** reliability diagram per primary-family arm.
- **Fig 2:** tier ladder (all arms + 0.5 reference).
- **Fig 3:** birth → midpoint paired Brier change with the
  no-new-articles stratum.
- **Table 2:** crowd-anchor case studies.
- **Ledger** (per design.md §5): browsable question ledger, filterable by
  writer/class/outcome; every VOID, failed call, and struck draft remains
  a visible row (never hidden); each row shows both snapshots, the
  resolution with source links, and expandable rationales.
- **VOID bound line under Table 1** (both the complete-case bound and
  the 0.5-imputation variant, per §10.6).
- **Murphy point-components table (paper appendix):** per
  primary-family arm, reliability / resolution / uncertainty as point
  values only (§10.4), labeled unstable exploratory.
- **Birth-date × horizon-band distribution table (paper methods
  appendix):** kept questions cross-tabulated by event birth date and
  horizon band (7–13 / 14–20 / 21–30 days), per §1.2.
- **Question-flow diagram (paper methods; also linked from the
  ledger):** drafted → struck-by-reason → kept → resolved/VOID,
  including generation-failure shortfalls (§3, atomic per R3-B01) and
  sensitive-screen strikes (§1.4).
- **Sensitivity block (paper appendix, under the headline result):**
  VOID bounds (§10.6), the 0.5-imputation re-scoring of failed calls
  (§7) and of failed updating snapshots (§10.5), and the count and list
  of unclipped endpoint forecasts (p ∈ {0, 1}, §10.2).
- **Paper-limitations list (paper limitations section; frozen minimum
  set) [added per round-4 audit R4-B01/R4-B02/R4-M02, pre-call]:**
  (i) retrospective backtest with outcome-aware question construction —
  residual hindsight bias cannot be eliminated, only stated and logged;
  (ii) [R4-B01] run-corpus selection is outcome-blind with respect to
  ingest timing only, conditional on present-day event-to-article
  membership, which is not provably the as-of-birth state (the §2
  corpus limitation, inherited by the ranking quantities);
  (iii) [R4-B02] resolver and second reviewer are model instances of
  the same family; their independence is architectural (context
  isolation), not institutional; the published resolution log lets any
  reader re-adjudicate every determination;
  (iv) [R4-M02] the production arm enters the primary family on
  stable-alias release-date evidence; alias-to-weights immutability is
  an assumption the provider does not let us verify — a residual
  contamination channel — and the `:floor` suffix additionally permits
  provider routing variance within the pinned provider policy;
  (v) ~50 clustered questions from 45 events; backtest ≠ forward
  record;
  (vi) [added per deviations row 26, post-forecast] the manual channel's
  model-identity and settings verification (generation metadata, console
  timestamps, settings screenshot — the R3-M03/R4-M03 controls) was
  waived by operator decision for run 1; the Fable console arm's
  identity rests on operator attestation, the pre-call sha256-committed
  call-file headers, and output-form consistency, not on independent
  metadata.
- **Headline rule:** the paper's headline states the primary contrast
  result and nothing stronger; every other number appears only with its
  exploratory label. Language rule: "descriptive scores," never
  "rankings."

## 12. Reproducibility bundle (item 22)

Verbatim from design §5: PREREG.md snapshot + deviations log · complete
eligible-and-excluded event manifest with predicate values · questions +
full template fields · vetting log (all drafts, diffs, decisions) ·
resolution log with second-review outcomes · raw attempts and forecasts
with rationales and request timestamps (harness-logged; console runs
timestamped via saved-output records in the manual ledger) · corpus
manifests with content hashes · exact prompts, model IDs, request
parameters · scoring configuration + analysis code revision ·
crowd-anchor records · cost ledger extract. The production model remains
unnamed publicly; the bundle states plainly that its arm is therefore not
independently reproducible and documents its cutoff evidence to the
extent possible (the dossier records: vendor cutoff NOT DOCUMENTED;
qualifies via pre-June release of a stable model alias, indirect but
strong evidence; alias-to-weights immutability assumed, not verifiable,
disclosed — R3-M02/R4-M02 wording). The contamination dossier
ships in the public bundle with its NOT-FOR-PUBLICATION section removed;
the public rows cite evidence type and date without the withheld vendor
URL.

## 13. Budget and execution channels (pins from execution)

- **Budget:** $15–30 (design §6) stands. Pilot (2026-07-11, tag
  `005-pilot`, one event, 4 harness calls) measured $0.02019 total;
  extrapolated harness spend for the full run ≈ **$1.57 raw** (315
  calls: 270 forecast calls across the three harness arms + ~45 drafting
  calls; [recomputed per round-3 audit R3-m02, pre-call] the earlier
  $2.08 figure included 90 phantom "drafter-forecast" calls that do not
  exist — the drafter drafts, it does not forecast), **$2–7 with
  pessimistic margins** (8-article packets ≈ 2.5× pilot prompt, kimi 2×
  completion budget, retry allowance) — inside budget at the DECISION-E
  run-corpus N = 45, which matches the extrapolation's own ~45-event
  assumption. Frontier console
  pricing (Fable 5) checkpoint action **CLOSED 2026-07-11**: Jakub pasted
  the PILOT-fable call file — 2342 prompt / 1480 completion tokens,
  $0.0974 (`anthropic/claude-fable-5`, $10/M in, $50/M out); output
  parsed cleanly (valid JSON, probabilities in range, no repair). 90
  pastes extrapolate to ≈ $8.77 manual-channel spend; raw total ≈ $1.57
  harness + $8.77 Fable console ≈ $10.3; **total run ≈ $11–16 with
  margins** (harness $2–7 + Fable ≈ $9), inside the envelope (the Sol
  paste action was deleted with DECISION-B).
- **Manual channel:** Fable 5 runs in Jakub's OpenRouter console from
  generated call files.
  - Input: `docs/labs-forecasts-2026-07-11/calls/<model>/<event-slug>.<birth|mid>.md`
    — parameter header (model ID, temperature, max_tokens,
    response_format), then `## SYSTEM` and `## USER` in the pilot-file
    format.
  - Output: `calls/<model>/outputs/<event-slug>.<birth|mid>.json` — raw
    response content verbatim; console token/cost figures pasted into the
    cost ledger (manual runs bypass the harness ledger).
  - Provenance [NOT EXECUTED in run 1 — waived by operator decision,
    deviations row 26; see §11 limitations item (vi). The design below
    remains the protocol for future runs.] [amended per round-3 audit
    R3-M03, pre-call; amended per
    round-4 audit R4-M03, pre-call]: for EVERY console attempt
    (including failed or retried ones) Jakub saves the **OpenRouter
    generation id and the timestamp shown in the console** alongside the
    raw output. The harness then fetches
    `GET /api/v1/generation?id=<id>` and records the returned metadata
    (model, tokens, provider, created) in the cost ledger as independent
    verification of model identity, route, request time, and the
    one-attempt rule. In addition, Jakub captures **ONE console-settings
    screenshot per calling SESSION** — showing model, temperature,
    max_tokens, and response_format as selected — saved under
    `docs/labs-forecasts-2026-07-11/calls/provenance/`. Console settings
    are not modified within a calling session; any settings change ends
    the session and requires a fresh screenshot before further attempts.
    What each
    evidence type establishes, stated plainly: **generation metadata** =
    identity, route, time, tokens; **console-settings screenshot** =
    the selected sampling settings; **call-file header** = the intended
    settings. No evidence type is claimed to establish more. Each
    call-file input and each raw output file is **sha256-hashed in the
    corpus manifest** shipped with the bundle.
  - Attempt rule: 1 + 1 (§6).
- **Harness channel:** production writer, Kimi K2.6, GLM-4.6, drafter via
  OpenRouter (writerEval request pattern, `OPENROUTER_API_KEY`), cost
  ledger lines tagged `005-run1`; per-arm parameters per §6 including the
  DECISION-C max_tokens table.
- Pilot calls are tagged `005-pilot` and discarded from all analyses.

---

*Checkpoint (Task 6 Step 2, held 2026-07-11): Jakub reviewed the vetting
rubric (§4), the sensitive-event predicate (§1.4), the drafter and
forecaster prompts (§3, §6), DECISION-A/B/C/D/E (all decided 2026-07-11,
resolved inline above; DECISION-E, the top-45 run-corpus rule, was the
final checkpoint amendment and closes the DECISION-A tightening
question), the regenerated manifest's eligible N and paste arithmetic,
and the Task 4 primary-family verdicts. The §6 harness retry rule —
design's "retry limit (2)" read as initial attempt + 2 retries = max 3
requests per call — is [CONFIRMED at checkpoint]. No forecast call and no freeze
before explicit approval.*
