From 9aed9cc268640a201222745577f5039e654ab7a8 Mon Sep 17 00:00:00 2001 From: ZeoStudio <2269627154@qq.com> Date: Sun, 25 Oct 2026 09:06:22 +0800 Subject: [PATCH 1/3] [AGENT-DROP] game-agent: R3 Monogatari iOS15 range-parser source and verification contract --- .../FILES/Tools/VNPort/tests/swift/main.swift | 25 ++++++ .../Narrative/VeilMonogatariByteRange.swift | 42 ++++++++++ .../20261025-monogatari-ios15-r3/MANIFEST.md | 11 +++ .../20261025-monogatari-ios15-r3/PATCH.diff | 77 +++++++++++++++++++ .../20261025-monogatari-ios15-r3/PROPOSAL.md | 10 +++ .../20261025-monogatari-ios15-r3/RISKS.md | 7 ++ .../SOURCE_RECEIPT.md | 4 + .../20261025-monogatari-ios15-r3/TEST_PLAN.md | 7 ++ 8 files changed, 183 insertions(+) create mode 100644 AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/FILES/Tools/VNPort/tests/swift/main.swift create mode 100644 AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/FILES/VeilLink/Narrative/VeilMonogatariByteRange.swift create mode 100644 AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/MANIFEST.md create mode 100644 AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/PATCH.diff create mode 100644 AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/PROPOSAL.md create mode 100644 AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/RISKS.md create mode 100644 AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/SOURCE_RECEIPT.md create mode 100644 AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/TEST_PLAN.md diff --git a/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/FILES/Tools/VNPort/tests/swift/main.swift b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/FILES/Tools/VNPort/tests/swift/main.swift new file mode 100644 index 00000000..0dd619ef --- /dev/null +++ b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/FILES/Tools/VNPort/tests/swift/main.swift @@ -0,0 +1,25 @@ +import Foundation + +func check(_ header: String?, _ length: Int, _ start: Int?, _ end: Int?) { + let actual = VeilNovelRangeParser.resolve(header, fileLength: length) + if let start = start, let end = end { + precondition(actual?.first == start, "bad start for \(header ?? "nil")") + precondition(actual?.last == end, "bad end for \(header ?? "nil")") + } else { precondition(actual == nil, "expected rejection: \(header ?? "nil")") } +} +check(nil, 100, 0, 99) +check("bytes=0-0", 100, 0, 0) +check("bytes=13-", 100, 13, 99) +check("bytes=-10", 100, 90, 99) +check("bytes=-999", 100, 0, 99) +check("bytes=90-300", 100, 90, 99) +check("bytes=99-99", 100, 99, 99) +check("bytes=100-", 100, nil, nil) +check("bytes=12-11", 100, nil, nil) +check("bytes=1-2,3-4", 100, nil, nil) +check("bytes=1-xyz", 100, nil, nil) +check("bytes=18446744073709551616-", 100, nil, nil) +check("bytes=-0", 100, nil, nil) +check("BYTES=1-5", 100, nil, nil) +check(nil, 0, nil, nil) +print("PASS: 15 Swift Foundation range-parser cases") diff --git a/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/FILES/VeilLink/Narrative/VeilMonogatariByteRange.swift b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/FILES/VeilLink/Narrative/VeilMonogatariByteRange.swift new file mode 100644 index 00000000..924b993d --- /dev/null +++ b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/FILES/VeilLink/Narrative/VeilMonogatariByteRange.swift @@ -0,0 +1,42 @@ +import Foundation + +/// RFC 7233 single-byte-range subset for a read-only local bundle server. +/// Deliberately rejects multiple/ambiguous ranges rather than guessing. +struct VeilNovelResolvedByteRange: Equatable { + let first: Int + let last: Int // inclusive + let fullLength: Int + + var count: Int { last - first + 1 } + var contentRange: String { "bytes \(first)-\(last)/\(fullLength)" } +} + +enum VeilNovelRangeParser { + static func resolve(_ header: String?, fileLength: Int) -> VeilNovelResolvedByteRange? { + guard fileLength > 0 else { return nil } + guard let header = header else { + return VeilNovelResolvedByteRange(first: 0, last: fileLength - 1, fullLength: fileLength) + } + let value = header.trimmingCharacters(in: .whitespaces) + guard value.hasPrefix("bytes="), !value.contains(",") else { return nil } + let spec = String(value.dropFirst(6)) + let parts = spec.split(separator: "-", omittingEmptySubsequences: false) + guard parts.count == 2 else { return nil } + func digits(_ s: Substring) -> Int? { + guard !s.isEmpty, s.utf8.allSatisfy({ $0 >= 48 && $0 <= 57 }) else { return nil } + return Int(s) + } + if parts[0].isEmpty { + guard let suffix = digits(parts[1]), suffix > 0 else { return nil } + return VeilNovelResolvedByteRange(first: max(0, fileLength - suffix), last: fileLength - 1, fullLength: fileLength) + } + guard let first = digits(parts[0]), first < fileLength else { return nil } + let end: Int + if parts[1].isEmpty { end = fileLength - 1 } + else { + guard let explicit = digits(parts[1]), explicit >= first else { return nil } + end = min(explicit, fileLength - 1) + } + return VeilNovelResolvedByteRange(first: first, last: end, fullLength: fileLength) + } +} diff --git a/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/MANIFEST.md b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/MANIFEST.md new file mode 100644 index 00000000..0b264f9c --- /dev/null +++ b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/MANIFEST.md @@ -0,0 +1,11 @@ +# R3 Inbox manifest +- agent_id: game-agent +- task_id: 20261025-monogatari-ios15-r3 +- base_main_sha: 501ef814a0a9bea41419fe2d9f48315371b30320 +- submission_path: AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/ +- mode: INBOX_ONLY +- actual_status: OWNER_PACKAGE_COMPLETED; GITHUB_PARTIAL_SOURCE_STAGING_ONLY +- complete_owner_package: VeilLink_Monogatari_OfficialFullEngine_R3_20261025.zip (5,636,992 bytes) +- complete_owner_package_sha256: 840270de26bcf53ea1f8fe68e4d8ec717ae610d289c1de6dfa7573c59bd2cd09 +- upstream ZIP sha256: 16d221485888b0193312e9989ecafa57cb1913978bf2f09ba554552ba3885806 +- no product/main/release/ipa action: true diff --git a/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/PATCH.diff b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/PATCH.diff new file mode 100644 index 00000000..9bb94c5f --- /dev/null +++ b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/PATCH.diff @@ -0,0 +1,77 @@ +diff --git a/VeilLink/Narrative/VeilMonogatariByteRange.swift b/VeilLink/Narrative/VeilMonogatariByteRange.swift +new file mode 100644 +--- /dev/null ++++ b/VeilLink/Narrative/VeilMonogatariByteRange.swift +@@ -0,0 +1,42 @@ ++import Foundation ++ ++/// RFC 7233 single-byte-range subset for a read-only local bundle server. ++/// Deliberately rejects multiple/ambiguous ranges rather than guessing. ++struct VeilNovelResolvedByteRange: Equatable { ++ let first: Int ++ let last: Int // inclusive ++ let fullLength: Int ++ ++ var count: Int { last - first + 1 } ++ var contentRange: String { "bytes \(first)-\(last)/\(fullLength)" } ++} ++ ++enum VeilNovelRangeParser { ++ static func resolve(_ header: String?, fileLength: Int) -> VeilNovelResolvedByteRange? { ++ guard fileLength > 0 else { return nil } ++ guard let header = header else { ++ return VeilNovelResolvedByteRange(first: 0, last: fileLength - 1, fullLength: fileLength) ++ } ++ let value = header.trimmingCharacters(in: .whitespaces) ++ guard value.hasPrefix("bytes="), !value.contains(",") else { return nil } ++ let spec = String(value.dropFirst(6)) ++ let parts = spec.split(separator: "-", omittingEmptySubsequences: false) ++ guard parts.count == 2 else { return nil } ++ func digits(_ s: Substring) -> Int? { ++ guard !s.isEmpty, s.utf8.allSatisfy({ $0 >= 48 && $0 <= 57 }) else { return nil } ++ return Int(s) ++ } ++ if parts[0].isEmpty { ++ guard let suffix = digits(parts[1]), suffix > 0 else { return nil } ++ return VeilNovelResolvedByteRange(first: max(0, fileLength - suffix), last: fileLength - 1, fullLength: fileLength) ++ } ++ guard let first = digits(parts[0]), first < fileLength else { return nil } ++ let end: Int ++ if parts[1].isEmpty { end = fileLength - 1 } ++ else { ++ guard let explicit = digits(parts[1]), explicit >= first else { return nil } ++ end = min(explicit, fileLength - 1) ++ } ++ return VeilNovelResolvedByteRange(first: first, last: end, fullLength: fileLength) ++ } ++} +diff --git a/Tools/VNPort/tests/swift/main.swift b/Tools/VNPort/tests/swift/main.swift +new file mode 100644 +--- /dev/null ++++ b/Tools/VNPort/tests/swift/main.swift +@@ -0,0 +1,25 @@ ++import Foundation ++ ++func check(_ header: String?, _ length: Int, _ start: Int?, _ end: Int?) { ++ let actual = VeilNovelRangeParser.resolve(header, fileLength: length) ++ if let start = start, let end = end { ++ precondition(actual?.first == start, "bad start for \(header ?? "nil")") ++ precondition(actual?.last == end, "bad end for \(header ?? "nil")") ++ } else { precondition(actual == nil, "expected rejection: \(header ?? "nil")") } ++} ++check(nil, 100, 0, 99) ++check("bytes=0-0", 100, 0, 0) ++check("bytes=13-", 100, 13, 99) ++check("bytes=-10", 100, 90, 99) ++check("bytes=-999", 100, 0, 99) ++check("bytes=90-300", 100, 90, 99) ++check("bytes=99-99", 100, 99, 99) ++check("bytes=100-", 100, nil, nil) ++check("bytes=12-11", 100, nil, nil) ++check("bytes=1-2,3-4", 100, nil, nil) ++check("bytes=1-xyz", 100, nil, nil) ++check("bytes=18446744073709551616-", 100, nil, nil) ++check("bytes=-0", 100, nil, nil) ++check("BYTES=1-5", 100, nil, nil) ++check(nil, 0, nil, nil) ++print("PASS: 15 Swift Foundation range-parser cases") diff --git a/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/PROPOSAL.md b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/PROPOSAL.md new file mode 100644 index 00000000..e6d6fd13 --- /dev/null +++ b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/PROPOSAL.md @@ -0,0 +1,10 @@ +# Full official Monogatari v2.8.0: iOS15 reliability R3 +Owner requested additional optimization after R2 full upstream binary import. +This PR stages an actual **Foundation byte-range parser** plus 15-scenario executable test in FILES/PATCH.diff. +The complete user-facing R3 ZIP contains remaining modified **native SwiftUI/WebKit source, full unmodified upstream engine, source vendor, 94-file package**, original official release ZIP, iOS host adapter and all validation programs. Those additional sources and binary assets are **not** stored in this GitHub Inbox proposal, and must be ingested separately by Governor. + +R3 candidate improvements: 256-KiB bounded asset streaming, single Range 206 / invalid 416, path+size guards, WebContent process termination manual recovery, init-failure handling, current-session LocalStorage availability warning, de-duplicate/allowlist JS->native messages, disable debug JS execution (while retaining debug.js bytes) and disable eager preload. + +Current tests: exact official archive 2,798,775 bytes SHA match, 56 source files retained, all 12 upstream engine blobs unchanged, 15 Swift Foundation range tests PASS, 19 story nodes / 4 endings PASS, bridge+error tests PASS, fake integration checkout dry-run/apply PASS, source-only patch apply check PASS. Not Apple SDK or physical device tests. + +Priority: Resolve iPhone7 P0 touch/signing and #64 #65 #66 before product promotion. No direct change to chat/SQLite/Keychain/BLE/wire/A9/A10. diff --git a/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/RISKS.md b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/RISKS.md new file mode 100644 index 00000000..18d90ad0 --- /dev/null +++ b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/RISKS.md @@ -0,0 +1,7 @@ +# R3 risk review +- The GITHUB submission is intentionally partial (ByteRange parser and its tests plus contract); full binary/Swift host sources remain in owner's exact ZIP, **not merged**. +- On iOS15 custom WKURLSchemeHandler may have different Range/cancellation/AVFoundation behavior than simulated; HTTPURLResponse on non-http schemes untested with Apple SDK. +- Custom-origin localStorage probe only tests current-session write/read, not storage durability across relaunch; no false persisted-save guarantee. +- iOS SDK Swift/WebKit typecheck and iPhone7 playback, memory, touch and process-recovery tests are still pending. +- GameLobby/project.yml changes overlap existing other feature lanes; Governor only decides integration order. +- Do not modify main, workflows, signing, identity, BLE, database or releases; no IPA dispatch. diff --git a/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/SOURCE_RECEIPT.md b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/SOURCE_RECEIPT.md new file mode 100644 index 00000000..68f1c01b --- /dev/null +++ b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/SOURCE_RECEIPT.md @@ -0,0 +1,4 @@ +# R3 source availability and truth boundary +Official complete user's uploaded ZIP was verified at SHA256 16d221485888b0193312e9989ecafa57cb1913978bf2f09ba554552ba3885806. +The generated exact owner R3 ZIP (SHA256 840270de26bcf53ea1f8fe68e4d8ec717ae610d289c1de6dfa7573c59bd2cd09) contains full upstream and all optimized candidate files. This PR contains only a source-subset plus required Inbox proposal paperwork; ZIP is not in GitHub due Inbox binary restrictions. +Evidence: Linux Swift Foundation test 15 PASS, source patch git apply --check PASS, official upstream 12/12 unchanged, Node checks of 4 endings + JS bridge PASS, mock integration 63 files dry-run and isolated apply PASS. **No iPhone7 runtime test.** diff --git a/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/TEST_PLAN.md b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/TEST_PLAN.md new file mode 100644 index 00000000..6c8817f5 --- /dev/null +++ b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/TEST_PLAN.md @@ -0,0 +1,7 @@ +# Acceptance tests +1. Verify official ZIP SHA256 `16d221485888b0193312e9989ecafa57cb1913978bf2f09ba554552ba3885806`; all 12 engine files untouched. +2. Run `swiftc VeilLink/Narrative/VeilMonogatariByteRange.swift Tools/VNPort/tests/swift/main.swift -o /tmp/vnrange && /tmp/vnrange` (15 cases). +3. Independently extract user-provided R3 ZIP after matching SHA256, review complete host Swift, JS, and real vendor tree; do not treat this PR as shipping the complete game. +4. On isolated integration branch: add full source+resources, check XcodeGen **folder** Copy Resources layout, iOS15 build and XCTest. +5. On iPhone7/iOS15.8.3: storage across relaunch; normal/ranged media requests; memory, tap and crash/reload tests; dark/light and VoiceOver. +6. No IPA or main promotion until Governor P0 gates and owner release authorization. From 45842ea6d3fc128e9170c6d81f38a31ebe12ff3d Mon Sep 17 00:00:00 2001 From: ZeoStudio <2269627154@qq.com> Date: Sun, 25 Oct 2026 10:49:18 +0800 Subject: [PATCH 2/3] [AGENT-DROP] R4 addendum: preserve full engine and stage iOS15 compatibility shim --- .../overlays/js/veillink-ios15-compat.js | 33 ++++++++++++++++ .../R4_ADDENDUM.md | 33 ++++++++++++++++ .../R4_PATCH.diff | 38 +++++++++++++++++++ 3 files changed, 104 insertions(+) create mode 100644 AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/FILES/Tools/VNPort/overlays/js/veillink-ios15-compat.js create mode 100644 AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/R4_ADDENDUM.md create mode 100644 AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/R4_PATCH.diff diff --git a/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/FILES/Tools/VNPort/overlays/js/veillink-ios15-compat.js b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/FILES/Tools/VNPort/overlays/js/veillink-ios15-compat.js new file mode 100644 index 00000000..9258f136 --- /dev/null +++ b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/FILES/Tools/VNPort/overlays/js/veillink-ios15-compat.js @@ -0,0 +1,33 @@ +/* Monogatari v2.8.0 compatibility shim for iOS 15 WKWebView custom/file origins. + Engine files remain byte-for-byte identical to the official distribution. */ +(function () { + 'use strict'; + if (typeof Object.hasOwn !== 'function') { + Object.hasOwn = function (object, key) { + return Object.prototype.hasOwnProperty.call(Object(object), key); + }; + } + var rng = window.crypto; + if (rng && typeof rng.randomUUID !== 'function' && typeof rng.getRandomValues === 'function') { + // randomUUID() may be withheld in non-secure custom-scheme origins. + // Use only the platform's cryptographic random generator; never Math.random. + try { + Object.defineProperty(rng, 'randomUUID', { + configurable: true, + value: function () { + var bytes = new Uint8Array(16); + rng.getRandomValues(bytes); + bytes[6] = (bytes[6] & 15) | 64; + bytes[8] = (bytes[8] & 63) | 128; + var hex = []; + for (var i = 0; i < 16; i++) hex.push(bytes[i].toString(16).padStart(2, '0')); + return hex.slice(0, 4).join('') + '-' + hex.slice(4, 6).join('') + '-' + + hex.slice(6, 8).join('') + '-' + hex.slice(8, 10).join('') + '-' + + hex.slice(10).join(''); + } + }); + } catch (_) { + // If the host object is immutable, let the engine report the unsupported origin. + } + } +})(); diff --git a/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/R4_ADDENDUM.md b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/R4_ADDENDUM.md new file mode 100644 index 00000000..b88f9342 --- /dev/null +++ b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/R4_ADDENDUM.md @@ -0,0 +1,33 @@ +# Monogatari R4 Playability Compatibility Addendum — 2026-10-25 + +This is an update to **the same Game Agent R3 Inbox lane**. It is not a functional merged game, not an IPA, and must not be self-merged. + +## Complete owner-delivered candidate +- Artifact: `VeilLink_Monogatari_Playability_R4_20261025.zip` (in the current ChatGPT conversation). +- ZIP bytes: **5,674,020**; SHA-256: `8a0b419d5184edbb41c99ab0cfc4935b14125ced586e2c200c5bd747d18dfa72`. +- 111 archive entries; original official ZIP SHA-256 `16d221485888b0193312e9989ecafa57cb1913978bf2f09ba554552ba3885806`; entire upstream `engine/` subtree remains unmodified. +- Full R4 SwiftUI host, scripts, CSS, optional file loading mode, test suites and tools are in that **user-facing ZIP**, not all in this PR. + +## Actual new code staged in GitHub +- `FILES/Tools/VNPort/overlays/js/veillink-ios15-compat.js`: executable additive Safari/WebKit origin compatibility polyfill for missing `crypto.randomUUID` and `Object.hasOwn`, never using Math.random. +- `R4_PATCH.diff`: proposed add-only source patch for this shim. Governor may accept after review. + +## Other improvements only in the full owner ZIP +1. Native WKWebView manual `loadFileURL(_:allowingReadAccessTo:)` fallback when custom-scheme navigation/init fails; file and custom scheme may have separate save namespaces. +2. 20-second startup deadline, explicit user reload, stale coordinator event invalidation. +3. JS native notification bridge is loaded before JS main init; compatibility shim before official engine. +4. Small-screen touch targets, keyboard focus and reduce-motion style overlay. +5. XcodeGen nested `type: folder` reference check and conservative optional repair for **generated .pbxproj**. +6. Reproducible genuine ZIP reimport (60 game files), negative integrity tests and corrected movable integration tests. + +## Local validation achieved +- True official release ZIP SHA256 PASS; 56 upstream files present; 12 engine binaries byte-for-byte PASS. +- All 60 regenerated game files match R4 candidate; 19 nodes/3 choices/4 endings story graph. +- 15 Swift byte-range tests, 5 PBX path fixtures, JS bridge/launch-order/UUID shims, mock integration dry run/apply/reapply rejection PASS. +- Swift parser only; NOT Apple SDK SwiftUI typecheck. +- Browser smoke attempt blocked by execution environment's administrator policy. NO iPhone 7 device runtime, offline save/restore, touch or audio test has run. + +## Hard acceptance gates +Prioritize #64/#65/#66 iOS15 startup/gesture/data P0. On a separate Governor integration branch ingest **verified complete owner ZIP**, inspect XcodeGen compiled .app folder tree, run macOS iOS15/XCTest and physical iPhone7 dark/light/gesture/save/relaunch/branch/media validation. DO NOT merge main, change signing/version, or dispatch IPA Action until gates pass and owner authorizes release. + +**Status: SOURCE CANDIDATE VERIFIED; FULL GAME PLAYABILITY UNCONFIRMED.** diff --git a/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/R4_PATCH.diff b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/R4_PATCH.diff new file mode 100644 index 00000000..9cb62f43 --- /dev/null +++ b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/R4_PATCH.diff @@ -0,0 +1,38 @@ +diff --git a/Tools/VNPort/overlays/js/veillink-ios15-compat.js b/Tools/VNPort/overlays/js/veillink-ios15-compat.js +new file mode 100644 +--- /dev/null ++++ b/Tools/VNPort/overlays/js/veillink-ios15-compat.js +@@ -0,0 +1,33 @@ ++/* Monogatari v2.8.0 compatibility shim for iOS 15 WKWebView custom/file origins. ++ Engine files remain byte-for-byte identical to the official distribution. */ ++(function () { ++ 'use strict'; ++ if (typeof Object.hasOwn !== 'function') { ++ Object.hasOwn = function (object, key) { ++ return Object.prototype.hasOwnProperty.call(Object(object), key); ++ }; ++ } ++ var rng = window.crypto; ++ if (rng && typeof rng.randomUUID !== 'function' && typeof rng.getRandomValues === 'function') { ++ // randomUUID() may be withheld in non-secure custom-scheme origins. ++ // Use only the platform's cryptographic random generator; never Math.random. ++ try { ++ Object.defineProperty(rng, 'randomUUID', { ++ configurable: true, ++ value: function () { ++ var bytes = new Uint8Array(16); ++ rng.getRandomValues(bytes); ++ bytes[6] = (bytes[6] & 15) | 64; ++ bytes[8] = (bytes[8] & 63) | 128; ++ var hex = []; ++ for (var i = 0; i < 16; i++) hex.push(bytes[i].toString(16).padStart(2, '0')); ++ return hex.slice(0, 4).join('') + '-' + hex.slice(4, 6).join('') + '-' + ++ hex.slice(6, 8).join('') + '-' + hex.slice(8, 10).join('') + '-' + ++ hex.slice(10).join(''); ++ } ++ }); ++ } catch (_) { ++ // If the host object is immutable, let the engine report the unsupported origin. ++ } ++ } ++})(); From b021d0517fcb8f2d4c12535eaca022799f2cbe38 Mon Sep 17 00:00:00 2001 From: ZeoStudio <2269627154@qq.com> Date: Sun, 25 Oct 2026 13:13:42 +0800 Subject: [PATCH 3/3] [AGENT-DROP] R5 startup, storage continuity evidence and reviewed JS glue --- .../FILES/Tools/VNPort/overlays/js/main-r5.js | 16 ++++++++ .../VNPort/overlays/js/veillink-native.js | 39 +++++++++++++++++++ .../R5_ADDENDUM.md | 27 +++++++++++++ 3 files changed, 82 insertions(+) create mode 100644 AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/FILES/Tools/VNPort/overlays/js/main-r5.js create mode 100644 AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/FILES/Tools/VNPort/overlays/js/veillink-native.js create mode 100644 AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/R5_ADDENDUM.md diff --git a/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/FILES/Tools/VNPort/overlays/js/main-r5.js b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/FILES/Tools/VNPort/overlays/js/main-r5.js new file mode 100644 index 00000000..c2c8eb3a --- /dev/null +++ b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/FILES/Tools/VNPort/overlays/js/main-r5.js @@ -0,0 +1,16 @@ +'use strict'; +/* global Monogatari, monogatari */ +const { $_ready, $_ } = Monogatari; +$_ready (() => { + try { + Promise.resolve(monogatari.init('#monogatari')) + .then(function () { + window.VeilNovelHost && window.VeilNovelHost.notify('ready'); + }) + .catch(function () { + window.VeilNovelHost && window.VeilNovelHost.notify('init-failed'); + }); + } catch (_) { + window.VeilNovelHost && window.VeilNovelHost.notify('init-failed'); + } +}); diff --git a/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/FILES/Tools/VNPort/overlays/js/veillink-native.js b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/FILES/Tools/VNPort/overlays/js/veillink-native.js new file mode 100644 index 00000000..adf4f862 --- /dev/null +++ b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/FILES/Tools/VNPort/overlays/js/veillink-native.js @@ -0,0 +1,39 @@ +// R5: notification-only bridge; persistent-origin witness never reads game saves. +(function () { + 'use strict'; + var allowed = Object.freeze({ + ready: true, error: true, 'init-failed': true, 'storage-unavailable': true, + 'storage-probe-created': true, 'storage-probe-retained': true + }); + var sent = Object.create(null); + var bridge = window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.veilNovel; + function notify(type) { + if (!Object.prototype.hasOwnProperty.call(allowed, type) || sent[type]) return; + sent[type] = true; + if (bridge && typeof bridge.postMessage === 'function') { + try { bridge.postMessage({ type: type }); } catch (_) { /* web preview has no native bridge */ } + } + } + Object.defineProperty(window, 'VeilNovelHost', { + value: Object.freeze({ protocolVersion: 3, notify: notify }), + configurable: false, writable: false + }); + // Separate sentinel, not a Monogatari save key. This tests same-origin + // availability and allows the native host to compare across later launches. + try { + var storage = window.localStorage; + var healthKey = '__veilnovel_storage_probe_r5'; + if (storage.getItem(healthKey) === 'veilnovel-v1') { + notify('storage-probe-retained'); + } else { + storage.setItem(healthKey, 'veilnovel-v1'); + if (storage.getItem(healthKey) === 'veilnovel-v1') { + notify('storage-probe-created'); + } else { + notify('storage-unavailable'); + } + } + } catch (_) { notify('storage-unavailable'); } + window.addEventListener('error', function () { notify('error'); }); + window.addEventListener('unhandledrejection', function () { notify('error'); }); +})(); diff --git a/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/R5_ADDENDUM.md b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/R5_ADDENDUM.md new file mode 100644 index 00000000..1bcea345 --- /dev/null +++ b/AGENT_INBOX/submissions/game-agent/20261025-monogatari-ios15-r3/R5_ADDENDUM.md @@ -0,0 +1,27 @@ +# R5 PLAYABILITY HARDENING — 2026-10-25 + +**Verified owner-facing complete package:** `VeilLink_Monogatari_Playability_R5_20261025.zip` +- exact size **5,697,469 bytes** +- SHA-256 `068ba55bfa36672d61960240a684dc4d90ceb7a10868409baf73bc4e6ac6c6f1` +- 115 packaged files; 114 per-file SHA256SUMS entries validated. +- upstream `monogatari-v2.8.0.zip` verified SHA256 `16d221485888b0193312e9989ecafa57cb1913978bf2f09ba554552ba3885806` and **12/12 pristine upstream engine files**. + +## Actual R5 fixes in owner's ZIP +1. Load native error bridge **before** the official engine, so boot exceptions aren't invisible. +2. Monogatari init Promise: catch both direct synchronous throw and rejected async result. +3. Independent `localStorage` witness keyed only to VN application metadata; per-origin native UserDefaults expectation warns if the marker disappears. Never reads, rewrites, imports or deletes actual Monogatari saved games. A marker surviving **does not prove actual saved-game durability**. +4. Verify both essential JS glue files exist before game navigation; handle post-commit WebKit navigation failures as well as provisional errors. +5. Keep complete upstream engine unmodified and preserve explicit dual loading modes, no automatic cross-origin migration. + +## Executed local tests +- 5 Python R4 regression suites PASS +- 5 Node suites including R5 bridge + 3 init outcomes PASS +- 15 Swift Foundation Range cases PASS; Swift iOS sources **syntax parsed only** +- real vendor ZIP rebuilt into 60 bit-identical game files PASS +- game graph 19 nodes, 3 choices, 4 endings and 36 states PASS +- git apply --check / whitespace=error for complete source-only candidate patch PASS +- Browser was **BLOCKED_BY_ADMINISTRATOR** for localhost, data:, and file: URLs: **no game UI/interaction run**. +- **No macOS iOS15 build, XCTest with Apple SDK, physical iPhone7 gameplay or real save/load after force-quit.** + +## Governance and completeness +This Draft PR only stages **text-only partial source + auditable receipt**. Complete modified SwiftUI/WebKit host, full vendor and JS sources and binaries are in exact owner's R5 ZIP, NOT in this PR. Governor must verify/import the ZIP on an isolated integration branch, reconcile P0 #64/#65/#66 touch/signing/data continuity, XcodeGen bundle resource structure, build full Apple iOS15/XCTest, and conduct physical iPhone7 validation. **Do not merge main or dispatch IPA/release.**