{
  "format": "shadowrun-matchbox-anywhere-provenance-v1",
  "version": 1,
  "guideBehaviorVersion": "1.5.0",
  "baseGuideVersion": "1.1.0",
  "sourceRomSha256": "586551eadaff2693c0f21d9c47a697841989ae312d422fa4bf30823473a40fae",
  "romModified": false,
  "runtimeModified": false,
  "guideScript": {
    "file": "matchbox-guide.js",
    "bytes": 25025,
    "sha256": "4d19dc3f4a9ee17ababc704bade1d138b451f1d0ddf4f859a45a8edc93af2d2e"
  },
  "guideStyle": {
    "file": "matchbox-guide.css",
    "bytes": 2749,
    "sha256": "5afd8f21481a7c2d424ba17aaa8f8c54aa65933df3378a9589d72ad1210c79be"
  },
  "bridge": {
    "file": "ram-bridge.js",
    "bytes": 9025,
    "sha256": "8ad6968da3c32e8cfbbc8bce6ea8d6086b8dc887e80af901295b63d9c9fe3a21"
  },
  "writeAllowlistHex": [
    "1CDB",
    "1CDC",
    "2FA2",
    "2FA3",
    "3059",
    "305A"
  ],
  "coordinates": {
    "guideWorldXYZ": [
      458,
      622,
      64
    ],
    "projectionConstants": [
      220,
      174
    ],
    "cameraQuarterWords": [
      "0CC4",
      "0CC6"
    ],
    "appliedSignedQuarterVelocityWords": [
      "0CC8",
      "0CCA"
    ],
    "submittedCamera": "u16(camera) - s16(appliedVelocity), then floor(/4)",
    "screenFeet": "x=220-floor((u16[0CC4]-s16[0CC8])/4); y=174-floor((u16[0CC6]-s16[0CCA])/4)",
    "quarterBounds": [
      [
        0,
        2048
      ],
      [
        0,
        1148
      ]
    ],
    "signedVelocityBounds": [
      -32,
      32
    ],
    "source": [
      "8188EF..818919 uploads camera/4 into BG1/BG2 PPU scroll registers.",
      "818B43..818BCD computes signed camera deltas.",
      "8189A6..8189F5 applies those deltas and retains them."
    ],
    "nativePpuFramesCompared": 321,
    "mismatches": 0,
    "oldCurrentCameraOnlyMismatchedFrames": 168,
    "cadence": "Read a current live RAM copy at browser animation cadence. Do not interpolate a world-fixed sprite or retain the old140ms movement sampling."
  },
  "fieldGuard": {
    "validRoomEntries": "0..497 inclusive, except472 and478 with nativeFFFF data-pointer sentinels",
    "nmiHandler": "u24[006E] ==80C281",
    "dynamicPlayer": "slot=u16[0CC2], even0..0056; u16[150A+slot]==08A4; u16[2FB0]==08A4; u16[1038+slot]!=FFFF",
    "control": "u16[1D53]==FFFF; nativeCA/80CE34 reads it and80CE29 disables it; room loader80A6D0..DA gates it during initialization",
    "visible": "u16[01C0]==000F; u16[01CC]==0000",
    "menusAndDialogue": "u16[0208]==FFFE; u16[0254]==0000; words021C/021E/0220/0222 allFFFF",
    "noPendingTransition": "u16[1CDB]==FFFF",
    "ownedForUse": "u16[3059]==08A4",
    "qualification": "Source-bounded normal-field eligibility, not a claim that every one of496 original entries was played through."
  },
  "courtyardEntries": [
    1,
    13,
    14,
    16,
    416,
    417,
    418,
    419
  ],
  "queueSemantics": {
    "entryWord": "2FA2 is the current original room ENTRY, overwritten immediately by a native5C request.",
    "queueWord": "1CDB is a pending loader request, not an independent currently rendered room ID.",
    "enterHidden": "Save the exact stable origin2FA2 entry in enhancement metadata, set2FA2=210 and1CDB=7FFF.",
    "return": "From stable hidden entry210, queue the saved exact original entry. Preserve aliases rather than returning every trip to1.",
    "spawn": "The native loader uses that entrance record's XYZ and facing; it does not return to the exact previous standing position.",
    "source": [
      "80CD1D native5C writes2FA2 and1CDB=7FFF.",
      "80A5C5 indexes entry*9 at8D977E.",
      "80A639..A655 loads entry flags/XYZ beforeA400 spawns Jake."
    ],
    "forbidden": "Do not call helper285, restore a research state into a user session, or write additional coordinates, quest flags, stats or inventory."
  },
  "metadata": {
    "envelope": "Existing cosom-shadowrun-original-state-v1 envelope and original storage namespace retained.",
    "guideV1": "{version:1,unlocked:boolean} remains accepted; no origin was recorded by v1.",
    "guideV2": "{version:2,unlocked:boolean,returnEntry?:integer}; returnEntry validated against496 entries and must not equal210.",
    "legacyHiddenFallback": "A v1 hidden-room snapshot has no recoverable prior origin; explicitly label its fallback to courtyard entry1.",
    "restore": "Explicit restore replaces enhancement state; absent/invalid metadata cannot reuse a later transient return entry. Paused core loads queue until resuming, so retain imported metadata until that load settles.",
    "nativeRunBoundary": "Preserve established unlock behavior, per parent scope decision; no new native-new/load reset feature is claimed by this bugfix. Clear stale transient return origin once outside hidden room or on explicit metadata replacement."
  },
  "verification": {
    "helperTestsPassed": 8,
    "actualPinnedFixtureImportTests": 4,
    "pinnedNativeBootWithoutResearchStateImport": true,
    "pinnedSuccessfulOriginEntries": [
      58,
      69,
      13,
      14,
      419
    ],
    "unchangedEntityStateRecordsComparedPerTrip": 701,
    "statsRange": "3DB0..3DDF",
    "storyAndPartyWords": [
      "2FA4",
      "2FA6"
    ],
    "productionFieldVectors": 520,
    "productionProjectionVectors": 321,
    "productionGuideSha256": "4d19dc3f4a9ee17ababc704bade1d138b451f1d0ddf4f859a45a8edc93af2d2e",
    "unchangedBridgeSha256": "8ad6968da3c32e8cfbbc8bce6ea8d6086b8dc887e80af901295b63d9c9fe3a21",
    "browserAndPhysicalController": "Separate root/browser validation; these source tests do not establish physical wireless/HID operation or a completed campaign."
  },
  "sourceReceiptSha256": "d3c6f7f3a0d9b60e166411edeb3422e8adfb08f02560516e0e3f49c0141f80cd",
  "uiProofSha256": "4871324f7fe05534ed40652d628719e71187de0c9b55e4c99510d79761185668",
  "browserProofSha256": "d05158b94c5530a1eb7d7889c89c1a6d58a2f544fe574a290b339fb3b3be35f4",
  "browserVerification": "Actual browser portrait/grant/use, native hidden entry210 and origin returns, v2 hidden snapshot reload, legacyv1 interior entry3, menu refusal and ordinary walk to entry232 with persistent Use. Physical controller buttons and a complete campaign are not claimed.",
  "presentation": "Recovered sprite, portrait and bitmap font with new English browser dialogue; this is an optional overlay, not a ROM-inserted native NPC or collision actor.",
  "controller": "Uses the original input driver’s assigned Player1 and configured SNES button/axis labels, with edge/neutral release gating. Keyboard G talks; M uses or returns.",
  "limitations": [
    "Return requests the captured original entrance, using its native spawn/facing, not the exact previous standing tile.",
    "Oldv1 hidden snapshots have no recorded origin and explicitly fall back to courtyard entry1.",
    "Source guards support normal ready gameplay; title/loading/menu/dialogue/fade/busy states refuse the shortcut. Every original room and full campaign have not been played through.",
    "Existing native-new/load unlock behavior is retained; this fix does not introduce a new run-reset policy."
  ]
}
