F0 — Uji Kelayakan Dear Affectionate

Gerbang wajib sebelum satu baris aplikasi dibangun — Panduan Induk 4.4, Bagian 20 Fase 0. Sembilan uji, satu halaman. Prinsip: bangun terkecil → amati → perbaiki rancangan dari kenyataan.
Origin: … | Lulus: 0/9 | crossOriginIsolated: … | Paket: v2q · 11 Nov 2026 (F0 mini — Uji 8 dibangun ulang: Gerbang Empat Aturan Iklan, Panduan 14.6 edisi 4.6)

1 Google OAuth + appDataFolder + kuota Belum

Login Google, tulis/baca berkas di folder HIDDEN per-app (appDataFolder) — BUKAN enkripsi, cuma laci rahasia di Drive. Enkripsi isi berkas diuji terpisah di Uji 3. Baca kuota via about.get. Scope: drive.appdata saja. v2g: OAuth pakai REDIRECT flow (bukan popup) — user di-redirect ke Google, login, kembali ke halaman ini dengan token di URL fragment.

Perbedaan jelas:
• Uji 1 (ini) = folder HIDDEN → Drive UI gak kelihatan, kuota terpisah, app lain gak bisa baca.
• Uji 3 = ENKRIPSI isi berkas → walau ketangan orang, gak bisa dibaca tanpa passkey.
Analogi: Uji 1 = laci rahasia di kamar. Uji 3 = brangkas terkunci di dalam laci.
Catatan untuk pengguna F0: Di aplikasi final, pengguna tidak perlu membuat Client ID — DA punya Client ID sendiri yang terdaftar di Google. Di F0 ini pengguna membuat Client ID sendiri hanya karena DA belum dipublikasikan. Jadi ritual "buat Client ID di Google Cloud Console" itu cuma buat F0, bukan bagian dari pengalaman pengguna nyata.
⚠ Setup tambahan v2g (redirect flow): Selain Authorized JavaScript origins, tambahkan Authorized Redirect URIs di Google Console:
→ https://dear-affectionate.pages.dev/f0.html
→ https://dear-affectionate.pages.dev/f0
Google Auth Platform → Clients → klik Client ID → "Authorized Redirect URIs" → add both URLs.
v2g: redirect flow. Klik 1a → redirect ke Google → login → balang ke sini dengan token. Pastikan Authorized Redirect URIs sudah ditambahkan di Google Console.

2 Cross-device Envelope Unwrap (PRF-KEK + ECDH) Belum

v2d — refactor arsitektur: Kriteria lulus BUKAN "HEX PRF sama lintas perangkat" — credentialId + PRF + biometrik boleh beda per perangkat. Yang harus sama adalah plaintext hasil dekripsi. Arsitektur dua lapis bungkus: Bungkus Recovery (KEK dari PRF Passkey Akun Google → AES-GCM bungkus Master Key) + Bungkus Per-Perangkat (ECDH P-256 per perangkat → bungkus Master Key). Lihat panduan v4.5 Bagian 4.6, 5.2, 6.1, dan Ralat 11 November 2026.

📋 Resep uji (single device):
1. Ketik catatan di atas → klik Buat Kunci Master → biometrik diminta
2. Tutup tab sepenuhnya, buka lagi halaman ini
3. Klik Buka Kunci → biometrik diminta lagi → catatan muncul kembali
📋 Resep uji (cross-device):
1. Di Perangkat 1: Buat + Ekspor → JSON tersalin ke clipboard
2. Di Perangkat 2 (akun Google sama, passkey tersinkron via Google Password Manager): tempel JSON → klik Impor + buka
3. Biometrik Perangkat 2 diminta → catatan harus muncul sama dengan Perangkat 1
v2o: tombol Buka Kunci & Dekripsi SELALU bisa ditekan. Kalau kolom masih berisi teks baru yang belum dienkripsi, sistem berhenti dan kasih tahu kamu dulu — teks gak hilang, gak ditimpa diam-diam.
Butuh konteks aman (HTTPS / localhost) dan browser dengan dukungan PRF (Chrome 128+). Passkey harus tersinkron via Google Password Manager untuk uji cross-device.

3 Enkripsi/dekripsi dari PRF (AES-GCM-256) Belum

Lulus minimal F0: tulis catatan → simpan terenkripsi → tutup tab sepenuhnya → buka lagi → biometrik diminta → teks muncul kembali. Kunci tidak pernah disimpan — hanya PRF passkey.

Ciphertext disimpan di localStorage; kunci hanya hidup saat passkey dipakai.

4 SQLite-WASM + OPFS + FTS5 (+ sqlite-vec) Belum

Query FTS5 pada database di OPFS (brankas). Sub-uji sqlite-vec diuji apa adanya — hasilnya jadi keputusan arsitektur F0.

OPFS butuh crossOriginIsolated (header COOP/COEP dari _headers). Tanpa itu uji jalan di memori.

5 Transliterasi aksara + terjemahan opus-mt-en-id Belum

Mesin transliterasi JSON (pratinjau Fase 6) + terjemahan offline opus-mt-en-id (Apache-2.0) via Transformers.js — model ±80MB diunduh sekali, lalu tersimpan cache.

Terjemahan memakan waktu & kuota unduhan pertama kali.

6 TTS offline multi-bahasa Belum

v2d — fungsi diperluas: DA membacakan catatan offline dalam semua bahasa (Indonesia, Inggris, Mandarin, Korea, Jepang, dll), tanpa internet. Plan A: Piper id_ID via ONNX Runtime Web (self-host wasm). Plan B: Facebook MMS-TTS via Transformers.js — 1100+ bahasa, model ±60-100MB per bahasa diunduh sekali.

Plan A: unduh voice Piper ±60MB. Plan B: unduh model MMS-TTS ±60-100MB per bahasa. Kedua model tersimpan permanen di perangkat setelah unduhan pertama.

7 Keyboard DA di PC & HP: emoticon + tombol PC Belum

Ralat F0: keyboard DA tampil di PC dan HP — emoticon & lain-lain dibawa keyboard DA sendiri (keyboard PC justru tidak punya). Baris teratas: tombol PC (Esc, Tab, Ctrl, Shift, Alt, Home, ←, →, End, Del, ⏎) yang berfungsi nyata di dalam halaman — niatnya: keyboard laptop yang rusak bisa digantikan penuh. Di HP, inputmode="none" meredam keyboard sistem agar tidak menabrak panggung (Fase 6). + tulis/baca clipboard text/html.

Klik huruf + emoji (masuk = bagian 1). Lalu coba tombol PC: Shift → huruf jadi kapital; Ctrl → A/C/V/X/Z; panah/Home/End/Del. ↑/↓ penuh diuji di Fase 6 (kolom ini satu baris).
📋 Resep uji fungsional keyboard DA:
1. Ketik q di kolom → muncul "q"
2. Shift → w → harus muncul W (kapital)
3. Ctrl → a → semua teks terseleksi (Ctrl+A)
4. Ctrl → c → teks tersalin ke clipboard
5. Ctrl → v → teks ditempel
6. ← / → → kursor pindah
7. Home / End → kursor ke ujung kiri / kanan
8. Del → hapus karakter
9. Esc → lepas semua modifier yang sticky
Lulus jika minimal 6 dari 9 berjalan benar.

8 Iklan Empat Aturan + manifest ×2 + COOP/COEP Belum

Gerbang uji iklan (Panduan 14.6 edisi 4.6): slot iklan rumah dirender nyata di halaman ini (zona aplikasi) dan di publik.html (zona publik). Empat aturan diuji mekanis satu per satu + manifest ×2 + isolasi.

🎯 APA YANG DIUJI: Apakah iklan dari jaringan luar (AdSense/EthicalAds/Carbon/dll) bisa masuk lewat pintu yang benar TANPA melanggar satu pun aturan wajib?
Empat aturan wajib: R1 pintu dua jalur — jaringan luar hanya di halaman publik (tanpa COEP), slot in-app tertutup (aset statis, nol iframe/nol skrip jaringan) · R2 bukan video/audio — renderer menolak media non-gambar sebelum dirender · R3 tanpa pemantauan — nol permintaan pihak ketiga, nol cookie, nol beacon saat slot dirender · R4 tidak menutupi konten — bukan position:fixed, ruang tetap (nol layout shift), bounding box tidak bertumpang-tindih konten. Kriteria lulus: keempat aturan LULUS + manifest.json & manifest-publish.json ada + crossOriginIsolated=YA + publik.html ada & tanpa COEP. Gagal satu = gagal semua.

↑ Slot iklan rumah nyata — dirender dari aset lokal ./ikon/donat.svg saat halaman dibuka lewat renderer 4 aturan, bukan gambar hiasan.

Jalankan lewat server/deploy — bukan file://.

9 Chroma-key MP4 → WebM transparan Belum

Logo Loading (donat infinity, latar hitam) dikonversi nyata di sandbox: colorkey=black → VP8 yuva420p (alpha_mode=1), 432×240, 5 detik, 603KiB. Mainkan di atas latar ungu starry — tidak boleh ada kotak background, lubang donat transparan.

Konversi sudah terbukti di sandbox (ffmpeg 7.1.5). Uji playback = manual per browser.