Bab 6: Log Keputusan Arsitektur (ADR-001 s/d ADR-076)

ADR adalah singkatan dari Architecture Decision Record β€” catatan keputusan arsitektur. Setiap kali tim membuat pilihan desain penting untuk aplikasi mancing "CtSPoC" (Catch the Scott), keputusan itu ditulis sebagai satu entri bernomor: apa yang diputuskan, kenapa, dan apa akibatnya. Aplikasi ini terdiri dari dua perangkat β€” Rod (iPhone, sebagai pengendali fisik) dan World (macOS, mesin permainan dan perenderan) β€” yang saling berbicara lewat satu paket Swift bernama Shared.

Log ini penting dibaca urut per tema, bukan per nomor, karena banyak keputusan awal direvisi atau bahkan dibatalkan total oleh keputusan yang lebih baru. Kalau dibaca lompat-lompat per nomor, pembaca bisa salah kira sebuah aturan lama masih berlaku padahal sudah diganti. Total ada 76 ADR (ADR-001 sampai ADR-076). Catatan: log ini tidak punya tanggal kalender β€” urutan hanya berdasarkan nomor ADR (makin besar nomornya, makin baru), dengan referensi silang ke dokumen terpisah CHECKPOINT.md.

1. Fondasi Arsitektur β€” "konstitusi" proyek (ADR-001 s/d ADR-021)

Kelompok ini berisi aturan pendek yang dibuat di awal proyek dan tidak pernah dibatalkan. Semua ADR sesudahnya dibangun di atas aturan-aturan ini.

  • ADR-001 β€” Pemisahan World/Rod. Proyek dipecah jadi dua aplikasi independen: World (perender di macOS) dan Rod (pengendali di iPhone). Alasan: perender dan pengendali punya tanggung jawab berbeda β€” lebih mudah dites, bisa dirilis terpisah, dan pengendalinya bisa dipakai ulang untuk game lain.
  • ADR-002 β€” Paket Swift Bersama (Shared). Semua model/protokol yang dipakai bersama diletakkan dalam satu paket Shared, supaya World dan Rod memakai model data yang sama persis dan tidak ada duplikasi.
  • ADR-003 β€” RodState Sebagai Satu-satunya Sumber Kebenaran. Satu model (RodState) mewakili seluruh info dari pengendali; kode gameplay/render hanya boleh membaca dari model ini, tidak boleh ada state gerakan duplikat di tempat lain.
  • ADR-004 β€” Pemisahan Data Gerakan dan Data Spasial. Data dari CoreMotion (pitch/roll/yaw) dan dari Nearby Interaction (jarak/arah) dijaga tetap terpisah; RodState menggabungkan keduanya jadi satu.
  • ADR-005 β€” RealityKit Hanya Ada di World. Semua urusan render adalah milik World; Rod sama sekali tidak merender apa pun.
  • ADR-006 β€” Rod Tidak Boleh Bergantung pada Reality. Rod tidak boleh sama sekali meng-import RealityKit atau ARKit β€” perannya cuma sensor dan input.
  • ADR-007 β€” Shared Harus Independen dari Platform. Paket Shared hanya boleh meng-import Foundation β€” tidak boleh SwiftUI, RealityKit, CoreMotion, NearbyInteraction, CoreHaptics, UIKit, atau AppKit. Aturan ini terus dikutip di ADR-ADR berikutnya (misalnya ADR-033, ADR-049).
  • ADR-008 β€” Pola MVVM. Tampilan (View) harus pasif; logika bisnis diletakkan di ViewModel/Manager.
  • ADR-009 β€” Komposisi Lebih Diutamakan daripada Pewarisan. Lebih suka pakai komposisi/protokol daripada hierarki pewarisan (inheritance) yang dalam.
  • ADR-010 β€” Pengiriman Bertahap. Tiap sprint harus bisa dibangun, dijalankan, dan diuji; tidak boleh ada sprint yang bergantung pada pekerjaan yang belum selesai.
  • ADR-011 β€” Gameplay Ditunda. Urutan prioritas eksplisit: sesi spasial β†’ gerakan β†’ sinkronisasi β†’ visualisasi Reality β†’ pengenalan gestur β†’ gameplay (mekanik memancing sengaja ditunda ke belakang).
  • ADR-012 β€” Utamakan API Apple. Utamakan SDK Apple versi stabil terbaru (Nearby Interaction, RealityKit, CoreMotion, CoreHaptics, Swift Concurrency); hindari API yang sudah usang.
  • ADR-013 β€” Keterikatan Longgar (Loose Coupling). World dan Rod hanya boleh berkomunikasi lewat kontrak bersama (tidak boleh ada ketergantungan langsung World ke Rod atau sebaliknya).
  • ADR-014 β€” Kepemilikan Sesi Nearby Interaction (NI). Rod yang memegang sesi NI (karena SDK macOS menandai NISession tidak tersedia di macOS); World hanya menerima hasil data spasialnya lewat RodState. Kedua proyek tidak boleh saling import. Catatan status belakangan: aturan kepemilikan ini tetap benar, tapi lihat ADR-041 di bawah β€” ternyata data spasial dari NI ini tidak benar-benar dipakai oleh gameplay, hanya tampil di UI debug.
  • ADR-015 β€” Pengendali Spasial yang Bisa Dipakai Ulang. Dinyatakan secara eksplisit bahwa tujuan jangka panjang proyek BUKAN sekadar game mancing, tapi kerangka kerja "pengendali spasial" yang bisa dipakai ulang (raket tenis, tongkat bisbol, tongkat golf, pedang, dll) β€” mancing hanyalah pemakai pertama.
  • ADR-016 β€” Orientasi Dimiliki oleh Kalibrasi. Proses kalibrasi (di lapisan gerakan Rod/Shared) menangkap dan menyimpan satu quaternion referensi saat diam, lalu menerapkan kebalikannya ke orientasi langsung (live), dan mempublikasikan hasil koreksinya di RodState.orientation. World memakai nilai ini apa adanya, tidak boleh menghitung ulang dari sudut Euler. Alasannya: memakai nilai Euler relatif untuk gameplay sekaligus render dulu menyebabkan rod terlihat "meloncat" (snap) begitu kalibrasi selesai. Aturan ini dikutip ulang nanti, misalnya di catatan smoothing bend ADR-051.
  • ADR-017 β€” Batas Cast Resolver. Gerakan cast (lempar kail) ditangkap sekali sebagai CastSnapshot yang tidak berubah (orientasi, kecepatan sudut, waktu); CastResolver mengubahnya jadi CastSolution (kekuatan, arah, sudut peluncuran). Pendeteksi gerakan hanya mendeteksi momen lepas (release), tidak melakukan penyeimbangan gameplay; World tidak pernah membaca CoreMotion secara langsung. Ini jadi fondasi untuk banyak ADR soal cast berikutnya (ADR-032/033/050/054/056/057).
  • ADR-018 β€” Pemisahan Fase Gestur Cast dan Transform. Lapisan gerakan Rod/Shared memegang fase-fase gestur (Idle/Backswing/Charging/Forward Swing/Release/Follow Through) dan mempublikasikan castPower secara live; saat release, hasilnya diselesaikan sekali jadi CastSolution yang menetap. State cast dan state spasial (NI) dijaga tetap sebagai dua kontrak terpisah β€” World tidak boleh menyusun ulang nilai cast dari data mentah gerakan, atau memakai jarak cast untuk menggerakkan rod. Alasan: mencampur output cast ke transform rod sebelumnya membuat controller terlihat bergeser (translate) saat release.
  • ADR-019 β€” Pemisahan Root Controller dan Simulasi Kail. World menjaga RodRoot pada posisi tetap relatif kamera, hanya menerapkan RodState.orientation padanya; arah/kekuatan/jarak cast hanya menggerakkan peluncuran dan simulasi kail, tidak pernah menggerakkan root rod; menggulung (reeling) hanya mengubah posisi kail, bukan root rod. Alasan: mengaitkan root rod ke jarak cast dulu membuat rod terlihat maju saat cast lalu meloncat balik setelah menggulung. Pemisahan ini dipakai/dimanfaatkan lagi di ADR-033 dan ADR-043.
  • ADR-020 β€” Rod sebagai Pengendali, World sebagai Permainan. Batas produk yang eksplisit: Rod murni input fisik (gerakan, penangkapan kalibrasi, niat cast/reel, tombol, status koneksi, haptik); World memegang semua hal yang berhubungan dengan gameplay (menu, tutorial, instruksi kalibrasi, HUD, simulasi kail/ikan, hasil, progres). Tidak boleh ada info gameplay yang tampil di Rod pada versi V1. Alasan: agar iPhone terasa "diam secara visual" sehingga pemain merasa memegang joran sungguhan, bukan layar kedua; juga mencegah duplikasi aturan gameplay di dua perangkat. Prinsip ini terus dikutip di ADR-ADR berikutnya, misalnya ADR-038, ADR-053, ADR-064.
  • ADR-021 β€” Debug Dulu. Setiap subsistem harus punya info debug yang bisa diamati (status sesi, jarak, arah, pitch/roll/yaw, frekuensi update) sebelum gameplay-nya dibangun. Ini jadi dasar untuk grup pengungkap "Developer Details" yang ditambahkan nanti di ADR-029.

2. Jaringan / Transport Bluetooth

  • ADR-059 β€” Mode Pengiriman Mengikuti Kesegaran Pesan, Bukan Default Tunggal. NetworkMessage menandai requiresReliableDelivery per jenis pesan: telemetri berkelanjutan berfrekuensi tinggi (stream .state/RodState) dikirim tidak andal/unreliable (sampel basi jadi tak berguna begitu tergantikan sampel baru β€” kirim ulang malah menambah keterlambatan sampel yang antre di belakangnya); sinyal sekali-kirim yang jelas (discoveryToken, fishingEvent, hookPhase) tetap andal/reliable, karena kehilangan satu saja bisa diam-diam merusak state game. Alasan: mode .reliable pada MultipeerConnectivity berperilaku seperti TCP β€” satu paket hilang menyebabkan head-of-line blocking, yang terasa seperti lag controller padahal tak ada hubungan dengan frame rate. Konsep pemisahan reliable/unreliable ini terus dipakai saat transport ditulis ulang total ke CoreBluetooth (lihat ADR-035/063).
  • ADR-035 β€” Transport Diganti Total: MultipeerConnectivity β†’ CoreBluetooth. TransportClient (Rod) dan TransportHost (World) ditulis ulang total di atas CoreBluetooth; bentuk TransportProtocol/NetworkMessage di Shared tidak berubah. Rod berperan sebagai perangkat BLE peripheral (CBPeripheralManager), mengiklankan satu GATT service dengan 3 characteristic: state (notify/tidak-andal, untuk stream RodState ~30Hz), reliable-out (indicate, untuk .discoveryToken), dan command (write-with-response, untuk perintah Worldβ†’Rod seperti .fishingEvent/.hookPhase). World berperan sebagai BLE central (CBCentralManager) yang scan/connect/subscribe/write. Ditambahkan juga BLEFraming/BLEMessageReassembler (di Shared, murni Data, tanpa import CoreBluetooth) untuk memecah payload sesuai batas ATT MTU dengan header panjang 4-byte β€” sudah diverifikasi lewat tes roundtrip standalone sebelum dipasang. Jalur .state yang tidak-andal sengaja tidak pernah dipecah (fragment) β€” pesan yang kebesaran untuk satu paket langsung dibuang saja (toh sampel yang lebih baru cuma ~33ms lagi); dua jalur reliable boleh dipecah dengan aman karena CoreBluetooth mengonfirmasi tiap paket, dan keduanya diantrekan FIFO supaya kiriman bersamaan tidak saling tumpang-tindih/rusak. Kedua kelas transport dan protokolnya dijalankan di @MainActor (callback CoreBluetooth jatuh di antrean utama karena kedua manager pakai queue: nil); kesesuaian delegate ObjC memakai @preconcurrency. Untuk sambung ulang: Rod tetap mengiklankan diri setelah central berhenti subscribe; World tetap scan ulang setelah terputus. Izin platform (entitlements) diubah: NSBonjourServices dihapus, ditambahkan teks izin Bluetooth, ENABLE_RESOURCE_ACCESS_BLUETOOTH diaktifkan untuk aplikasi macOS World yang sandboxed, izin jaringan diperketat jadi NO karena tak ada lagi jaringan lain yang dipakai. Alasan: ada bug dikenal di MultipeerConnectivity pada iOS 26 yang membuat pairing tidak stabil khusus di skenario Bluetooth-berat/tanpa Wi-Fi (persis skenario proyek ini β€” mancing di luar ruangan); model notify/write GATT dari CoreBluetooth lebih cocok untuk pesan kecil-dan-sering ini. Status: diterima, tapi verifikasi latensi di perangkat asli belum pernah dijalankan.
  • ADR-049 β€” Daftar Pasangan Perangkat (Allowlist) di Atas CoreBluetooth. Sebelumnya World terhubung ke Rod mana pun yang ditemukan pertama kali, dan Rod menganggap central mana pun yang subscribe sebagai "yang" terhubung β€” kalau ada beberapa perangkat dalam jangkauan, ponsel mana pun bisa terhubung ke Mac mana pun. Ditambahkan mekanisme pairing sekali-lalu-terkunci di kedua sisi, disimpan lewat UserDefaults (bukan di Shared, karena tipe CBPeripheral/CBCentral spesifik platform): PairedDeviceStore di World menyimpan identitas Rod yang sudah dipasangkan dan menyaring didDiscover; PairedCentralStore di Rod menyimpan identitas central yang dipasangkan, dan β€” ini yang krusial β€” setiap panggilan updateValue sekarang menyasar [subscribedCentral] secara spesifik, bukan nil (sebelumnya nil menyiarkan data asli ke siapa pun yang subscribe, tanpa peduli status pairing di level aplikasi β€” perbaikan yang cuma di level status saja tidak akan menutup kebocoran data yang sesungguhnya ini). Kedua sisi juga mendapat tombol UI "Forget Device"/"Forget Paired Mac" untuk jalan keluar. Alasan: diminta langsung supaya satu ponsel tidak bisa tidak sengaja terhubung ke Mac yang salah. Sengaja hanya dibuat satu slot pasangan (bukan manajemen banyak-perangkat penuh) sebagai bacaan minimal dari permintaan tersebut.
  • ADR-062 β€” Rod Dapat Jalur Pemulihan "Forget Paired Mac"; Kegagalan Decode yang Diam-diam Kini Dicatat Log. Ditemukan saat mendiagnosis bug "Press Start Fishing" yang macet: (1) jalur decode pesan masuk di kedua transport memakai try? ... else { continue }, yang diam-diam menelan kegagalan decode apa pun (misalnya ketidakcocokan skema karena hanya satu sisi yang dibangun ulang) β€” sekarang dicatat log di bawah #if DEBUG. (2) Akar masalah sebenarnya: Rod tidak punya cara menolak subscription dari central yang tidak cocok di level protokol β€” ia tetap berhasil subscribe (jadi World membaca status .ready), tapi lapisan aplikasi di Rod tidak pernah menambahkannya ke sendTargets, sehingga Rod diam-diam tidak pernah mengirim data ke Mac itu. Fungsi RodViewModel.forgetPairedDevice() sebenarnya sudah ada dan berfungsi tapi tidak punya pemanggil di UI (tombolnya ada di dalam DisclosureGroup yang di-comment-out, dibiarkan sesuai konvensi proyek untuk tidak mengutak-atik pekerjaan orang lain yang sedang berjalan) β€” jadi ditambahkan baris pairedDeviceRow berdiri sendiri. Alasan: fitur "Forget Device" milik World sendiri (ADR-049) tidak bisa menjangkau dan membersihkan penyimpanan independen milik Rod β€” setelah dipakai, Rod menolak tersambung ulang bahkan setelah di-relaunch, benar-benar jalan buntu tanpa perbaikan ini.
  • ADR-063 β€” RodState Diberi Kunci Wire Pendek β€” Setiap Cast Diam-diam Gagal Terkirim Lewat BLE. Akar masalah ditemukan lewat logging baru: TransportClient.sendUnreliable(_:) memang sengaja tidak pernah memecah (fragment) jalur .state (sesuai desain ADR-035) β€” pesan yang kebesaran untuk satu potongan BLE langsung dibuang. castSolution yang terisi (yaitu setiap pesan .state selama dan setelah jendela followThrough dari sebuah cast sungguhan) ternyata konsisten ter-encode jadi 531–542 byte, padahal batas satu-potongan yang terukur cuma 512 byte β€” artinya setiap upaya cast, tanpa kecuali, diam-diam dan sepenuhnya dibuang, sepanjang durasi followThrough, tanpa error sama sekali di mana pun (karena RodState saat idle tetap kecil, jadi semua yang lain tampak berfungsi normal tanpa petunjuk apa pun). Ini adalah kerapuhan desain yang sudah lama laten, dipicu meluap oleh field baru isCastingArmed dari ADR-061, tapi akar masalahnya (kunci JSON yang bertele-tele melawan batas potongan yang keras) sudah ada sejak awal. Perbaikan: ditambahkan enum CodingKeys eksplisit yang memetakan setiap properti RodState ke nama wire pendek (timestampβ†’"ts", distanceβ†’"d", dst.) β€” payload terisi yang sama kini ter-encode jadi 419 byte, cukup di bawah 512. Alternatif yang ditolak: menaikkan batas potongan (tidak sepenuhnya bisa dikendalikan β€” mengikuti ATT MTU hasil negosiasi BLE) dan memecah .state (bertentangan dengan maksud desain "tidak boleh dipecah" untuk kanal yang tak terkonfirmasi). Ditambahkan juga diagnostik permanen: sendUnreliable sekarang mencatat log kejadian "dibuang karena ukuran" dan "antrean kirim penuh". Ini kemungkinan besar perbaikan bug paling berdampak di seluruh log β€” kegagalan cast total dan permanen.
  • ADR-061, poin 5 β€” Tombol "Retry Connection" di Menu Utama World. Koneksi BLE kadang macet ke kondisi yang tidak bisa dipulihkan otomatis, sebelumnya hanya bisa diperbaiki dengan force-quit lalu buka ulang World. WorldViewModel.retryConnection() menjalankan transport.disconnect() lalu .connect() (sama seperti buka ulang aplikasi) tanpa kehilangan state aplikasi; tombol hanya muncul saat !isRodReady.
  • ADR-041 β€” Nearby Interaction Masih Ada Tapi Tidak Krusial untuk Gameplay V1. Audit kode langsung (grep semua kemungkinan pemakai) mengonfirmasi Rod tetap menjalankan NI persis seperti ADR-014, dan field RodState.directionX/Y/Z/distance tetap dikirim β€” tapi tidak ada kode gameplay, render, atau gating koneksi mana pun yang membaca field-field itu. Posisi rod berasal dari konstanta tetap + orientasi saja (ADR-019); arah cast berasal dari orientasi terkoreksi/geometri rig (ADR-033); mekanik jarak fight/escape adalah perhitungan ruang-scene RealityKit antara dua entity, tidak berkaitan dengan pengukuran jarak dunia-nyata dari NI; gating koneksi murni dari status CoreBluetooth. Status NI sendiri hanya tampil di satu baris debug yang tidak dibaca apa pun yang lain. Keputusan: kode NI dibiarkan tetap ada (bukan keputusan untuk menghapus β€” itu ranah terpisah/lebih besar), tapi memperbaiki klaim usang di AGENTS.md yang bilang NI "tetap menjadi sumber transform spasial rod" (benar sebelum ADR-019, tidak pernah diperbarui setelah ADR-019 memisahkannya). Alasan: diangkat pemain setelah membaca kritik eksternal soal nilai praktis NI dibanding CoreBluetooth RSSI-ranging; kerangka pemain sendiri ternyata sesuai hasil audit β€” CoreBluetooth saja ternyata cukup untuk V1, jadi aspek "pengendali spasial" belum benar-benar krusial. Yang eksplisit belum diputuskan: apakah NI akan dihapus suatu saat, atau apakah framing proyek akan diubah namanya.

3. Rendering RealityKit, Rig Rod, dan Kamera

  • ADR-033 β€” Arah Cast Diturunkan dari Geometri Rig Langsung, Bukan Konstanta yang Dipatok ke Mesh Lama. Akar masalah kail mendarat menyamping padahal secara visual rod terlihat lurus ke depan: CastResolver memutar konstanta hardcode CastVector3.forward = (0,0,-1), yang hanya benar untuk mesh panah placeholder lama (ujungnya menghadap -Z lokal). Saat proses integrasi aset digabungkan dan rod_main.usdz dipasang lewat RodRigController, seluruh rantai tulangnya justru beristirahat di sepanjang +Y lokal β€” tidak ada yang memperbarui konvensi sumbu hardcode ini. Perbaikan (dilakukan di World, bukan Shared, karena Shared harus tetap tidak tahu-menahu soal mesh sesuai ADR-007/018): hitung arah hadap secara live saat cast sebagai normalize(tipEntity.worldPosition - controllerEntity.position), sehingga otomatis benar terlepas dari konvensi sumbu rig apa pun yang dipakai.
  • ADR-034 β€” Arah Cast Dibatasi ke Kerucut Depan; Ukuran Bobber Digandakan. Ditambahkan batas keras berupa kerucut selebar 135Β° (castConeHalfAngle = 67.5Β°) di sekitar arah depan kamera yang tetap, sebagai jaminan cadangan terlepas dari apa pun hasil hitungan arah hadap sebelumnya. Juga ditambahkan aimCorrectionAngle, direvisi langsung dari tebakan awal 90Β° menjadi hasil pengukuran 180Β° setelah pembacaan sudut mentah tanpa batas (debug-only) menunjukkan arah hadap dari geometri rig ternyata -174Β° (hampir persis terbalik, bukan seperempat putaran meleset). Sisa selisih kecil ~6Β° (antara -174Β° dan -180Β° yang tepat) sengaja dibiarkan menunggu pengujian langsung lebih lanjut. Ukuran bola kail juga digandakan (radius 0.035β†’0.07) semata agar penguji bisa melihat di mana kail mendarat.
  • ADR-043 β€” Gerakan Angkat Kail Menuju Titik Khusus, Bukan Titik Anchor Render Rod. Fase "angkat" saat menggulung sebelumnya menuju controllerEntity.position (dockAnchorPosition, [0.22, 1.95, -2.1]) β€” pengukuran jejak nyata dock_main.usdz (X di rentang [-2.04, 2.04], Z di rentang [-4.5, 4.5], lewat Entity(contentsOf:).visualBounds) menunjukkan titik anchor itu ternyata berada di dalam lantai dermaga yang solid, sehingga gerakan angkat mengangkat kail langsung menembus/melintasi mesh dermaga (dilaporkan sebagai kail "clipping" menembus dermaga). Ditambahkan titik tujuan khusus hookLiftTargetPosition = [0.22, 1.95, -4.7] (X/Y sama, Z digeser melewati tepi -4.5 dermaga yang terukur) β€” sengaja memisahkan urusan anchor-render dari urusan titik-tujuan-gameplay (meniru pemisahan root/kail yang sudah ada di ADR-019).
  • ADR-044 β€” Angkat Mendekati Dermaga Pakai Kecepatan Tetap Terjamin, Bukan Tarik-Menarik. Dalam jarak 1.0m dari hookLiftTargetPosition, kail sebelumnya masih bergerak dengan kecepatan bersih tarik-menarik (kecepatan reel pemain dikurangi tarikan ikan), yang bisa macet atau bahkan mundur tepat di tepi dermaga β€” dilaporkan sebagai kail "mengambang". Perbaikan: di dalam zona angkat, kail selalu maju dengan kecepatan tetap baru dockLiftSpeed = 3.5 m/s (lebih cepat dari kecepatan reel maksimum pemain sendiri) tanpa pengurangan tarikan ikan; di luar zona, tarik-menarik tetap seperti biasa. Resolusi tangkap/kosong juga diubah dari perhitungan jarak horizontal saja menjadi jarak 3D penuh, sehingga resolusi menunggu proses naik benar-benar selesai.
  • ADR-058 β€” World Secara Eksplisit Mengatur Kamera Orang-Pertama. RealityView dalam mode non-AR/virtual tidak punya fallback kamera ARKit dan tidak punya sudut pandang bawaan β€” tanpa entity PerspectiveCamera eksplisit ditambah content.camera = .virtual, RealityKit otomatis membingkai kotak-batas (bbox) scene dari sudut pandang sembarangan. Ini pernah benar-benar terjadi sebagai bug nyata: pemain terlihat berdiri di bawah air sambil melihat ke atas ke bagian bawah dermaga. Posisi/orientasi kamera diturunkan dari kamera player_pov yang diatur di repo aset Blender, memakai pemetaan yang sudah terverifikasi dari Blender (Z-atas) ke RealityKit (Y-atas): (x,y,z) β†’ (x,z,-y), bukan sekadar tebakan.
  • ADR-051 β€” Perbaikan Rig Rod: Smoothing Bend, Putaran Reel Placeholder, Perbaikan Line Mengikuti Rod. Tiga perbaikan diminta sekaligus ("benerin rod: diem/bend, reel muter, line ngikut"): (1) applyBend sekarang menjalankan pitch/roll mentah lewat filter low-pass satu-kutub (bendSmoothing=0.25) sebelum menghitung sudut sendi β€” memperbaiki jitter khusus di visualisasi lentur sekunder saja, bukan rotasi rig utama secara keseluruhan (yang sudah pernah diperbaiki sebelumnya lewat entri "Rod Tingling" di CHECKPOINT, tapi belum diterapkan ke efek tambahan yang satu ini). (2) Memeriksa langsung data skeleton/mesh asli rod_main.usdz (bukan asumsi) dan memastikan memang tidak ada geometri/sendi reel/spool sama sekali β€” reel sungguhan adalah tugas aset Blender terpisah; ditambahkan bola pipih placeholder (ModelEntity) yang ditempel dekat sendi Handle, diputar oleh fungsi baru applyReelSpin(reelSpeed:isReeling:deltaTime:). (3) Memperbaiki masalah yang sudah diketahui sebelumnya tapi belum dibenahi: root rod_line.usdz mewarisi seluruh orientasi dunia dari ujung rod, sehingga sumbu kendur (sag) lokal-X yang tetap milik line ikut berputar mengikuti roll rod, jadi melenceng dari bidang lentur rod saat pitch dan roll digabung. Diperbaiki dengan membaca orientasi dunia ujung rod saat itu dan memutar sumbu sag dengan kebalikannya sebelum menghitung sag tiap sendi β€” ini pendekatan pendekatan (approximation), bukan solusi sempurna (tiap sendi melawan orientasi ujung rod secara terpisah, tidak sepenuhnya berantai lewat sendi-sendi line sebelumnya), tapi dianggap wajar mengingat sudut sag per-sendi kecil (maksimum ~20Β°).
  • ADR-041 (lihat Β§2 di atas) juga relevan di sini sebagai temuan terkait rendering (data spasial yang ternyata tidak dipakai render).

4. Mekanik Casting (model kekuatan/waktu β€” mengalami beberapa kali desain ulang)

Berikut evolusi kronologis "bagaimana cara casting bekerja":

  • ADR-017/018 (lihat Β§1) β€” batas dasar cast-snapshot/resolver; model fase gestur.
  • ADR-032 β€” Kekuatan Cast Dibobot oleh Jarak Backswing, Bukan Kecepatan Sentakan Saja. Sebelumnya kekuatan cast hanya berasal dari satu sampel kecepatan rotasi sesaat pada frame release β€” seberapa jauh pemain menarik ke belakang tidak pernah diukur. Ditambahkan pelacakan backswingPeakDistance (jarak-pose-dari-idle puncak yang tercapai selama gestur .cast berlangsung) baik di meteran live maupun di CastResolver yang otoritatif; rumus campuran power = distancePower * (0.7 + 0.3 * flickPower) β€” jarak backswing jadi dasar/gerbang utama, kecepatan sentakan hanya menambah bonus hingga 30%. Secara eksplisit ditandai sebagai percobaan pertama yang dipilih dengan tangan (belum final).
  • ADR-033/034 (lihat Β§3) β€” perbaikan arah cast, jalur paralel dengan kekuatan.
  • ADR-050 β€” Upaya Cast Butuh Persiapan Eksplisit "Start Casting". Sebelumnya pose apa pun yang mendekati castPose langsung diam-diam mulai mengisi daya, tanpa sinyal niat yang jelas. Ditambahkan isCastingArmed: Bool, yang sepenuhnya menggerbangi proses pengisian β€” pose yang belum "diarmed" mendekati castPose sekarang berperilaku persis seperti idle. Tombol baru "Start Casting" ditambahkan di Rod; status arm ini otomatis dibersihkan di 3 tempat (cast berhasil ditembakkan, hookPhase keluar dari .idle, sesi berakhir) sehingga tidak akan pernah macet dalam status armed.
  • ADR-054, poin 1 β€” Kekuatan Cast Kini Berasal dari Durasi Tahan, Bukan Jarak Backswing (menggantikan istilah jarak dari ADR-032). backswingDistance (radian) diganti dengan backswingHoldDuration (detik) sebagai suku dasar kekuatan, campuran 0.7/0.3 dengan sentakan tidak berubah. Koreksi hasil uji langsung, hari yang sama: mengisi ulang (re-arm) segera setelah release ternyata mewarisi kekuatan cast sebelumnya yang sudah beku, karena early-return fase followThrough hanya digerbangi oleh timer cooldown lokal Rod, tidak bergantung pada isCastingArmed β€” diperbaiki sehingga arm baru selalu langsung mereset castEndsAt.
  • ADR-056 β€” Kekuatan Cast Menghapus Total Bonus Sentakan; Timer Live Ditampilkan di World. Kecepatan sentakan sekarang sama sekali tidak menyumbang kekuatan β€” kekuatan murni dari holdPower; sentakan sekarang hanya berfungsi sebagai pemicu release. Ini membuka jalan untuk menghapus sebagian kode mati (plumbing kecepatan sudut, field CastSnapshot.angularVelocity, field laju rotasi per-sumbu sampai balik ke CoreMotion) setelah dikonfirmasi lewat grep bahwa tidak ada kode lain yang bergantung padanya. Ditambahkan castHoldDuration live yang dikirim dan ditampilkan di World sebagai "Holding X.Xs" di sebelah bar kekuatan. Juga ditemukan secara tidak sengaja: pemanggilan CastMeterView ternyata sudah lama di-comment-out β€” selama ini tidak pernah benar-benar tampil di layar, bukan sekadar kurang teruji β€” sekarang di-uncomment kembali.
  • ADR-057 β€” Kekuatan Cast Jadi Mini-Game Timing, Bukan Ramp Pengisian (menggantikan ramp monoton dari ADR-054/056). Kekuatan sekarang berosilasi terus-menerus: power = (1-cos(phase))/2 selama satu oscillationPeriod berulang (awalnya 2.0 detik) β€” mekanik gaya "kena puncak" ala ayunan golf/pelampung mancing, bukan ramp "tahan lebih lama = lebih kuat". Sentakan tetap memicu release, dan mengunci nilai osilasi apa pun yang sedang berjalan saat itu. Koreksi hasil uji langsung, hari yang sama: re-arm mewarisi kekuatan cast sebelumnya yang beku (pola akar masalah yang sama dengan perbaikan di ADR-054, muncul lagi karena ini jalur early-return yang berbeda) β€” diperbaiki dengan mereset castEndsAt tanpa syarat setiap kali isCastingArmed aktif. oscillationPeriod juga diperlambat dari 2.0 detik ke 3.5 detik sesuai masukan "terlalu cepat".
  • ADR-054, poin 3 / ADR-061, poin 3 / ADR-066 β€” lihat Β§5 (kesulitan fight) dan di bawah untuk mekanik jarak-menentukan-ukuran-ikan dan batas-bawah-jarak-cast yang dibangun di atas sistem kekuatan/arah cast yang sudah final.
  • ADR-066 β€” Batas Bawah Jarak Cast Dinaikkan Supaya Cast Pendek Bisa Melewati Dermaga. Rumus kecepatan-vs-kekuatan pada launchHook diubah dari castSpeed*(0.5+power*1.5) menjadi castSpeed*(1.4+power*0.6) β€” hanya batas bawah di power=0 yang naik (0.5xβ†’1.4x); batas atas di power=1 tidak berubah. Akar masalah: jejak mesh dermaga yang terukur (Z=-4.5, dari posisi rod sekitar Z=-2.1) membuat cast pendek (zona hijau) dulu mendarat di dalam geometri solid dermaga alih-alih menciprat melewatinya, karena perhitungan balistik tidak tahu-menahu soal tabrakan (collision) dengan dermaga. Diverifikasi secara numerik lewat tabel sebelum/sesudah; estimasi jarak yang ditampilkan di CastMeterConfig (yang memang sudah didokumentasikan terputus dari fisika sesungguhnya) sengaja dibiarkan tidak disentuh.

5. Mekanik Gameplay / Fight Ikan (tegangan, resistensi, kabur, progres)

Ini adalah mekanik dengan iterasi dan pembatalan terbanyak di seluruh log.

  • ADR-022 β€” Kepemilikan Spawn Ikan (Fish A). FishManager milik World memunculkan satu entity ikan (primitif bola tidak-seragam, karena belum ada mesh kapsul) saat kail masuk air, berenang idle, lalu hilang saat kembali ke idle; belum ada mekanik minat/gigitan/fight. Status: dibatalkan oleh ADR-023 di hari yang sama β€” arah berubah jadi "belum perlu ikan visual, benahi dulu state machine-nya"; FishManager.swift dihapus total.
  • ADR-023 β€” Fase Kail Mencerminkan Gigitan Ikan Sungguhan, Belum Ada Ikan Visual (membalikkan pendekatan visual-dulu dari ADR-022). HookPhase mendapat state baru .fishOnHook di antara .hookInWater dan .reeling. World melacak biteTimer/hasFishOnHook secara privat; FishingEvent.fishBite/.catchFish untuk pertama kalinya benar-benar dipakai (sebelumnya sudah ada tapi tidak pernah dikirim). Belum ada pembedaan cari/minat, tegangan, atau logika kabur β€” gigitan selalu berhasil jika digulung. Alasan: menampilkan ikan sebelum state machine-nya jujur akan jadi "kebohongan visual di atas loop yang belum benar-benar berfungsi."
  • ADR-024 β€” Timer Kabur dan Putus Line karena Kecepatan Reel. Dua timer independen: biteExpireTimer (menghitung mundur selagi fishOnHook dan tidak sedang menggulung; jika habis, ikan kabur kembali ke .hookInWater) dan lineStrainTimer (terkumpul selagi menggulung di atas ambang tertentu; jika terlalu lama, line putus ke .idle). Pola haptik baru fishEscaped() yang berbeda dari lineBreak(). Status: dibatalkan oleh ADR-028 β€” kedua timer ini digantikan oleh zona-aman tegangan yang disatukan; mekanik "zona aman berkelanjutan" yang tadinya dianggap di luar cakupan ternyata persis yang diminta dokumen produk.
  • ADR-025 β€” Kecepatan Reel Berskala Berkelanjutan dengan Laju Rotasi. Memperbaiki kecepatan reel yang jenuh jadi biner 0/1 (karena ada batas bawah pembagi max(_, 1) yang membuatnya efektif konstan) dengan mengalibrasi terhadap laju rotasi puncak yang benar-benar didemonstrasikan pemain sendiri (reelFullRotationRate) sebagai referensi 1.0, bukan batas bawah sembarangan.
  • ADR-026 β€” Model Data FishSpecies dan Tegangan Line Berkelanjutan. Ditambahkan FishSpecies (di Shared, data murni: rentang berat/panjang, resistensi, nilai) dan FishFightController (di World) yang menggantikan timer boolean strain-line dengan lineTension: Float berkelanjutan (0...1) yang naik di atas kecepatan reel aman per-spesies dan meluruh selain itu, putus di 1.0. Kepemilikan state fight dipindah keluar dari WorldViewModel ke controller baru ini (dibuat kecil, tidak tahu apa pun soal transport/entity). Pemisahan ini jadi contoh yang dipakai ulang nanti untuk FishFightConfig di ADR-039.
  • ADR-027 β€” Tegangan Line Mengikuti Durasi Fight, Bukan Kecepatan Reel. Mengubah rumus dari ADR-026: tegangan sekarang murni terkumpul dari waktu yang telah berlalu selama menggulung (deltaTime / effectiveMaxFightDuration), bukan kecepatan reel, sesuai permintaan ("kalo user kelamaan nge reel... line putus"). Status: dibatalkan oleh ADR-028, hanya satu tugas kemudian β€” ternyata tidak benar-benar menjawab permintaan sesungguhnya pemain (mekanik zona aman di mana ikan terlihat benar-benar melawan lewat jarak kail), jadi diganti total.
  • ADR-028 β€” Zona Aman Tegangan Bersatu Menggantikan Timer Durasi. Menerapkan mekanik sesungguhnya yang dimaksud dokumen produk: lineTension naik/turun berkelanjutan ((reelPull - effectiveFishPullRate) * deltaTime), dimulai dari initialTension=0.5; kabur di bawah 0, putus di atas 1. Ikan sekarang benar-benar menarik kail secara fisik β€” WorldViewModel.driftHookAway menggerakkan kail menjauh sepanjang sumbu rod-kail saat tidak sedang digulung, memberi tarik-menarik yang benar-benar terlihat. Mekanisme dari ADR-024/027 dihapus total. LineTensionView sekarang menampilkan zona aman berbayang plus peringatan "LOSING FISH"/"SNAPPING". Ini menjadi mekanik yang jadi fondasi semua ADR tuning fight berikutnya (030, 039, 054 poin 3, 061 poin 3) tanpa diganti lagi β€” arsitektur "final" untuk tegangan.
  • ADR-029 β€” Layar Hasil, Antarmuka Minimal Rod V1, Minat Ikan. Tiga celah ditutup sekaligus: (1) HookPhase.result ditambahkan, dikecualikan dari casting/reeling supaya tidak bisa balapan dengan tampilan hasil dari rod; layar hasil menampilkan spesies/berat/panjang/bintang/koin/rekor-baru lewat FishRecordStore baru; kabur/line-putus sengaja TIDAK masuk ke .result (bacaan sempit dari dokumen produk, menghindari modal yang membosankan di setiap nyaris-lolos). (2) ContentView Rod ditulis ulang sesuai spesifikasi V1 minimal (hanya tombol Start/Calibrate/End Fishing); semua baris debug diturunkan ke dalam DisclosureGroup "Developer Details" yang bisa dilipat, bukan dihapus (konvensi proyek). RodViewModel.isFishing/startFishing()/endFishing() ditambahkan, menggerbangi cast/reel ke sesi eksplisit, bukan selalu aktif. Celah yang ditandai tapi belum diperbaiki di sini: instruksi kalibrasi masih ada di teks Rod, bukan World (baru ditutup nanti oleh ADR-064). (3) State pra-gigitan "Fish Interested": updateSearching sekarang mengembalikan .interested/.bite lewat dua timer berurutan, bukan satu; Rod dapat pola haptik getar periodik baru (interestPulse), World dapat event .fishInterested, belum ada isyarat visual (ditambahkan nanti di ADR-052).
  • ADR-030 β€” Resistensi Berskala dengan Ukuran Terroll, Bukan Cuma Spesies. FishSpecies.resistance menjadi batas atas per-spesies, bukan nilai fight langsung β€” resistensi aktual = species.resistance * sizeRatio, di mana sizeRatio adalah posisi beratΓ—panjang tangkapan ini dalam rentang spesiesnya. Alasan: sebelumnya dua hasil roll berbeda ukuran dari spesies yang sama melawan dengan cara yang identik.
  • ADR-031 β€” Perbaikan Jarak Cast, Jarak Fight, dan State Reel di Fase Cari. Empat perbaikan: (1) jarak cast yang diukur sungguhan (jarak peluncuran-ke-cipratan hasil simulasi fisika, bukan estimasi meteran yang terputus) sekarang membatasi ukuran ikan yang bisa di-roll lewat sizeCeilingRatio/biasedRoll β€” cast jauh bisa dapat ikan besar, cast pendek dibatasi lantai 0.3. (2) Jarak fight minimum terjamin (0.4m) dipaksakan begitu gigitan terjadi, memperbaiki bug di mana menggulung terlalu dini bisa menyelesaikan tangkapan di tick yang sama dengan gigitan terjadi, sebelum LineTensionView sempat tampil. (3) Menggulung di fase cari tidak lagi berpura-pura jadi .reeling/.fishOnHook β€” digerbangi oleh hasFishOnHook, memperbaiki bug state machine sekaligus glitch haptik (getar minat-ikan mati terlalu dini).
  • ADR-037 β€” Tier Ikan dan Sistem Progres Tiga Level Berdasarkan Jumlah Tangkapan. FishSpecies mendapat properti tier: FishTier (.small/.medium/.big/.boss); FishCatalog bertambah dari 1 jadi 4 spesies (fish_a/b/c, scott). ProgressionStore baru: mulai Level 1 (hanya small) β†’ 10 ekor small tertangkap β†’ Level 2 (medium terbuka) β†’ 10 ekor medium tertangkap β†’ Level 3 (big DAN boss/Scott terbuka bersamaan, sesuai spesifikasi harfiah "tiga level"). Ditambahkan banner naik-level dan baris progres HUD. Tier .boss sengaja dijaga terpisah (tidak digabung ke .big) karena Scott adalah pertemuan "boss" yang secara naratif ditandai khusus sesuai permintaan. Nilai statistik spesies secara eksplisit ditandai sebagai placeholder kasar, belum diseimbangkan.
  • ADR-039 β€” Sesi Retuning Kesulitan Fight: Tarik-Menarik, Kabur Berbasis Jarak, Haptik Tegangan, Kamera Fight (retuning besar multi-bagian, banyak direvisi berkali-kali di hari yang sama). Lima perubahan diminta sekaligus setelah masukan "terlalu mudah": jarak cast diperpanjang (castSpeed 3.6β†’5.0, jangkauan maksimum ~13mβ†’~24m); kamera sekarang mengikuti fight (.fishOnHook/.reeling), bukan cuma penerbangan cast; laju tegangan reel dinaikkan 0.5β†’0.85, lalu dikoreksi ke 0.55 setelah uji langsung menunjukkan 0.85 membuat bahkan tier terlemah nyaris mustahil tanpa line putus instan β€” dihitung ulang manual dengan tabel waktu-hingga-putus. Tarik-menarik sungguhan + kabur berbasis jarak: ikan sekarang aktif menguras progres reel selagi digulung (basePullSpeed 0.4β†’1.0); ditambahkan escapeDistanceAllowance baru (6m) yang memicu .escaped jika ikan menarik terlalu banyak line ekstra. Kabur sekarang mereset ke .idle (memerlukan cast ulang), menyamakan perlakuan dengan line-putus yang sebelumnya sudah begitu. Seluruh angka tuning fight dipindah ke struct FishFightConfig baru di Shared (dipakai bersama oleh FishFightController dan FishingHaptics supaya rasa gameplay dan haptik tidak bisa saling melenceng) β€” permintaan eksplisit pemain: "config file... so I can tune manually." Perbedaan resistensi antar-tier ternyata terlalu lemah (semua tier menyatu jadi tegangan bersih yang mirip) β€” ditambahkan 3 field pengali resistensi baru sehingga pada roll ukuran maksimum, sebaran antar-tier jadi drastis (fish_a ~2 detik untuk putus, scott malah net-negatif, artinya menggulung kecepatan penuh saja tidak cukup menahan line-nya Scott). Haptik pita-tegangan berkelanjutan di Rod (reelTensionLow/Medium/High), hanya transisi yang dikirim lewat jaringan, ritme berkelanjutan lokal saja. Susulan sehari yang sama #1: basePullSpeed dipangkas separuh (0.7β†’0.35), kecepatan tarik-reel pemain dinaikkan 50% (3.0β†’4.5) sesuai masukan langsung bahwa tarikan ikan terasa terlalu cepat dan reel terasa terlalu lambat. Susulan #2: keduanya dipotong lagi 25% (0.35β†’0.2625, 4.5β†’3.375). Susulan #3: penalti arah-fight (juke) dipangkas separuh (0.20β†’0.10); kecepatan reel-in dibuat berskala risiko/imbalan mengikuti tegangan β€” lambat (0.5 m/s) di zona aman/hijau, meningkat ke cepat (1.0 m/s) di zona bahaya/merah, memberi imbalan bagi pemain yang berani bertahan dekat ambang putus. Susulan #4: rentang 0.5/1.0 m/s tadi dilaporkan "tidak bisa dimainkan, terlalu lambat" β€” diretune jadi 2.0/4.0 m/s (rasio 2x yang sama, kedua angka eksplisit dari permintaan). Ini adalah ADR dengan iterasi langsung terbanyak dalam satu sesi di seluruh log β€” hampir semua angka berubah berkali-kali dalam satu sesi berdasarkan masukan playtest langsung.
  • ADR-053 β€” Arah Fight: Sub-Fase Juking Kiri/Kanan Berwaktu yang Butuh Counter dari Rod. Sub-mekanik baru dilapisi di atas fight tegangan (bukan menggantikannya): saat gigitan terjadi, fightDirection acak (.left/.right) dimulai untuk jendela waktu acak 5–10 detik, berganti sisi setiap 0.6–1.8 detik (tidak bisa ditebak, tidak metronomik). Dilawan lewat RodState.roll β€” dengan konvensi arah berlawanan (ikan menarik kiri β†’ pemain memiringkan rod ke kanan), dievaluasi murni dari roll yang dikirim, tanpa plumbing sensor baru. Melawan dengan benar meredakan tegangan; salah malah menambah tegangan, ditambahkan langsung ke rumus tegangan yang sudah ada (menjaga satu sumber kebenaran fight, bukan meteran kedua yang independen). Penjualan visual (kail bergeser menyamping) sengaja dijaga terpisah dari matematika tegangan itu sendiri β€” murni kosmetik. Baris HUD baru di World ("Fish pulling ←/β†’ / Lean rod β†’/←") karena Rod tidak memiliki HUD gameplay dan Core Haptics tidak bisa menyampaikan kiri-vs-kanan. Ketujuh angka konfigurasi baru secara eksplisit ditandai sebagai tebakan pertama, belum terukur.
  • ADR-054, poin 3 β€” Kesulitan Tier 3/4 Diringankan. Resistensi fish_c/scott diturunkan (0.75/0.95 β†’ pertama jadi 0.60/0.75, lalu lebih jauh lagi jadi 0.10 menyamai fish_b) β€” hanya fish_a yang mempertahankan angka aslinya, 0.35. Tuas yang benar untuk dipakai adalah FishSpecies.resistance (per-spesies), bukan pengali global di FishFightConfig (yang juga akan memengaruhi tier yang lebih mudah, padahal tidak diminta).
  • ADR-061, poin 3 β€” Jarak Cast Membatasi Ukuran Ikan dalam Tiga Zona Diskret, Bukan Batas Atas Berkelanjutan. Memetakan sepertiga-sepertiga bar kekuatan hijau/kuning/merah dari CastMeterView langsung ke jendela tier-bintang lantai+langit-langit yang keras (hijau: hanya bintang 1–2; kuning: 3–4; merah: 4–5; kuning/merah sengaja tumpang tindih di bintang 4 sesuai kata-kata permintaan itu sendiri), menggantikan mekanisme batas-atas-saja dari ADR-031 di mana cast pendek terkadang masih bisa dapat ikan besar secara kebetulan. Batasan zona diturunkan dengan membalik rumus pembulatan bintang yang sudah ada.
  • ADR-055 β€” Tombol Reset Progres. Ditambahkan ProgressionStore.reset() plus tombol "Reset Progress" di Menu Utama (gaya destruktif yang sama dengan "Forget Device," tampil tanpa syarat karena progres tidak berkaitan dengan pairing).
  • ADR-052 β€” Bobber Mengambang: Gerak Idle dan "Interest Dip" Sebelum Gigitan. Sebelumnya kail diam sempurna di ketinggian air tanpa isyarat visual apa pun sebelum gigitan. Ditambahkan gerak bob gelombang-sinus kecil yang selalu tampil (realisme ambient) plus gerak "interest dip" yang lebih tajam, cepat, dan hanya ke bawah, dilapiskan di atasnya setiap kali fishFight.isFishInterested aktif (memakai ulang state minat yang sudah ada dari ADR-029, yang sebelumnya belum punya konsumen visual β€” hanya haptik/audio).

6. Cutscene & Presentasi Ikan Tangkapan (rangkaian iteratif panjang, ADR-045 s/d ADR-076)

Seluruh rangkaian ini adalah satu fitur yang terus disempurnakan β€” hampir setiap entri langsung mengikuti masukan langsung terhadap entri sebelumnya.

  • ADR-045 β€” Resolusi Tangkapan Memutar Cutscene Sebelum Layar Hasil (State Presentasi di World, Bukan HookPhase Baru). Saat tangkapan sungguhan terjadi, alih-alih langsung menonaktifkan kail dan menampilkan ResultView, World sekarang memutar cutscene terskrip: bola placeholder melompat ke atas (easing sin, puncak 0.6m) selama 1.3 detik dengan overlay judul "CATCH!", baru kemudian berpindah ke layar hasil. Sengaja diimplementasikan sebagai Bool milik World saja (isShowingCatchCutscene), bukan case HookPhase baru, karena .result sudah menyediakan penguncian input yang dibutuhkan dan ini murni presentasi (sesuai aturan ketergantungan Rod/Shared/World β€” Rod tidak memiliki presentasi gameplay apa pun). Secara eksplisit ditandai sebagai placeholder menunggu pekerjaan aset Blender selanjutnya.
  • ADR-046 β€” Kamera Cutscene Tangkapan Berpindah ke Kail, Memakai Ulang Jalur Follow-Cam yang Sudah Ada. Cutscene dari ADR-045 sebelumnya diputar seluruhnya di luar jangkauan kamera dari sudut pandang pemain yang tetap. Ditambahkan cabang pertama baru di updateCameraFollow(): selagi cutscene aktif, kamera melihat ke kail dari sudut yang lebih dekat dan rendah dibanding bidikan mengikuti-fight di tengah-fight.
  • ADR-047 β€” Cutscene Tangkapan Menahan Ikan di Puncak Lompatan, Bukan Satu Lengkung Berkelanjutan. Satu easing berkelanjutan hanya menyentuh puncak untuk satu momen saja, terasa "terlalu singkat". Diganti dengan 3 fase eksplisit: Rise/naik (0.35 detik) β†’ Freeze/beku (0.9 detik, diam di puncak) β†’ Settle/turun (0.35 detik), berkelanjutan di setiap batas fase (tidak ada loncatan). Struktur rise/freeze/settle ini jadi tulang punggung untuk semua pekerjaan timing berikutnya, misalnya ADR-070/071/075.
  • ADR-048 β€” Cutscene Tangkapan Dapat Letterbox, Dorongan Kamera Masuk, dan Hiasan Judul. Empat tambahan murni presentasi diminta sebagai "buat lebih dramatis": kamera bergerak halus (smoothstep) dari offset awal yang lebih lebar ke offset akhir yang lebih dekat sepanjang durasi cutscene; ditambahkan batang letterbox plus glow radial; entri judul dibuat spring yang sengaja terlihat melebihi (overshoot) untuk efek "pop"; HUD gameplay memudar selama cutscene. Semua dipilih dengan tangan, tidak menyentuh Shared/Rod.
  • ADR-068 β€” Cutscene Tangkapan Memutar Ikan Beranimasi Sungguhan, Satu Spesies Saja, Diskalakan ke Panjang Tangkapan Hasil Roll. Bola placeholder digantikan aset sungguhan, mekong_catfish_caught.usdz, dimuat dari repo aset Blender saudara (~/repos/new-blender-project). Kenapa Mekong Giant Catfish khususnya: sebuah catatan handoff terpisah mendokumentasikan 5 dari 8 spesies "selesai" ternyata punya cacat orientasi/normal/UV yang belum terselesaikan; hanya Sailfish dan Mekong Catfish yang disebut andal, dan Mekong Catfish secara eksplisit disebut sebagai spesies rujukan/template β€” Sailfish dikecualikan hanya karena rignya melalui jalur impor berbeda (kasus khusus yang dikenal). Diverifikasi langsung (bukan sekadar dipercaya) lewat unzip/usdcat bahwa file itu benar-benar berisi SkelAnimation yang sudah dipanggang (baked). Ikan diskalakan ke panjang hasil roll tangkapan sesungguhnya, bukan ukuran tetap yang diatur pembuatnya. Hanya satu spesies dipakai untuk keempat tier katalog β€” memetakan tier tertentu ke spesies tertentu sengaja ditunda sebagai keputusan desain konten, bukan keputusan teknis. Celah lisensi belum terselesaikan ditandai: aset ini berlisensi CC-BY 4.0 (butuh atribusi: "Ikan Patin," Sketchfab), dan belum ada layar kredit sama sekali di aplikasi yang sudah dirilis β€” dicatat secara eksplisit sebagai item terbuka, bukan diam-diam dirilis begitu saja.
  • ADR-069 β€” Ikan Tangkapan Menghadap ke Rod, dan Klip Perjuangannya Diputar Lebih Cepat. Dua perbaikan setelah pemeriksaan langsung pertama ("masih terlihat seperti animasi preview, seharusnya terlihat meronta, menghadap ke rod"): (1) orientasi sekarang dihitung ulang tiap frame menghadap ujung rod yang live, lewat konstruksi dua-langkah (jalur-terpendek plus koreksi roll) β€” asumsi sumbu lokal (kepala di sepanjang Y, punggung di sepanjang Z) diverifikasi secara independen dengan memeriksa langsung bindTransforms di file .usdz yang sudah diekspor, bukan sekadar dipercaya dari dokumentasi sisi-Blender (ditandai sebagai risiko nyata mengingat konvensi Z-atas file ini berbeda dari swap Y-atas milik exporter glTF saudaranya). (2) kecepatan klip meronta diset ke 1.4x, karena asetnya memang sengaja dibuat dengan amplitudo yang lebih lembut sesuai karakter ikan lele (memang disengaja, bukan cacat), dan kecepatan putar adalah satu-satunya tuas yang tersedia tanpa membuat ulang di Blender.
  • ADR-070 β€” Cutscene Tangkapan Dapat Selubung Slow-Motion di Kode, Selama Fase Freeze. Jam cerita tunggal cutscene (cutscene.elapsed) sekarang maju dengan deltaTime * dilation, di mana dilasi melandai dari 1 turun ke 0.3 (tahan, lalu kembali ke 1) khusus selama fase freeze β€” karena posisi, dorongan kamera, dan kecepatan animasi ikan sendiri semuanya sudah diturunkan dari satu jam yang sama ini, mendilasinya otomatis memperlambat semuanya secara serentak. Total waktu nyata cutscene naik dari ~1.6 detik jadi ~3 detik. Diminta berbarengan dengan permintaan sisi-Blender untuk animasi/rigging meronta baru yang tidak bisa dikerjakan sesi coding ini sendiri β€” diserahkan sebagai spesifikasi tertulis ke repo aset (APP_TEAM_HANDOFF_CAUGHT_STRUGGLE.md), dengan slow-motion langsung diimplementasikan di kode sebagai separuh permintaan yang bisa langsung dikerjakan sendiri.
  • ADR-071 β€” Klip "Caught" Baru Diintegrasikan; Kecepatan Animasi Diturunkan agar Puncaknya Berada di Tengah Dip Slow-Motion. Handoff sisi-Blender (dari ADR-070) mengirimkan klip Caught yang dibuat ulang, lebih ganas, untuk Mekong Catfish (rig sama, bindTransforms dikonfirmasi identik byte demi byte). catchCutsceneFishAnimationSpeed diubah dari konstanta hardcode menjadi properti terhitung yang diturunkan sehingga momen paling dramatis dari klip (frame 44 dari 90) tepat jatuh di titik tengah waktu-cerita fase freeze β€” dihitung lewat penurunan rumus yang menunjukkan bahwa waktu-klip-per-waktu-cerita tidak bergantung pada bentuk dilasi, jadi tidak perlu dihitung ulang kalau konstanta timing berubah lagi nanti. Desain yang mengoreksi diri sendiri ini secara eksplisit lebih baik dari pendekatan sebelumnya (konstanta hardcode yang akan basi begitu klipnya berubah β€” persis yang baru saja terjadi).
  • ADR-072 β€” Ikan Tangkapan Memakai Pose Showcase Horizontal Tetap, Bukan Lagi Menghadap Rod. Dilaporkan setelah pemeriksaan langsung: orientasi menghadap-rod dari ADR-069 menghasilkan pose yang tidak terduga, didominasi oleh selisih vertikal apa pun yang kebetulan ada antara posisi ikan yang tetap dan ketinggian ujung rod yang live (bergantung kemiringan pemain) β€” terasa "masih normal/vertikal, bukan pose tangkapan yang horizontal." Digantikan dengan arah dunia +X yang konstan, dipilih karena geometri kamera cutscene tetap dan selalu berada di X=0, menjamin siluet menyamping/horizontal terlepas dari tinggi lompatan atau state rod. Entri ini sendiri dibatalkan satu ADR kemudian.
  • ADR-073 β€” Ikan Tangkapan Kembali ke Pose Vertikal Tetap "Terkait dan Tergantung," Menyamping ke Kamera (langsung membalikkan ADR-072, satu iterasi setelah dirilis). Masukan langsung: "kelihatan kayak lagi berenang, harusnya vertikal kepala-di-atas, bukan horizontal kayak pose berenang" β€” pose horizontal punggung-di-atas ternyata persis siluet yang sama dengan state Cruise milik aset itu sendiri, bukan ikan tangkapan/tergantung. Konstruksi matriks-rotasi langsung baru dibuat yang mengarahkan kepala lurus ke atas (dunia +Y) sambil menjaga sumbu lateral tetap sejajar dengan sumbu pandang kamera (supaya tetap menyamping, tidak memendek/foreshortened) β€” konstruksi dua-langkah yang sudah ada di fishOrientation(facing:) secara eksplisit tidak dipakai ulang di sini karena rumus itu rusak (degenerate) saat arah hadap tepat mengarah ke atas-dunia. Diverifikasi secara numerik lewat eksekusi Swift REPL standalone, bukan sekadar penurunan rumus di atas kertas. Alasan asli dari ADR-072 (arah tetap menjamin tegak lurus kamera) tetap dipertahankan; yang salah hanya pilihan horizontalnya.
  • ADR-074 β€” Dip Slow-Motion Kedua Memperpanjang Bagian Akhir; Kail dan Line Tetap Menempel di Ikan. Dua permintaan "polish": (1) fase settle sekarang punya dip slow-motion sendiri (menggeneralisasi fungsi dilasi dari ADR-070 supaya bisa dipakai baik di freeze maupun settle), menambah 1.5 detik waktu-cerita β€” secara eksplisit ditandai menghasilkan biaya waktu-nyata yang jauh lebih besar dari perkiraan (total ~7+ detik) akibat efek integral dilasi. (2) kail tetap menempel di mulut ikan (diposisikan ulang tiap frame memakai offset yang dibaca dari bindTransforms asli ikan, bukan ditaksir mata) alih-alih menghilang, dan tegangan line dipaksa ke nilai tegang tetap selama cutscene, bukan kendur.
  • ADR-075 β€” Cutscene Diretune Jadi Tepat 5 Detik Waktu Nyata; Kail Diposisikan Ulang/Diskalakan Ulang ke Mulut Sesungguhnya. Respons langsung terhadap tangkapan layar langsung: (1) durasi settle dari ADR-074 tadinya penambahan naif "+1.5 detik waktu-cerita" yang, setelah matematika dilasi slow-motion benar-benar diintegralkan, ternyata menghasilkan ~7+ detik waktu nyata alih-alih 5 detik yang dimaksud β€” diperbaiki dengan menyelesaikan integral dilasi dengan benar (C β‰ˆ 2.688) dan menghitung durasi settle persis yang dibutuhkan (0.83 detik), diverifikasi lewat integrasi numerik independen (numpy), bukan hitungan tangan. (2) konstanta offset kail sebelumnya bersumber dari posisi bind-pose sendi Head (pivot kerangka, bukan ujung mesh yang terlihat) β€” diukur ulang terhadap kotak-batas (extent) mesh sesungguhnya dan diiterasi dua kali (0.6β†’1.0β†’1.15) berdasarkan tangkapan layar langsung sampai benar-benar melewati moncong. (3) kail sekarang ikut skala tampilan ikan sendiri (sebelumnya ukuran tetap, membuat tangkapan yang lebih kecil terlihat kerdil). Contoh bagus dari disiplin berulang di log ini: "baca data aset sesungguhnya, jangan ditaksir mata."
  • ADR-076 β€” Line Khusus-Cutscene Ditambahkan, Terbentang dari Kail ke Ujung Rod. Diminta segera setelah ADR-075: "bisa tambah senar pancingnya?" β€” kail mengambang tanpa sambungan visual apa pun. Ditambahkan entity silinder tipis baru yang berdiri sendiri (bukan perpanjangan dari rig rod_line.usdz sendiri β€” dikonfirmasi dengan membaca langsung RodRigController.swift bahwa rig line yang sudah ada hanya melenturkan rantai tulang berpanjang tetap dan tidak punya mekanisme untuk memperpanjang jangkauan totalnya, sementara kail cutscene berada ~2.6m lebih jauh dari anchor rod dibanding jangkauan yang pernah dirancang untuk rig itu). Line baru ini direntangkan/diorientasikan lewat perhitungan vektor sederhana per-frame (skala + titik tengah + quaternion-dari-dua-vektor) antara kail dan ujung rod yang live, sehingga tetap tersambung benar bahkan saat lentur rod sendiri bergerak. Pilihan yang lebih sederhana dan berisiko lebih rendah dibanding mencoba merentangkan mesh berskin melampaui panjang bind aslinya (ditandai di tempat lain, di dokumentasi repo aset sendiri, sebagai kelas masalah yang jauh lebih sulit). Ini adalah entri terbaru dalam log.

7. Audio

  • ADR-040 β€” Audio di Sisi World Meniru Router Haptik Rod. SFX pertama ditambahkan, seluruhnya di sisi World (SoundManager + FishingSounds), meniru struktur pola HapticManager + FishingHaptics yang sudah ada di Rod, supaya kedua desain "router umpan balik" ini tetap konsisten. Satu corong emit(_:) di WorldViewModel memanggil baik penanganan suara maupun pengiriman jaringan, sehingga pemicu haptik dan suara tidak bisa saling melenceng. Loop reel digerakkan oleh frame (bukan oleh event) sehingga menggulung line kosong pun tetap dapat suara reel. AVAudioPlayer dipilih ketimbang audio spasial RealityKit karena belum ada yang butuh posisi 3D. Dua celah sengaja dibiarkan terbuka (sudah dikonfirmasi ke pengguna): kabur/line-putus memakai ulang suara cipratan sekali-pakai (belum ada aset khusus); naik-level belum punya suara sama sekali.
  • ADR-065 β€” Dua SFX Baru: Loop Ambience Idle, Loop Musik Fight Ikan dengan Fade-Out. idle.wav berulang selama .idle/.hookInWater; reel_fight.wav berulang selama fight aktif, memudar selama 1.5 detik pada hasil akhir fight apa pun (tangkap/kabur/line-putus sama saja) lewat overload baru stopLoop(_:fadeDuration:). Revisi, hari yang sama: reel_fight.wav awalnya adalah "kejutan" sekali-pakai untuk tangkapan bintang 4+ β€” didesain ulang di hari yang sama menjadi pasangan musik idle/fight yang digerakkan oleh state seperti dijelaskan di atas, sesuai permintaan susulan; pemicu berbasis-bintang dan metode sekali-pakainya dihapus total.
  • ADR-067 β€” SFX fish_catched, Pengurangan Tegangan Diperhalus 30%, Cakupan Loop-Idle Dikonfirmasi. Tiga permintaan dalam satu pesan: (1) dikonfirmasi cakupan loop-idle (dari ADR-065) memang sudah berfungsi benar β€” tidak perlu perubahan, diverifikasi dengan membaca kode sesungguhnya, bukan sekadar berasumsi ada regresi. (2) ditambahkan fish_catched.wav, diputar tambahan bersamaan dengan suara cipratan tangkapan yang sudah ada. (3) baseFishPullRate diperhalus dari 0.15 ke 0.105 (pengurangan 30%), mengikuti pola sesi yang sudah mapan yaitu hanya menyekalakan suku dasar pengurasan tegangan.

8. Haptik

  • ADR-054, poin 2 β€” Setiap Pola Haptik Rod Mendapat Kenaikan Intensitas Sungguhan. Tabel lengkap kenaikan intensitas sebelum/sesudah di semua pola haptik (cast, cipratan, reelTick, fishBite, catchFish, lineBreak, fishEscaped, fishInterested) plus tiga intensitas pita tegangan, sesuai masukan langsung "haptik-nya kurang terasa kuat" β€” semua pola dinaikkan, bukan cuma yang ditebak-tebak saja, karena keluhannya bersifat umum. Sharpness juga dinaikkan khusus di pita tegangan untuk rasa yang lebih tajam (bukan sekadar lebih keras).
  • ADR-060 β€” Setiap Pola Haptik Rod Dimaksimalkan ke Batas Atas Intensitas CoreHaptics. Permintaan susulan: "kalikan ke angka terbesar yang bisa ditangani ponsel." Setiap nilai hapticIntensity yang tersisa di semua pola dan tiga pita tegangan dinaikkan ke batas literal API, yaitu 1.0 (apa pun di atas itu akan dipotong (clamped) oleh OS β€” tidak ada lagi ruang naik untuk parameter ini tanpa bentuk pola yang berbeda, misalnya continuous events, yang belum diminta). Nilai sharpness sengaja tidak disentuh (mengatur warna suara/timbre, bukan kekuatan) β€” pita tegangan rendah/sedang/tinggi tetap berbeda lewat interval ketuk/sharpness meskipun intensitasnya sekarang sama. Ini jadi state akhir dari tuning intensitas dalam log ini.
  • Mekanik arah-fight dari ADR-053 (lihat Β§5) juga merupakan keputusan yang bersinggungan dengan haptik: secara eksplisit diputuskan bahwa arah juke kiri/kanan tidak bisa disampaikan lewat satu aktuator Core Haptics saja, jadi harus dibuat visual/HUD-only di World.

9. Alur UI/UX (Menu Utama, Onboarding, Batas Sesi, Layar Hasil)

  • ADR-029 (lihat Β§5) β€” layar Hasil pertama dan antarmuka minimal Rod V1.
  • ADR-036 β€” Menu Utama World, Mempertahankan Scene Tetap Ada Melewati Transisi Menu/Bermain. Ditambahkan enum Screen (.mainMenu/.playing); scene RealityKit tidak pernah dipasang/dilepas bersyarat berdasarkan layar β€” Menu Utama/Hasil digambar sebagai overlay di ZStack yang sama di atas scene yang selalu hidup, karena menjalankan ulang pembangunan lingkungan ~200-instance setiap bolak-balik ke menu akan jadi biaya yang bisa dihindari dan terasa mengagetkan. startGame() digerbangi oleh kesiapan koneksi; returnToMenu() digerbangi oleh hookPhase == .result. Ini menutup celah yang sudah ditandai sejak ADR-029 (Return to Menu dulu dilewati karena belum ada menu untuk kembali). Arsitektur ini kemudian dirombak total oleh ADR-038.
  • ADR-038 β€” Rod Memegang Batas Mulai/Selesai Sesi, Bukan World (merombak alur berbasis-tombol dari ADR-036). RodState mendapat isFishing: Bool, dikirim terus-menerus; WorldViewModel.screen sekarang bereaksi murni terhadap tepi naik/turun field itu, bukan lewat tombol di sisi World β€” startGame() dihapus total. Ditambahkan pengaman gagal: Rod yang benar-benar terputus di tengah sesi sebelumnya akan membuat screen macet selamanya di .playing tanpa ada controller yang bisa menekan "End Fishing," jadi transport.onStateChange sekarang juga memanggil returnToMenu() saat terputus/gagal. Menu Utama dan layar Hasil di World sama-sama kehilangan tombolnya yang sekarang jadi berlebihan/kontradiktif (tombol di World yang memaksa screen = .mainMenu akan langsung diam-diam ditimpa balik oleh pesan .state berikutnya). UI Rod menyusut jadi satu tombol yang berganti konteks (Start/End Fishing) plus Calibrate dipindah ke pojok toolbar. Alasan: memperluas prinsip "Rod adalah input, World adalah permainan" (ADR-020) sampai ke batas sesi itu sendiri β€” memulai/mengakhiri sesi sebelumnya adalah satu-satunya kontrol yang masih dirutekan lewat World, terasa janggal karena perhatian/tangan pemain seharusnya tetap di Rod fisik. Ini menjadi arsitektur final untuk siklus hidup sesi dalam log ini.
  • ADR-049 (lihat Β§2) β€” tambahan UI pairing (baris Forget Device / Forget Paired Mac).
  • ADR-055 (lihat Β§5) β€” tombol Reset Progress.
  • ADR-061, poin 4 β€” Layar Hasil Ditutup Lewat "Start Casting" di Rod, Bukan Tombol di Sisi World. Tombol "Continue Fishing" di ResultView dihapus total; RodState mendapat isCastingArmed, dan mengaktifkan arm dari layar hasil sekarang diperbolehkan satu fase lebih awal (.idle || .result) sehingga menekan Start Casting di Rod sekaligus menutup layar hasil dan mengaktifkan arm untuk cast berikutnya dalam satu gerakan fisik. HookPhase.allowsCasting sendiri tidak diubah, sehingga perlindungan-balapan dari ADR-029 (sentakan fisik tidak bisa menembak sebelum penutupan layar hasil di World selesai) tetap sepenuhnya terjaga. Ini melanjutkan arah "Rod memegang alur" dari ADR-038.
  • ADR-064 β€” Alur Onboarding, Panduan Kalibrasi Live di World, Kalibrasi Tersedia Kapan Pun Kail Idle. Menutup celah lama "Menu Utama World + Tutorial + instruksi Kalibrasi" yang sudah ditandai sejak ADR-029/038. Tiga bagian: (1) kalibrasi sekarang bisa dijangkau kapan pun HookPhase == .idle (tidak hanya sebelum sesi dimulai) β€” baik kondisi nonaktif tombol di Rod maupun calibrateMotion() sendiri sama-sama mendapat pelonggaran syarat ini, membuat rekalibrasi sungguhan di tengah sesi benar-benar bisa dijangkau, bukan cuma tampil seolah tersedia. (2) CalibrationStep dipindah dari enum lokal-Rod ke Shared (meniru preseden HookPhase sendiri) dan dikirim live lewat RodState; CalibrationGuidanceView baru menampilkan panduan berbasis-langkah yang sama di dua tempat di World (langsung di Menu Utama, dan sebagai overlay saat rekalibrasi di tengah sesi) β€” teks instruksi di perangkat Rod sendiri sengaja tetap dipertahankan (tidak dihapus), karena pemain mungkin sedang melihat ponsel, bukan layar World, saat gestur sesungguhnya dilakukan; keduanya membaca langkah dasar yang sama sehingga tidak akan pernah saling bertentangan. (3) OnboardingView pertama-kali-buka baru (tiga halaman statis: selamat datang, tujuan utama, level/tier), digerbangi oleh flag tersimpan hasSeenOnboarding, dengan titik masuk ulang "How to Play" dari Menu Utama. Teks halaman Level ditulis dari ambang batas sesungguhnya milik ProgressionStore saat ini, secara tidak sengaja menemukan dan memperbaiki komentar dokumentasi basi di file itu (kata-kata 3/5/10 sudah melenceng dari ambang batas sesungguhnya, 10/10). Menutup celah yang sudah 3-ADR usianya.

10. Konvensi Build/Verifikasi yang Teramati Sepanjang Log

Ini bukan satu ADR tunggal, melainkan disiplin berulang yang secara eksplisit dinyatakan berkali-kali β€” layak dicatat karena tampil sebagai kebiasaan penting (load-bearing) di puluhan entri:

  • Hampir setiap entri punya bagian "Status" yang membedakan dengan jelas apa yang benar-benar sudah diverifikasi (misalnya swiftc -typecheck terhadap target tertentu, kadang pengecekan numerik lewat REPL Swift standalone, kadang pemeriksaan file langsung lewat unzip/usdcat, kadang pengecekan identitas byte lewat shasum) dari apa yang belum terverifikasi (playtest sungguhan / sesi dua-perangkat langsung). Tidak ada satu pun entri di log ini yang mengklaim "sudah dimainkan" kecuali dinyatakan eksplisit β€” kebanyakan entri hanya sebatas typecheck, "menunggu konfirmasi langsung."
  • Pola berulang membaca aset/file/kode sesungguhnya sebelum bertindak, bukan mempercayai dokumentasi atau ingatan begitu saja: misalnya ADR-051 mengekstrak skeleton asli rod_main.usdz sebelum menyimpulkan tidak ada geometri reel sama sekali; ADR-068/069 memverifikasi ulang secara independen klaim repo aset Blender sendiri soal spesies ikan mana yang aman dipakai dan sumbu bind-pose mana yang bisa dipercaya; ADR-043 mengukur kotak-batas mesh dermaga yang sesungguhnya alih-alih menaksir dengan mata; ADR-056 mengonfirmasi lewat grep bahwa tidak ada kode lain yang bergantung pada field-field tertentu sebelum menghapusnya.
  • Beberapa entri menunjukkan kelas bug yang sama muncul berulang dalam bentuk sedikit berbeda dan diperbaiki setiap kali muncul lagi (misalnya bug "re-arm mewarisi kekuatan cast sebelumnya yang beku" muncul di ADR-054 maupun ADR-057; keluarga bug "kail mengambang/menembus geometri" muncul lintas ADR-042/043/044).

Keputusan yang Kemudian Dibatalkan/Diganti

Daftar berikut merangkum semua ADR yang statusnya sudah tidak berlaku karena digantikan ADR yang lebih baru β€” supaya pembaca tidak salah kira aturan lama itu masih dipakai:

  • ADR-022 (spawn ikan visual duluan, tanpa fish state machine) β€” dibatalkan hari yang sama oleh ADR-023 (perbaiki dulu state machine, belum perlu ikan visual). Yang berlaku: ADR-023.
  • ADR-024 (dua timer terpisah: biteExpireTimer dan lineStrainTimer) β€” digantikan oleh ADR-028 (zona aman tegangan bersatu). Yang berlaku: ADR-028.
  • ADR-027 (tegangan line dari durasi fight, bukan kecepatan reel) β€” dibatalkan satu tugas kemudian oleh ADR-028, karena ternyata tidak menjawab permintaan sesungguhnya. Yang berlaku: ADR-028.
  • ADR-032 (kekuatan cast dari jarak backswing, formula distancePower*(0.7+0.3*flickPower) memakai jarak radian) β€” istilah dasarnya digantikan oleh ADR-054 poin 1 (durasi tahan menggantikan jarak); lalu seluruh model itu sendiri digantikan lagi oleh ADR-057. Yang berlaku saat ini: ADR-057 (osilasi timing, bukan ramp).
  • ADR-054 poin 1 (kekuatan cast dari durasi tahan, ramp monoton dengan bonus flick 30%) β€” digantikan oleh ADR-056 (bonus flick dihapus total, murni holdPower), lalu ADR-056 sendiri digantikan oleh ADR-057 (osilasi terus-menerus, bukan ramp lagi). Yang berlaku: ADR-057.
  • ADR-056 (kekuatan cast murni holdPower tanpa osilasi) β€” digantikan oleh ADR-057 di bawahnya. Yang berlaku: ADR-057.
  • ADR-031 (jarak cast membatasi ukuran ikan sebagai batas-atas berkelanjutan/sizeCeilingRatio) β€” dikeraskan/digantikan mekanismenya oleh ADR-061 poin 3 (tiga zona diskret hijau/kuning/merah). Yang berlaku: ADR-061 poin 3 (versi 2, prinsip dasarnya tetap dari ADR-031 tapi implementasinya dikeraskan).
  • ADR-036 (Menu Utama dengan alur start/return berbasis tombol di World) β€” dirombak total oleh ADR-038 (Rod yang memegang batas mulai/selesai sesi lewat isFishing, tombol World dihapus). Yang berlaku: ADR-038.
  • ADR-072 (ikan tangkapan memakai pose showcase horizontal tetap menghadap +X dunia) β€” dibalik langsung satu ADR kemudian oleh ADR-073 (kembali ke pose vertikal kepala-di-atas, menyamping ke kamera). Yang berlaku: ADR-073 (alasan dasar dari ADR-072 β€” arah tetap supaya selalu tegak lurus kamera β€” tetap dipertahankan, hanya pilihan orientasinya yang dibalik).
  • ADR-069 (orientasi ikan tangkapan dihitung ulang tiap frame menghadap ujung rod yang live) β€” digantikan oleh ADR-072 (pose showcase +X tetap), yang kemudian juga dibatalkan oleh ADR-073. Yang berlaku: ADR-073.
  • ADR-039 (banyak angka tuning fight: laju tegangan reel, basePullSpeed, kecepatan reel-in per zona) β€” direvisi berkali-kali di dalam ADR itu sendiri lewat empat "susulan sehari yang sama"; nilai finalnya di dalam log ini adalah hasil susulan #4 (laju tegangan reel 0.55; basePullSpeed 0.2625; kecepatan reel pemain 3.375; kecepatan reel-in zona aman/bahaya 2.0/4.0 m/s), yang selanjutnya sebagian masih diperhalus lagi oleh ADR-054 poin 3 dan ADR-067 poin 3.
  • ADR-065 (versi pertama reel_fight.wav sebagai kejutan sekali-pakai untuk tangkapan bintang 4+) β€” didesain ulang di hari yang sama menjadi loop musik fight yang digerakkan state. Yang berlaku: versi loop musik fight/idle dari ADR-065 yang direvisi, bukan versi kejutan sekali-pakai aslinya.
  • ADR-054 (intensitas haptik dinaikkan secara umum) β€” dinaikkan lagi ke batas maksimum mutlak oleh ADR-060. Yang berlaku: ADR-060 (intensitas 1.0 di semua pola, final).