{
 "stages": [
  "Select",
  "Observe",
  "Identity",
  "Plan",
  "Keys",
  "Trace",
  "Rig",
  "In-between",
  "Planes",
  "Tests",
  "Critic",
  "Ledger",
  "Pairs"
 ],
 "tests": [
  {
   "id": "S6",
   "name": "Source record complete",
   "cls": "structural",
   "stage": 0,
   "bar": "clip id, source id, interval, archive URL and reported rights present",
   "how": "tools/validate.py reads the lot's source record.",
   "status": "active",
   "applies": [
    "keys",
    "shot",
    "queued"
   ]
  },
  {
   "id": "M1",
   "name": "Reads as the category",
   "cls": "measured",
   "stage": 4,
   "bar": "above 0.75 (real human doodles)",
   "how": "Quick, Draw! MobileViT classifier on the drawn keyframes (run before the head revision; in-betweens not yet scored)",
   "status": "active",
   "applies": [
    "keys",
    "shot"
   ]
  },
  {
   "id": "M2",
   "name": "Looks hand-drawn",
   "cls": "measured",
   "stage": 4,
   "bar": "at least 30 percentile among real doodles of the category",
   "how": "tools/style_score.py: simplify the drawing the way Quick, Draw! simplified its own data (scale to 255, RDP epsilon 2), then percentile of mean distance to 25 nearest real drawings of the category over six stroke statistics.",
   "status": "active",
   "applies": [
    "keys",
    "shot"
   ]
  },
  {
   "id": "M2b",
   "name": "Likeness to the chosen doodle",
   "cls": "measured",
   "stage": 4,
   "bar": "at least 0.5 (1 = the doodle's own stroke statistics)",
   "how": "tools/gwp_tests.py: distance between the stroke statistics of each key and of the chosen doodle, in units of the category's spread, as exp(-RMS z).",
   "status": "active",
   "applies": [
    "shot"
   ]
  },
  {
   "id": "J4",
   "name": "Keeps the doodle's identity",
   "cls": "judged",
   "stage": 4,
   "bar": "a fresh critic shown the doodle and the keys says bar met",
   "how": "Critic packet from AGENTS.md; verdict file kept unedited in the lot.",
   "status": "active",
   "applies": [
    "keys",
    "shot"
   ]
  },
  {
   "id": "B1",
   "name": "Background holds between keys",
   "cls": "measured",
   "stage": 4,
   "bar": "at least 90% of strokes stay put between keys on a locked-off shot",
   "how": "tools/trace_keys.py: a stroke stays put if 90% of its points lie within 3 px of ink in every other key.",
   "status": "active",
   "applies": [
    "keys",
    "shot"
   ]
  },
  {
   "id": "T1",
   "name": "Trace keeps the drawing",
   "cls": "measured",
   "stage": 5,
   "bar": "recall at least 0.98 and every ink piece kept",
   "how": "tools/trace_keys.py: share of ink within line half-width + 2 px of a traced line; share of ink pieces of 20 px or more touched by a trace.",
   "status": "active",
   "applies": [
    "keys",
    "shot"
   ]
  },
  {
   "id": "T2",
   "name": "Stroke count of a doodle",
   "cls": "measured",
   "stage": 5,
   "bar": "character strokes inside the 5th to 95th percentile of real doodles of the category",
   "how": "Count traced character strokes; compare with Quick, Draw! stroke counts for the category.",
   "status": "planned",
   "applies": [
    "keys",
    "shot"
   ]
  },
  {
   "id": "T3",
   "name": "Strokes carry from key to key",
   "cls": "measured",
   "stage": 7,
   "bar": "at least 70% of ink matched between every pair of consecutive keys",
   "how": "tools/match_strokes.py: keys aligned by translation, strokes matched by mean point distance (Hungarian); share of ink in kept matches, worst key pair.",
   "status": "active",
   "applies": [
    "keys",
    "shot"
   ]
  },
  {
   "id": "M3",
   "name": "Holds the footage pose",
   "cls": "measured",
   "stage": 6,
   "bar": "mean at least 0.65, no frame below 0.45",
   "how": "ink inside the SAM mask x bounding-box agreement; worst frame 15 at 0.48",
   "status": "active",
   "applies": [
    "shot"
   ]
  },
  {
   "id": "M4",
   "name": "Planted feet stay put",
   "cls": "measured",
   "stage": 7,
   "bar": "under 2 px, measured on at least 4 planted intervals",
   "how": "world-space drift of a hoof inside 6 planted key intervals (screen x minus camera pan)",
   "status": "active",
   "applies": [
    "shot"
   ]
  },
  {
   "id": "M5",
   "name": "Body keeps its proportions",
   "cls": "measured",
   "stage": 7,
   "bar": "under 10% for each body segment",
   "how": "coefficient of variation of neck, body and leg length across frames: neck 6.1%, body 6.8%, legs 9.8%",
   "status": "active",
   "applies": [
    "shot"
   ]
  },
  {
   "id": "M6",
   "name": "Head travels on smooth arcs",
   "cls": "measured",
   "stage": 7,
   "bar": "under 4 px",
   "how": "mean third difference of the nose position in world space; pops show up as spikes",
   "status": "active",
   "applies": [
    "shot"
   ]
  },
  {
   "id": "M7",
   "name": "Every frame reads as the category",
   "cls": "measured",
   "stage": 7,
   "bar": "classifier p above 0.75 on every frame, not only keys",
   "how": "Run the Quick, Draw! classifier on all in-between frames.",
   "status": "planned",
   "applies": [
    "shot"
   ]
  },
  {
   "id": "M8",
   "name": "Held lines do not boil",
   "cls": "measured",
   "stage": 7,
   "bar": "under 1 px frame-to-frame jitter on strokes meant to hold",
   "how": "Match strokes across consecutive frames; measure mean point displacement on held parts.",
   "status": "planned",
   "applies": [
    "shot"
   ]
  },
  {
   "id": "M9",
   "name": "Contacts land when the footage lands",
   "cls": "measured",
   "stage": 7,
   "bar": "every foot plant within 1 frame of the plant in the footage",
   "how": "Detect plants in SAM mask bottoms and in the cartoon's contacts; compare frame numbers.",
   "status": "planned",
   "applies": [
    "shot"
   ]
  },
  {
   "id": "M10",
   "name": "Character follows the subject",
   "cls": "measured",
   "stage": 7,
   "bar": "centroid path within 5% of frame width of the SAM centroid path",
   "how": "Compare per-frame centroid of character ink with the SAM mask centroid.",
   "status": "planned",
   "applies": [
    "shot"
   ]
  },
  {
   "id": "S1",
   "name": "Near planes move faster",
   "cls": "structural",
   "stage": 8,
   "bar": "sky slowest, grass fastest",
   "how": "screen speed per plane = camera pan x (reference depth / plane depth)",
   "status": "active",
   "applies": [
    "shot"
   ]
  },
  {
   "id": "S2",
   "name": "Every drawing has a source",
   "cls": "structural",
   "stage": 8,
   "bar": "all",
   "how": "each object records its Quick, Draw! key_id or that the agent drew it",
   "status": "active",
   "applies": [
    "shot"
   ]
  },
  {
   "id": "S3",
   "name": "Exposure sheet covers the shot",
   "cls": "structural",
   "stage": 8,
   "bar": "every frame, keys marked",
   "how": "x-sheet rows vs frames; K rows vs agent keys",
   "status": "active",
   "applies": [
    "shot"
   ]
  },
  {
   "id": "S5",
   "name": "Nearer things hide farther ones",
   "cls": "structural",
   "stage": 8,
   "bar": "no far lines inside the walker body",
   "how": "painted by construction; round 3 critic still saw young-giraffe lines between the front legs",
   "status": "active",
   "applies": [
    "shot"
   ]
  },
  {
   "id": "S4",
   "name": "Page works on a phone",
   "cls": "structural",
   "stage": 9,
   "bar": "no sideways scroll, no script errors",
   "how": "headless render at 390 and 1000 px wide",
   "status": "active",
   "applies": [
    "shot"
   ]
  },
  {
   "id": "S7",
   "name": "Ledger chain intact",
   "cls": "structural",
   "stage": 11,
   "bar": "every ledger line hashes to the next",
   "how": "loop.py verify over the lot's ledger.jsonl.",
   "status": "planned",
   "applies": [
    "keys",
    "shot"
   ]
  },
  {
   "id": "J1",
   "name": "Story reads with sound off",
   "cls": "judged",
   "stage": 10,
   "bar": "an independent viewer names the action and every animal",
   "how": "3 blind reviews; last open gap (young giraffes read as llamas) repaired, not yet re-reviewed",
   "status": "active",
   "applies": [
    "shot"
   ]
  },
  {
   "id": "J2",
   "name": "Drawn beats traced",
   "cls": "judged",
   "stage": 10,
   "bar": "blind A/B preference for the drawn version",
   "how": "blind critic with shuffled labels",
   "status": "active",
   "applies": [
    "shot"
   ]
  },
  {
   "id": "J3",
   "name": "Keys alone tell it",
   "cls": "judged",
   "stage": 10,
   "bar": "keys-only playback reads as a walk",
   "how": "next: play only the 9 keys to an independent critic",
   "status": "active",
   "applies": [
    "shot"
   ]
  },
  {
   "id": "J5",
   "name": "A stranger would watch it twice",
   "cls": "judged",
   "stage": 10,
   "bar": "two of three fresh viewers choose to replay",
   "how": "Show the shot at normal speed to three fresh critics; ask only whether they would watch it again and why.",
   "status": "planned",
   "applies": [
    "shot"
   ]
  }
 ]
}