{
  "schema": 1,
  "passed": true,
  "date": "2026-10-27",
  "name": "Sonic Lighting Test",
  "version": "0.1.0",
  "language": "Java17 / TeaVM0.16.0",
  "scope": "Playable Green Hill Zone Act1, normal start through signpost and tally; later acts/title boot/playable SpecialStage excluded",
  "romUnchanged": true,
  "runtimeEmulator": false,
  "engineSha256": "7b8defa1d0f1cd4574ec44a2e75d9230a09d1c2220b5e8d4fe9b494881f5efa3",
  "ordinaryRoute": {
    "passed": true,
    "assists": false,
    "teleports": false,
    "initialX": 80,
    "initialY": 944,
    "updates": 2960,
    "deaths": 0,
    "lives": 3,
    "score": 15900,
    "rings": 51,
    "timerFrames": 2307,
    "complete": true,
    "endPhase": 4,
    "policy": {
      "period": 0,
      "hold": 8,
      "rollAt": 0,
      "enemyDistance": 56,
      "seed": 1,
      "style": 3
    },
    "maskRLE": [
      [
        2,
        25
      ],
      [
        18,
        8
      ],
      [
        2,
        140
      ],
      [
        18,
        8
      ],
      [
        2,
        51
      ],
      [
        18,
        8
      ],
      [
        2,
        93
      ],
      [
        18,
        8
      ],
      [
        2,
        108
      ],
      [
        18,
        8
      ],
      [
        2,
        30
      ],
      [
        18,
        8
      ],
      [
        2,
        48
      ],
      [
        18,
        8
      ],
      [
        2,
        46
      ],
      [
        18,
        8
      ],
      [
        2,
        46
      ],
      [
        18,
        8
      ],
      [
        2,
        47
      ],
      [
        18,
        8
      ],
      [
        2,
        177
      ],
      [
        18,
        8
      ],
      [
        2,
        80
      ],
      [
        18,
        8
      ],
      [
        2,
        156
      ],
      [
        18,
        8
      ],
      [
        2,
        46
      ],
      [
        18,
        8
      ],
      [
        2,
        46
      ],
      [
        18,
        8
      ],
      [
        2,
        50
      ],
      [
        18,
        8
      ],
      [
        2,
        63
      ],
      [
        18,
        8
      ],
      [
        2,
        44
      ],
      [
        18,
        8
      ],
      [
        2,
        118
      ],
      [
        18,
        8
      ],
      [
        2,
        5
      ],
      [
        18,
        8
      ],
      [
        2,
        131
      ],
      [
        18,
        8
      ],
      [
        2,
        26
      ],
      [
        18,
        8
      ],
      [
        2,
        26
      ],
      [
        18,
        8
      ],
      [
        2,
        15
      ],
      [
        18,
        8
      ],
      [
        2,
        3
      ],
      [
        18,
        8
      ],
      [
        2,
        46
      ],
      [
        18,
        8
      ],
      [
        2,
        54
      ],
      [
        18,
        8
      ],
      [
        2,
        85
      ],
      [
        18,
        8
      ],
      [
        2,
        89
      ],
      [
        18,
        8
      ],
      [
        2,
        87
      ],
      [
        18,
        8
      ],
      [
        2,
        144
      ],
      [
        18,
        8
      ],
      [
        2,
        47
      ],
      [
        18,
        8
      ],
      [
        2,
        46
      ],
      [
        18,
        8
      ],
      [
        2,
        46
      ],
      [
        18,
        8
      ],
      [
        2,
        46
      ],
      [
        18,
        8
      ],
      [
        2,
        46
      ],
      [
        18,
        8
      ],
      [
        2,
        46
      ],
      [
        18,
        8
      ],
      [
        2,
        46
      ],
      [
        18,
        8
      ],
      [
        2,
        46
      ],
      [
        18,
        8
      ],
      [
        2,
        46
      ],
      [
        18,
        8
      ],
      [
        2,
        46
      ],
      [
        18,
        8
      ],
      [
        2,
        46
      ]
    ],
    "milestones": [
      {
        "update": 136,
        "x": 516,
        "y": 940,
        "g": 1536,
        "rings": 0,
        "lives": 3
      },
      {
        "update": 227,
        "x": 1027,
        "y": 876,
        "g": 1536,
        "rings": 0,
        "lives": 3
      },
      {
        "update": 318,
        "x": 1540,
        "y": 876,
        "g": 1536,
        "rings": 5,
        "lives": 3
      },
      {
        "update": 432,
        "x": 2049,
        "y": 837,
        "g": 1517,
        "rings": 5,
        "lives": 3
      },
      {
        "update": 573,
        "x": 2563,
        "y": 690,
        "g": 864,
        "rings": 7,
        "lives": 3
      },
      {
        "update": 736,
        "x": 3072,
        "y": 684,
        "g": 317,
        "rings": 9,
        "lives": 3
      },
      {
        "update": 864,
        "x": 3588,
        "y": 620,
        "g": 1536,
        "rings": 14,
        "lives": 3
      },
      {
        "update": 1086,
        "x": 4097,
        "y": 714,
        "g": 0,
        "rings": 16,
        "lives": 3
      },
      {
        "update": 1245,
        "x": 4611,
        "y": 854,
        "g": 0,
        "rings": 19,
        "lives": 3
      },
      {
        "update": 1449,
        "x": 5121,
        "y": 710,
        "g": 1392,
        "rings": 42,
        "lives": 3
      },
      {
        "update": 1613,
        "x": 5635,
        "y": 684,
        "g": 1380,
        "rings": 45,
        "lives": 3
      },
      {
        "update": 1701,
        "x": 6146,
        "y": 625,
        "g": 1536,
        "rings": 45,
        "lives": 3
      },
      {
        "update": 1776,
        "x": 6658,
        "y": 881,
        "g": 3164,
        "rings": 50,
        "lives": 3
      },
      {
        "update": 1829,
        "x": 7174,
        "y": 1068,
        "g": 4215,
        "rings": 50,
        "lives": 3
      },
      {
        "update": 1934,
        "x": 7681,
        "y": 1107,
        "g": 1166,
        "rings": 50,
        "lives": 3
      },
      {
        "update": 2026,
        "x": 8193,
        "y": 1176,
        "g": 0,
        "rings": 50,
        "lives": 3
      },
      {
        "update": 2157,
        "x": 8707,
        "y": 1132,
        "g": 1458,
        "rings": 50,
        "lives": 3
      },
      {
        "update": 2247,
        "x": 9216,
        "y": 1071,
        "g": 1536,
        "rings": 51,
        "lives": 3
      },
      {
        "update": 2333,
        "x": 9728,
        "y": 1196,
        "g": 1536,
        "rings": 51,
        "lives": 3
      }
    ]
  },
  "checks": {
    "runtime": {
      "schemaVersion": 1,
      "passed": true,
      "date": "2026-10-27",
      "runtime": "Native editable Java 17 gameplay compiled to browser JavaScript with TeaVM 0.16.0; no emulator in this runtime.",
      "source": {
        "commit": "89c0e0e06b51fd9ebac44d988e4a89bd643fd031",
        "revision": "Sonic 1 REV00, FixBugs 0",
        "romSha256": "46160baa06362c711c9f1a5017cb7371026444936c8af5e93a78996cf32ff2a6",
        "nativeCoreTestOnly": true,
        "scoreLifeBehavior": "REV00 AddPoints maintains an unused score copy. Score-threshold extra lives are in the Revision-not-zero Japanese-region branch and do not apply here. A controlled 50,700-point tally test retains 3 lives."
      },
      "checks": {
        "playerCameraAndTerrain": {
          "passed": true,
          "cases": 6,
          "updates": 880,
          "playerFields": 11440,
          "cameraFields": 5280,
          "terrainQueries": 2772,
          "totalAssertions": 40656,
          "scope": "Java exact-match to selected verified JS movement, camera and terrain-query traces using the actual Java Stage. Direct native camera scope is separately bounded below; full-route native comparisons are reported separately.",
          "directNativeCameraScope": {
            "updates": 790,
            "fields": 4740,
            "loopSnapshotPhaseObservationExcluded": true
          }
        },
        "nativeSonicAnimation": {
          "passed": true,
          "cases": 6,
          "updates": 880,
          "fields": 7040,
          "differences": 0
        },
        "nativeLedgeAndObjectBalance": {
          "passed": true,
          "cases": 10,
          "updates": 400,
          "fields": 3600,
          "differences": 0
        },
        "nativeShieldAndInvincibility": {
          "passed": true,
          "cases": 3,
          "updates": 360,
          "fields": 6020,
          "differences": 0
        },
        "nativeTerrain": {
          "passed": true,
          "cases": 7952
        },
        "objects": {
          "passed": true,
          "sourceCases": 42,
          "sourceAssertions": 395,
          "placements": 214,
          "ringPositions": 155,
          "objectIds": 20,
          "nativeSolidCases": 1848,
          "nativeMotionUpdates": 2308,
          "nativeLoaderSweeps": 88,
          "nativeMonitorCases": 6,
          "nativeRingLossCases": 512,
          "nativeComparedFields": 133108,
          "differences": 0,
          "report": "reports/object-verification.json",
          "reportSha256": "ea6ae9040c95afb46bd4b7077c1c28e760b605e38177546ba110a9ca33893134"
        },
        "lifecycle": {
          "passed": true,
          "checks": 30,
          "scope": "Controlled lifecycle, goal/tally, death/lives/restart, time-over, card-age and REV00 score-life fixtures. Ordinary traversal is independently demonstrated below."
        },
        "ordinaryFullAct1": {
          "passed": true,
          "start": [
            80,
            944
          ],
          "updates": 2960,
          "goalAt": 2307,
          "tallyAt": 2431,
          "completeAt": 2960,
          "assists": false,
          "teleports": false,
          "hurtEvents": 0,
          "deathEvents": 0,
          "lives": 3,
          "rings": 51,
          "score": 15900,
          "timerFrames": 2307,
          "enemyDefeats": 7,
          "springEvents": 1,
          "checkpointAt": 1765,
          "maxX": 9767,
          "loopBackRoute": true,
          "loopGroundModes": [
            0,
            2,
            3
          ],
          "inputTraceSha256": "ba2ce6ba6f5f6bf2b44404ae2f0ac1cdc143708316869eab94065b84241a5e44"
        },
        "actualTeaVMVersusJVM": {
          "passed": true,
          "actualTeaVMCompiledJava": true,
          "ordinaryStartToComplete": true,
          "assists": false,
          "teleports": false,
          "updates": 2960,
          "snapshotsCompared": 2961,
          "visibleObjectSnapshotsCompared": 12888,
          "complete": true,
          "score": 15900,
          "rings": 51,
          "lives": 3,
          "engineSha256": "7b8defa1d0f1cd4574ec44a2e75d9230a09d1c2220b5e8d4fe9b494881f5efa3",
          "routeSha256": "ba2ce6ba6f5f6bf2b44404ae2f0ac1cdc143708316869eab94065b84241a5e44",
          "scope": "Parsed full BrowserEngine snapshots match JVM after every ordinary-input update. Native Canvas/browser rendering and input event delivery are separately tested."
        },
        "compiledReadableJavaSourceCopies": {
          "passed": true,
          "files": 13
        },
        "interactiveBrowser": {
          "tested": false,
          "scope": "Current Work tools do not provide an interactive browser. Actual module/RAF bootstrap, held-input replay and native Canvas rendering are independently checked. No physical controller hardware test is claimed."
        },
        "sourceSoundEvents": {
          "passed": true,
          "assertions": 9,
          "scope": "Source braking-branch skid commands, one-time pit death command and input-update event lifetime; no audio-mix identity claim."
        },
        "audioScheduler": {
          "passed": true,
          "tests": 8,
          "testFile": "tests/audio.test.mjs",
          "testSha256": "5c663df0872588463e03ef75e1770c7910067c9c9c59e9a4ca9b77eda3b792e3",
          "moduleSha256": "158ff765440c5e70aa9b9808817df1f3d3faf22049a5aec168afeca19ddc4249",
          "scope": "Portable FakeAudioContext scheduler checks: sample-loop window/intro preservation, tempo reanchor, extra-life prior track/offset restoration, stopping effects, stale async cancellation, finite cue completion, repeated skid retriggers without stacking. Actual browser decoding and native channel contention are separate."
        },
        "fullOriginalROMRoute": {
          "passed": true,
          "scope": "The same 2,960 ordinary held-input updates reach the Green Hill Act 1 signpost and exhaust the time and ring bonus tally in the unchanged original ROM and Java, with no assists, no teleports and no deaths. All 11 listed player-movement fields and ring/life counters match every compared update. This is a bounded route-completion/source comparison, not universal frame equivalence.",
          "romSha256": "46160baa06362c711c9f1a5017cb7371026444936c8af5e93a78996cf32ff2a6",
          "wasmValidationCoreSha256": "cfec0e5915c4b3d03336482e990a7809f16b37909992f94631c2cad8e92b5aae",
          "nativeFixtureSha256": "7ddb9655a9e77bdc76a6abf5cb909a82373a1239c510c9372f9c74861a91878d",
          "routeSha256": "ba2ce6ba6f5f6bf2b44404ae2f0ac1cdc143708316869eab94065b84241a5e44",
          "javaTraceSha256": "b335a1a930bb096248fd1ea2f50fd95be0c9c82c0cbfead13a22417faf2e7153",
          "privateDetailedAuditSha256": "b90a8f9156085df56f0f42fc9f02e754837f7efed42501ed6d225b493aa9f8ff",
          "updates": 2960,
          "snapshots": 2961,
          "nativeGoalUpdate": 2307,
          "nativeActClearCardUpdate": 2431,
          "nativeEnd": {
            "rings": 51,
            "lives": 3,
            "score": 15900,
            "timeBonus": 0,
            "ringBonus": 0,
            "zone": 0,
            "act": 0,
            "giantRingEntered": false
          },
          "originalROMUnchanged": true,
          "playerMovementFields": [
            "x",
            "y",
            "vx",
            "vy",
            "g",
            "angle",
            "grounded",
            "rolling",
            "rx",
            "ry",
            "route"
          ],
          "playerFieldComparisons": 32571,
          "playerMovementDifferences": 0,
          "ringAndLifeCounterDifferences": 0,
          "explicitDifferences": {
            "camera": {
              "updates": [
                1942
              ],
              "description": "One snapshot at update 1,942 differs; immediately next and all other camera samples match. Consistent with a native scheduler sampling boundary; not generalized camera equivalence."
            },
            "bonusTally": {
              "firstScoreTimingDifference": 2680,
              "nativeCardCreatedUpdate": 2431,
              "nativeFirstMoveUpdate": 2474,
              "nativeWaitBeginsUpdate": 2542,
              "nativeFirstBonusUpdate": 2722,
              "javaFirstBonusUpdate": 2680,
              "omittedOriginalPatternLoadingWaitVisits": 42,
              "description": "The original waits for its pattern-load queue before initializing and moving the results cards. The Java version uses already decoded assets and omits the verified 42 additional loading-wait visits. Final score of 15,900 and exhausted bonuses agree.",
              "focusedOriginalProof": "tests/native-card-phase.json",
              "focusedOriginalProofSha256": "03c076a54f660b454c6cf34b8200e953b2f3395cf2694f14edfc2581ba1a9848"
            },
            "clockStart": {
              "nativeFrameCounter": 26,
              "nativeTimerFrames": 30,
              "javaControlledPlayTimerFrames": 0,
              "nativeGoalTimerFrames": 2337,
              "javaFinalTimerFrames": 2307,
              "description": "Original fixture comes from ordinary boot/Start/title-fade. Java launcher starts directly in controlled play; original title/PLC boot loading is outside its scope."
            }
          },
          "fullNativeFrameEquivalenceClaimed": false,
          "javaBrowserBuildSha256": "7b8defa1d0f1cd4574ec44a2e75d9230a09d1c2220b5e8d4fe9b494881f5efa3"
        },
        "originalHurtDeathPrefix": {
          "passed": true,
          "scope": "A separate ordinary-input original-ROM hurt/death route agrees with Java through 1,793 updates for player movement, camera, rings, lives and score. Java immediately rebuilds the level at the following restart boundary; original ROM proceeds through hardware loading. No equivalence through that loader transition is claimed.",
          "romSha256": "46160baa06362c711c9f1a5017cb7371026444936c8af5e93a78996cf32ff2a6",
          "routeSha256": "142aa3ecc97bfb153db3b5bdf04343765cb2b69c5610595cad204042c37af955",
          "javaTraceSha256": "0a48a19d3346fcf1b0cce8617fb460a8b3bab22030b5626c9f59befd9036cd6c",
          "nativeFixtureSha256": "7ddb9655a9e77bdc76a6abf5cb909a82373a1239c510c9372f9c74861a91878d",
          "privateDetailedAuditSha256": "44724965b121d88a9d030ced87d98618a199d37a2f8f98b6d0247d51b9ac65f3",
          "updatesComparedBeforeRestart": 1793,
          "nativeDeaths": 1,
          "playerMovementDifferencesBeforeRestart": 0,
          "cameraDifferencesBeforeRestart": 0,
          "ringAndLifeAndScoreDifferencesBeforeRestart": 0,
          "firstExcludedRestartBoundaryUpdate": 1794,
          "privateNativeStatesExcludedFromPublication": true
        },
        "nativeCanvasRenderer": {
          "passed": true,
          "engineSha256": "7b8defa1d0f1cd4574ec44a2e75d9230a09d1c2220b5e8d4fe9b494881f5efa3",
          "draws": 365,
          "missingAssets": 0,
          "objectMappingFramesDrawn": 151,
          "originalSonicFlipPosesChecked": 176,
          "gameOverNativePixels": 1221,
          "scope": "Offline nativeCanvas raster/source coverage, stable input snapshots and original priority rules. Actual copied environment adapter queries compiled Java terrain; browser/input delivery and full gameplay equivalence are separate.",
          "reportSha256": "935f17a00c3a619f05cb30506d13ae1afdca8a4049f6e218ebad2d198db89797"
        },
        "browserShellBootstrap": {
          "passed": true,
          "report": "web/verification/browser-shell-results.json",
          "reportSha256": "cec70112fdac035aba5927237bd585c37a39931691c55794936a0b796b565782",
          "scope": "Actual page/module and RAF replay with controlled DOM and input stubs; physical controller hardware and interactive browser play are not claimed."
        }
      },
      "engine": {
        "file": "web/engine/sonic-engine.js",
        "bytes": 399287,
        "sha256": "7b8defa1d0f1cd4574ec44a2e75d9230a09d1c2220b5e8d4fe9b494881f5efa3",
        "sourceMapSha256": "b8e02c77c19c7acbad6ef205deb8e5663f4b60cc65b4c6011a5c351719090294",
        "compiler": "TeaVM 0.16.0",
        "build": "build.ps1 completed successfully with JDK 17 and offline Maven"
      },
      "sourceHashes": {
        "src/org/cosom/sonic/BrowserEngine.java": "63d7331716e8a88226e9bbae751d33ba461d79b3b9fe0a391120851043b082f6",
        "src/org/cosom/sonic/Camera.java": "8569ce406d0772d77d4d9299ae374c14319ec15682bf0c6f82dbb85d5742e65e",
        "src/org/cosom/sonic/Game.java": "d2ab8742aec9ce2422e3682b48c721d0b7e95e03829e738aa849a00ef7d7b14d",
        "src/org/cosom/sonic/Input.java": "54adc03ca9852a2a639fc4b0ed9f0e798b7a5e4c0144af8f47eb06d1d2d7f73c",
        "src/org/cosom/sonic/JavaObjects.java": "dc3bd8a45c6391fa3071d3a489b33963d82b8c86c22a2eb11148bdc4518d195c",
        "src/org/cosom/sonic/LevelAnimation.java": "289748fb55fce104390b12c679af48250d02b192991408d2387f38c7aff5cd2b",
        "src/org/cosom/sonic/Physics.java": "bf8b69ae95346f8b9b921bfcc147d9d626aad7af883a4b98bad93c0f372238cc",
        "src/org/cosom/sonic/Player.java": "e52ea4b51b7d10a0bd0771376a06734b60c8705a3b6d55b7336c63859b8fddc7",
        "src/org/cosom/sonic/PowerVisuals.java": "2ce3406a88b75650ca2e5e0f6772b8baf200f87827754a6d8b17bb2664d5d747",
        "src/org/cosom/sonic/SonicAnimation.java": "67cf3cc35023577cc622610804306e66e0439efad7289e30fc39c9135daae382",
        "src/org/cosom/sonic/Stage.java": "ba2ee81bec2cc0c6d08a885c71de7a425cf964d50ee21cb45dc1b2663b5f960a",
        "src/org/cosom/sonic/StageData.java": "ad3268b866aa185c3ea420e63f06e235dd31b29a4f2ec915229554c629d70e28",
        "src/org/cosom/sonic/Terrain.java": "267c65a756acd88a3b24cb03f18b7d6a513fc47fe8743e8df6073145d542bce0"
      },
      "knownLimits": [
        "Full Act 1 completion and bounded native comparisons do not prove every possible object-slot history, subframe interaction, rendered pixel or mixed audio sample.",
        "All 32,571 listed player-field comparisons, rings and lives agree on the 2,960-update original-ROM completion route. One camera snapshot at update 1,942 differs; the immediately following and all other camera samples agree. This is consistent with a native scheduler sampling boundary and is retained as an explicit limit.",
        "Focused unchanged-ROM observation measures 42 additional original pattern-load-queue wait visits before results-card initialization. Original first bonus is update 2,722 versus Java 2,680. Java retains the source 68-move, 180-wait and routine-visit sequence with already decoded assets; it does not insert a fitted hardware-loading delay. Final score and exhausted bonuses agree.",
        "Java starts directly in controlled play with timer 0; the original diagnostic fixture starts after ordinary boot/Start/title fade with timer 30. Original title screens, PLC boot loading and hardware restart-loading transitions are outside this launcher.",
        "Oscillators and a separate deterministic VBlank counter start at the source cleared baseline. The original boot/title/loader phase is not reproduced; VBlank is preserved across act restart. Isolated ring-loss cadence is verified at explicit phases.",
        "Music and effects use source-command recordings, not live SMPS channel synthesis. Speed-shoes playback-rate pitch/tempo and simultaneous channel contention remain presentation approximations.",
        "The first act ends after the source bonus tally. Act 2, a playable Special Stage and full original menus are outside this build.",
        "Diagnostic ROM/core files, native states and JVM snapshots remain private and are not runtime dependencies."
      ]
    },
    "objects": {
      "passed": true,
      "date": "2026-10-27",
      "scope": "Native Java GHZ1 object behavior and original-ROM diagnostic comparisons; not a claim of bit-identical complete game execution.",
      "sourceCommit": "89c0e0e06b51fd9ebac44d988e4a89bd643fd031",
      "romSha256": "46160baa06362c711c9f1a5017cb7371026444936c8af5e93a78996cf32ff2a6",
      "runtime": "Editable Java compiled separately with TeaVM; diagnostic core is test-only and not imported by runtime.",
      "tests": {
        "ObjectSelfTest": {
          "passed": true,
          "cases": 42,
          "assertions": 395,
          "placements": 214,
          "ringPositions": 155,
          "objectIds": 20
        },
        "ObjectNativeReferenceTest": {
          "passed": true,
          "cases": 1848,
          "fields": 24024,
          "mismatches": 0
        },
        "ObjectNativeMotionTest": {
          "passed": true,
          "updates": 2308,
          "fields": 32284,
          "mismatches": 0
        },
        "ObjectNativeLoaderTest": {
          "passed": true,
          "updates": 88,
          "fields": 73656,
          "mismatches": 0
        },
        "MonitorNativeReferenceTest": {
          "passed": true,
          "cases": 6,
          "fields": 72,
          "mismatches": 0
        },
        "RingLossNativeReferenceTest": {
          "passed": true,
          "cases": 512,
          "fields": 3072,
          "mismatches": 0
        }
      },
      "nativeComparedFields": 133108,
      "sourceHashes": {
        "src/org/cosom/sonic/JavaObjects.java": "dc3bd8a45c6391fa3071d3a489b33963d82b8c86c22a2eb11148bdc4518d195c",
        "tests/java/org/cosom/sonic/ObjectSelfTest.java": "38ec3582778ee5fcbd726105bfa2117ebfaf0060174db599d32d0838929944ba",
        "tests/java/org/cosom/sonic/ObjectNativeReferenceTest.java": "e4121c4bd95458274b7ba4c0edf23464d5d23807b3695582868ce34d014e1be1",
        "tests/java/org/cosom/sonic/ObjectNativeMotionTest.java": "a56c6d95b403159caa4003a42110c6b3a5ea36729fabe2e7ba57fcaf4711940b",
        "tests/java/org/cosom/sonic/ObjectNativeLoaderTest.java": "d6aa683e00eb4e22ba58bfbea607f11c041bd31eecb571eeb3f4dde88cd96c20",
        "tests/java/org/cosom/sonic/MonitorNativeReferenceTest.java": "498f380f341a33f8723e579ce9d802e5b192b43f2dff5fd2e52a728ad4ca40c2",
        "tests/java/org/cosom/sonic/RingLossNativeReferenceTest.java": "cc5a4a2f7d7d5643eaa437dec3eaabd7390f128e28ffe7b7c7d7c2014a1274e6",
        "tests/native-object-reference.py": "533e6158b96f94ee3801ffce6e486ac85c0d14cb62776f82bad261349f1e737d",
        "tests/native-object-reference.tsv": "4ced072587b34781a22adc729d061f1a5d7104d64cc75faccfa8c3c7e94ff70d",
        "tests/native-object-motion.py": "d6276c116471ecb127967c1f050299d7e53bc1a78fe7284285cef9ea08d111fd",
        "tests/native-object-motion.tsv": "e663d64c6c4f61a11a1718abb893359be26e269c6dbdaa5f51560cece436ea4b",
        "tests/native-object-loader.py": "66e6c4446d309aa476408f5b23e8348e60e92c48bc4e976a3fa0f3464ab351be",
        "tests/native-object-loader.tsv": "8e0c5b91c0e11882c8c20b9b510276c58aaf34bc23daf3c9036d30e40d46c866",
        "tests/native-monitor-reference.py": "9f721ce368f088c52927c9663b6df6b651cb3f56dc2923915ff5084432c04a3f",
        "tests/native-monitor-reference.tsv": "5fadb1d64e4a30821b5a0bfcb056655e84c445d82cd4047206bf0129882a14a2",
        "tests/native-ringloss-reference.py": "606bd6e7d9e8b15b9cdd6b5cf380e782f058dcd5157b9bdf41a6ab2798fc48c1",
        "tests/native-ringloss-reference.tsv": "b32137c3a95aa123e57882580a0966de220a195cd8b6ba7db7f445663e30798a"
      },
      "knownLimits": [
        "Oscillatory globals start from the source cleared baseline. The exact phase after the original title-card sequence has not been established. A retained reference capture is26 oscillator updates later and is not arbitrarily used as a canonical initial seed.",
        "VBlank uses a separate deterministic counter starting at0 and persisting across act restart. Its original boot/title/loader phase is not reproduced. RingLoss cadence is proven for explicit phases independent of that context.",
        "Original-ROM comparisons isolate selected routines and inputs. They do not prove all possible game states, camera histories, object-slot combinations or video lag frames.",
        "The giant ring implements the GHZ entry/flash event. A playable Special Stage is outside this act1 build.",
        "The renderer owns original tile animation, hardware sprite limits/priority and visual/audio presentation. These object checks do not prove every rendered pixel or mixed audio sample."
      ]
    },
    "renderer": {
      "passed": true,
      "stats": {
        "draws": 365,
        "drawnObjects": 1075,
        "visibleTilePatches": 16402,
        "missingAssets": 0,
        "backgroundCutouts": 3,
        "backgroundCutoutCache": 3,
        "lastFrame": 1601
      },
      "routeMutationChecks": 198,
      "originalSonicFlipPosesChecked": 176,
      "objectMappingFramesDrawn": 151,
      "spritePriorityAssertions": 4,
      "deathCardsDrawn": 2,
      "gameOverUpdates": 927,
      "gameOverNativePixels": 1221,
      "ordinaryOverAge0HasNoCard": true,
      "environmentScenes": 4,
      "actualTeaVMJavaTerrainUsed": true,
      "engineSha256": "7b8defa1d0f1cd4574ec44a2e75d9230a09d1c2220b5e8d4fe9b494881f5efa3",
      "snapshots": [
        {
          "name": "opening",
          "frame": 0,
          "pngSha256": "0d3fe759517cfa99ec995cd8aaf173e235b6228bd04894a3fdc76bfbdef71f1b"
        },
        {
          "name": "bridge",
          "frame": 241,
          "pngSha256": "df541ab198dc6aa650ef6eb0c3808cb2a9e158aea859cb01b1adfab598ab1b55"
        },
        {
          "name": "uphill",
          "frame": 375,
          "pngSha256": "983e969643b5c30f9c33c6c10023eff2fc3b00d8054c519a0c2d584d14f3f3c2"
        },
        {
          "name": "loop",
          "frame": 1554,
          "pngSha256": "d3724e360145dd29959adc026956e5c381e21a15cde59318d55524355ad5768a"
        },
        {
          "name": "tunnel",
          "frame": 1776,
          "pngSha256": "19b1b937d961f031ddab96bb664898bf48e39d3136424e1ba042be60bdff1159"
        },
        {
          "name": "waterfall",
          "frame": 1848,
          "pngSha256": "fdee72fc4fe67d62b07304cad1c5fe782dc5e00c5f99fef63d76405d508a6589"
        },
        {
          "name": "act-clear",
          "frame": 2960,
          "pngSha256": "860bc8fd7f91c9013bc401582cf28d4248f3b91800acc7f779c926da765f0942"
        }
      ],
      "scope": "Offline nativeCanvas raster/source coverage, stable input snapshots and original priority rules. Actual copied environment adapter queries compiled Java terrain; browser/input delivery and full gameplay equivalence are separate."
    },
    "browserShell": {
      "passed": true,
      "kind": "Actual Java browser page module with minimal DOM stubs and native Canvas",
      "engineSha256": "7b8defa1d0f1cd4574ec44a2e75d9230a09d1c2220b5e8d4fe9b494881f5efa3",
      "checks": [
        "all original art and weather assets load",
        "Java engine initializes through browser ABI",
        "original Sonic character lighting and shadows draw",
        "environment controls do not mutate Java state",
        "focused-button Space retains default activation",
        "start/keyboard/pause/single-step/restart handlers",
        "synthetic controller motion uses Java engine",
        "focus loss clears and pauses controller",
        "Start button press edges pause/resume",
        "three independent Java assist controls wire correctly",
        "real RAF loop allows complete generic HID mapping without resetting learning",
        "actual verified-route button/RAF/fixed-step handlers finish the complete act with assists off"
      ],
      "complete": true,
      "updates": 2960,
      "rings": 51,
      "score": 15900,
      "interactiveBrowser": "Unavailable: local browser use disabled in Work settings",
      "physicalController": "Not independently tested"
    },
    "audio": {
      "passed": true,
      "tests": 8,
      "testFile": "tests/audio.test.mjs",
      "testSha256": "5c663df0872588463e03ef75e1770c7910067c9c9c59e9a4ca9b77eda3b792e3",
      "moduleSha256": "158ff765440c5e70aa9b9808817df1f3d3faf22049a5aec168afeca19ddc4249",
      "scope": "Portable FakeAudioContext scheduler checks: sample-loop window/intro preservation, tempo reanchor, extra-life prior track/offset restoration, stopping effects, stale async cancellation, finite cue completion, repeated skid retriggers without stacking. Actual browser decoding and native channel contention are separate."
    },
    "sameRouteOriginalROMCompletion": {
      "passed": true,
      "scope": "The same 2,960 ordinary held-input updates reach the Green Hill Act 1 signpost and exhaust the time and ring bonus tally in the unchanged original ROM and Java, with no assists, no teleports and no deaths. All 11 listed player-movement fields and ring/life counters match every compared update. This is a bounded route-completion/source comparison, not universal frame equivalence.",
      "romSha256": "46160baa06362c711c9f1a5017cb7371026444936c8af5e93a78996cf32ff2a6",
      "wasmValidationCoreSha256": "cfec0e5915c4b3d03336482e990a7809f16b37909992f94631c2cad8e92b5aae",
      "nativeFixtureSha256": "7ddb9655a9e77bdc76a6abf5cb909a82373a1239c510c9372f9c74861a91878d",
      "routeSha256": "ba2ce6ba6f5f6bf2b44404ae2f0ac1cdc143708316869eab94065b84241a5e44",
      "javaTraceSha256": "b335a1a930bb096248fd1ea2f50fd95be0c9c82c0cbfead13a22417faf2e7153",
      "privateDetailedAuditSha256": "b90a8f9156085df56f0f42fc9f02e754837f7efed42501ed6d225b493aa9f8ff",
      "updates": 2960,
      "snapshots": 2961,
      "nativeGoalUpdate": 2307,
      "nativeActClearCardUpdate": 2431,
      "nativeEnd": {
        "rings": 51,
        "lives": 3,
        "score": 15900,
        "timeBonus": 0,
        "ringBonus": 0,
        "zone": 0,
        "act": 0,
        "giantRingEntered": false
      },
      "originalROMUnchanged": true,
      "playerMovementFields": [
        "x",
        "y",
        "vx",
        "vy",
        "g",
        "angle",
        "grounded",
        "rolling",
        "rx",
        "ry",
        "route"
      ],
      "playerFieldComparisons": 32571,
      "playerMovementDifferences": 0,
      "ringAndLifeCounterDifferences": 0,
      "explicitDifferences": {
        "camera": {
          "updates": [
            1942
          ],
          "description": "One snapshot at update 1,942 differs; immediately next and all other camera samples match. Consistent with a native scheduler sampling boundary; not generalized camera equivalence."
        },
        "bonusTally": {
          "firstScoreTimingDifference": 2680,
          "nativeCardCreatedUpdate": 2431,
          "nativeFirstMoveUpdate": 2474,
          "nativeWaitBeginsUpdate": 2542,
          "nativeFirstBonusUpdate": 2722,
          "javaFirstBonusUpdate": 2680,
          "omittedOriginalPatternLoadingWaitVisits": 42,
          "description": "The original waits for its pattern-load queue before initializing and moving the results cards. The Java version uses already decoded assets and omits the verified 42 additional loading-wait visits. Final score of 15,900 and exhausted bonuses agree.",
          "focusedOriginalProof": "tests/native-card-phase.json",
          "focusedOriginalProofSha256": "03c076a54f660b454c6cf34b8200e953b2f3395cf2694f14edfc2581ba1a9848"
        },
        "clockStart": {
          "nativeFrameCounter": 26,
          "nativeTimerFrames": 30,
          "javaControlledPlayTimerFrames": 0,
          "nativeGoalTimerFrames": 2337,
          "javaFinalTimerFrames": 2307,
          "description": "Original fixture comes from ordinary boot/Start/title-fade. Java launcher starts directly in controlled play; original title/PLC boot loading is outside its scope."
        }
      },
      "fullNativeFrameEquivalenceClaimed": false,
      "javaBrowserBuildSha256": "7b8defa1d0f1cd4574ec44a2e75d9230a09d1c2220b5e8d4fe9b494881f5efa3"
    }
  },
  "interactiveBrowserVerified": false,
  "physicalControllerVerified": false,
  "limits": "Selected original-ROM comparisons and a completed Java route do not establish every input, loading phase, hardware sprite limit or mixed audio sample identical."
}
