{
  "version": "riddle.good-catch.report.v1",
  "run_id": "run_010_neon_playback_sync_false_positive",
  "title": "Neon playback proof could pass without proving playback",
  "date": "2026-05-24",
  "target": "LilArcade Neon Step Sequencer",
  "source": {
    "integrations_pr": "https://github.com/riddledc/integrations/pull/721",
    "integrations_release_pr": "https://github.com/riddledc/integrations/pull/722",
    "lilarcade_pr": "https://github.com/davisdiehl/lilarcade/pull/493",
    "published_package": "@riddledc/riddle-proof-packs@0.4.8"
  },
  "catch": {
    "bug": "The Neon playback-sync proof pack profile could pass after clicking Play even when the captured app contract still reported isPlaying false and trainer.currentStep 0.",
    "root_cause": "The profile clicked the play button and waited, but did not wait for the visible Stop state, did not assert post-action isPlaying, and summarized stale field paths instead of the nested trainer state exposed by the app contract.",
    "not_an_app_playback_failure": "A direct browser sanity check showed Play All changed the UI to Stop and advanced the trainer playhead. The issue was a weak proof profile that could produce a false positive.",
    "proof_lesson": "Interaction proofs need a visible action receipt and a live app-contract state receipt. A click plus a screenshot is not enough when the claim is that playback started."
  },
  "before": {
    "artifact": "before-weak-proof.json",
    "status": "passed",
    "setup_action_count": 7,
    "waited_for_stop_text": false,
    "post_is_playing": false,
    "post_current_step": 0,
    "post_moved_forward": null,
    "summary": "The profile passed even though post-action contract evidence still showed playback stopped."
  },
  "after": {
    "artifact": "after-hardened-proof.json",
    "status": "passed",
    "setup_action_count": 10,
    "waited_for_stop_text": true,
    "post_is_playing": true,
    "post_current_step": 2,
    "post_moved_forward": true,
    "summary": "The hardened profile waits for Stop, reads nested trainer fields, and asserts post-action playback plus playhead movement."
  },
  "validation": [
    "Merged and published @riddledc/riddle-proof-packs@0.4.8 through trusted publishing.",
    "Synced LilArcade .riddle-proof/profiles/neon-playback-sync.json from the published pack.",
    "Ran npm run proof:sequencer:check-profiles in LilArcade.",
    "Ran npm test in LilArcade: 103 tests passed.",
    "Ran npm run build in LilArcade.",
    "Ran local playback proof from the synced LilArcade profile against http://127.0.0.1:5183 and captured Stop, isPlaying true, currentStep 2, movedForward true.",
    "Ran local mobile trainer layout proof on phone and ipad-mini with no horizontal overflow and no fatal console/page errors.",
    "Merged LilArcade PR #493 and verified the deploy notification completed successfully."
  ],
  "does_not_prove": [
    "long-running transport timing",
    "audio output quality",
    "song-wide playback correctness",
    "human taste or mix preference"
  ]
}
