Multiplayer — identitas, keanggotaan, dan kehadiran
Control Center bekerja untuk satu operator, tetapi model di baliknya bersifat multi-aktor sejak awal. Manusia dan agen mengirim pesan di space yang sama, menyunting tiket yang sama, dan muncul pada daftar kehadiran yang sama. Membuat itu aman dan mudah dipahami bermuara pada tiga keputusan: siapa yang dihitung sebagai aktor, apa yang menggerbangi akses, dan state mana yang dibagikan secara tahan lama versus sekadar disiarkan langsung.
Prinsipal: pengguna dan agen adalah aktor yang setara
Bagian berjudul “Prinsipal: pengguna dan agen adalah aktor yang setara”Segala sesuatu yang mencatat “siapa melakukan ini” — pesan, tiket, tinjauan,
rencana, log run, entri audit — diselesaikan melalui sebuah Principal, union
tersegel dari UserPrincipal dan AgentPrincipal dengan bentuk wire yang
ringkas (user:<id> / agent:<id>). Atribusi tidak pernah meleburkan N manusia
(atau N agen) menjadi satu akun sentinel, sehingga tinjauan yang ditinggalkan
agen dan tinjauan yang ditinggalkan manusia dapat dibedakan di mana pun keduanya
muncul.
Karena prinsipal adalah unit identitas, ia juga unit pembatasan:
- Batas laju bersifat per prinsipal, bukan per sesi. Pengaman banjir pada panggilan alat jarak jauh menganggarkan per pengguna, bukan per koneksi: semua perangkat seorang anggota mengambil dari satu jendela geser bersama (120 panggilan per menit, yang paling banyak 30 di antaranya boleh mengubah data), sehingga membuka tiga perangkat tidak melipattigakan jatah siapa pun dan satu anggota yang berisik tidak bisa membuat yang lain kelaparan.
- Pembatalan bersifat per prinsipal. Jurnal tindakan setiap klien hanya mencatat mutasi yang dilakukan prinsipal itu. Anda dapat ⌘Z edit tiket Anda sendiri; Anda tidak bisa membatalkan milik rekan satu tim — saat Anda melihatnya, jalur tahan lama sudah menyelesaikannya (lihat di bawah).
Keanggotaan adalah batas akses — bukan kunci pemasangan
Bagian berjudul “Keanggotaan adalah batas akses — bukan kunci pemasangan”Dua kredensial terpisah menjawab dua pertanyaan yang terpisah. Kunci pemasangan (lihat Kontrol jarak jauh dan seluler) mengautentikasi sebuah perangkat ke server. Keanggotaan memberi wewenang kepada pengguna perangkat itu untuk bertindak di dalam sebuah ruang kerja. Perangkat yang dipasangkan tetapi penggunanya tidak memegang keanggotaan di suatu ruang kerja tidak dapat membaca maupun mengubahnya.
Keanggotaan adalah satu baris per (ruang kerja, pengguna), yang disimpan di berkas basis data milik ruang kerja itu sendiri — jadi “siapa saja yang ada di ruang kerja ini?” adalah pembacaan bercakupan biasa, sedangkan pertanyaan kebalikannya, “saya berada di ruang kerja mana saja?”, pasti melintasi berkas dan merupakan salah satu dari sedikit fan-out antar-ruang kerja yang diizinkan. Itulah yang dijalankan oleh pemilih ruang kerja sebelum ruang kerja mana pun dipilih.
Setiap baris membawa peran dari tangga lima tingkat yang diurutkan berdasarkan peringkat:
| Peran | Boleh |
|---|---|
owner |
Kendali penuh, termasuk penghapusan ruang kerja; tepat satu per ruang kerja |
admin |
Mengelola anggota, undangan, pengaturan, operasi destruktif |
member |
Baca-tulis sehari-hari: pesan, tiket, run agen |
viewer |
Hanya-baca di seluruh ruang kerja; glob pengecualian rahasia menyembunyikan path yang cocok pada permukaan yang memuat kode |
guest |
Tingkat hanya-baca yang sama dengan viewer, pada peringkat terendah di tangga |
Setiap keputusan akses bermuara pada “apakah peran pemanggil setidaknya X”.
Tingkat lantainya diturunkan dari jenis operasi kecuali operasi itu
mendeklarasikannya secara eksplisit: pembacaan membutuhkan guest, mutasi
membutuhkan member, operasi destruktif membutuhkan admin. ACL per objek di
luar pemberian izin per repo di bawah ini sengaja berada di luar cakupan.
Undangan adalah cara keanggotaan diberikan, dari Pengaturan → Ruang kerja →
Anggota. Seorang admin menerbitkan kode sekali pakai (berupa tautan atau QR)
yang kedaluwarsa setelah tujuh hari secara bawaan; server hanya menyimpan hash
SHA-256 dari kode itu dan kodenya sendiri ditampilkan tepat sekali. Menukarkannya
menyediakan pengguna tersebut secara JIT, mencatat keanggotaan pada peran
undangan (tidak pernah owner — kepemilikan dialihkan secara eksplisit, tidak
pernah diberikan lewat undangan) dan menyerahkannya ke pemasangan perangkat.
Kredensial perangkat yang diterbitkan setelah pemasangan pun dibatasi waktunya
30 hari, jadi pemasangan bukan kunci permanen.
Pemberian izin repo berada di bawah keanggotaan. Karena server memegang
checkout penuh, keanggotaan ruang kerja saja tidak boleh pernah memberi hak
istimewa melebihi forge: setiap permukaan yang memuat kode — berkas, diff,
tinjauan PR, pencarian kode — memeriksa izin anggota pada repo itu. Pemberian
izin bersifat per (ruang kerja, pengguna, repo) dan diperingkat none → read
→ review → write, di mana write berarti menjalankan run agen yang menulis
ke repo. Tidak adanya baris berarti none; pemilik dan admin secara implisit
memegang write pada setiap repo yang tertaut dan tidak membawa baris sama
sekali.
Dua jalur state kolaborasi
Bagian berjudul “Dua jalur state kolaborasi”Control Center memisahkan state bersama ke dalam dua jalur dengan aturan ketahanan yang berlawanan, karena kedua jenis state itu gagal dengan cara yang berlawanan.
Jalur kehadiran yang sementara
Bagian berjudul “Jalur kehadiran yang sementara”Kehadiran — siapa yang online, di mana mereka berada, apa yang sedang mereka
ketik, apa yang sedang dilakukan agen saat ini — tidak bernilai begitu menjadi
basi. Seandainya dipersistenkan, setiap penyambungan ulang harus
merekonsiliasi “basis data mengatakan Sam sedang menyunting tiket ini” dengan
kenyataan. Jadi kehadiran tidak pernah ditulis ke basis data. Ia hidup di
hub kehadiran dalam memori di server: klien memublikasikan dengan
presence.update, peer berlangganan dengan presence.watch, dan entri
kedaluwarsa otomatis setelah tiga heartbeat yang terlewat (heartbeat berjalan
setiap 10 detik; hub menyapu setiap 5 detik). Tidak ada yang perlu
direkonsiliasi — hanya dibiarkan luntur.
Dua sifat menjaga jalur ini tetap dapat dipercaya:
- Identitas berasal dari sesi, tidak pernah dari argumen klien. Server
memetakan perangkat terautentikasi milik koneksi ke sebuah id pengguna; klien
hanya pernah bisa memperbarui kehadirannya sendiri, sehingga tidak ada yang
dapat memalsukan status atau lokasi peserta lain. Pembaruan
offlineyang eksplisit (terputus atau tombol tak terlihat) menghapus entri itu seketika. - Daftar kehadiran dipusatkan di server. Peer tidak pernah bertukar kehadiran secara langsung, sehingga setiap peserta melihat daftar yang sama apa pun topologinya. Agen tidak punya klien, jadi server menyintesis entri mereka dari state run langsung — berpikir, berjalan, terblokir di gerbang persetujuan, selesai — dengan satu run perwakilan yang menentukan state dan lokasi seorang agen agar run yang bersamaan tidak membuat daftar itu bergetar.
Fan-out bertingkat per konsumen: desktop dan web menempuh tingkat penuh (paling banyak satu emisi daftar per 100 ms), ponsel menempuh tingkat ringkasan (per 500 ms), sehingga pembaruan secepat kursor tidak bisa melelehkan PWA.
Lokasi seorang peserta — tempat mereka berada saat ini, hingga ke
artefaknya — adalah union tersegel: Space, File (repo + path + baris
opsional), Pr, Ticket, PlanNode. Tidak setiap lokasi punya tempat untuk
dituju: tidak ada rute penampil berkas, jadi lokasi File dirender sebagai
label alih-alih tujuan. Jalur ini juga membawa klaim lunak (“Sam sedang
menyunting tiket ini”, “seorang agen memegang worktree ini”): visibilitas
konflik, bukan kunci. Jenis lokasi yang tidak dikenal diuraikan menjadi null,
sehingga klien lama sekadar tidak merender apa yang tidak dipahaminya.
Jalur bersama yang tahan lama
Bagian berjudul “Jalur bersama yang tahan lama”Catatan yang harus bertahan — tiket, dokumen Catatan space bersama, pesan — menempuh jalur sebaliknya: otoritatif, terurut, dan dipersistenkan. Edit yang bersamaan diselesaikan dengan last-writer-wins dalam urutan penerimaan server, bukan berdasarkan jam klien. Penyelesaiannya sengaja dibuat berbutir halus: edit tiket bersifat per kolom, sehingga dua orang yang menyunting bidang berbeda pada tiket yang sama sama-sama diterapkan dan tidak ada yang menimpa yang lain (transisi alur kerja tetap memakai penguncian optimistis); dokumen Catatan space adalah satu kolom, sehingga seluruh dokumen bersifat LWW dengan klaim lunak di jalur kehadiran yang membuat penyuntingan bersamaan terlihat alih-alih terkunci. Ini sengaja bukan CRDT — beban pembuktian ada pada CRDT, dan LWW berdasar urutan penerimaan plus klaim yang terlihat mencakup pola kolaborasi yang nyata.
“Penulis terakhir” berarti urutan penerimaan server, tidak pernah jam klien — laptop dengan jam yang melenceng tidak dapat memenangkan edit yang sudah kalah. Di balik jalur tahan lama berdiri feed sinkronisasi: trigger SQLite menambahkan setiap mutasi ke log perubahan per ruang kerja di dalam transaksi penulisan, mengalokasikan nomor urut monotonik per ruang kerja dalam transaksi yang sama dengan mutasinya. Sebuah layanan server mengekor log itu menjadi frame delta berversi sesuai urutan. Klien berkembang dari snapshot penuh menjadi delta; celah dalam urutan menjatuhkan penyimpanan itu kembali ke mode snapshot alih-alih salah menerapkan frame.
Ikuti, arahkan, ambil alih, kembalikan
Bagian berjudul “Ikuti, arahkan, ambil alih, kembalikan”Jalur kehadiran bukan sekadar daftar — ia menggerakkan verba kolaborasi:
- Mode ikuti. Klik seorang peserta dan klien Anda mengikuti lokasinya, bernavigasi saat ia bernavigasi. Ikuti bersifat “sampai Anda bertindak”: begitu Anda bernavigasi atas kemauan sendiri, mode ikuti melepas. Spanduk yang dapat ditutup memberi tahu saat peserta lain sedang menyorot (mempresentasikan) space tempat Anda berada.
- Arahkan. Pesan ke agen yang sedang berjalan diantrekan sebagai pengarahan; agen membacanya ulang sebelum melanjutkan giliran berikutnya, sehingga Anda dapat mendorong sebuah run di tengah jalan tanpa menghentikannya.
- Ambil alih. Mengambil kendali atas sebuah percakapan menjeda setiap run aktif di batas giliran bersih berikutnya (run Claude Code, yang tidak punya batas aman, dihentikan) di balik snapshot git per giliran, sehingga pengambilalihan dapat dibalik. Penanda tahan lama memblokir pengiriman baru ke space itu dan bertahan melewati mulai ulang server — server tidak pernah melanjutkan otomatis ke edit manusia yang belum selesai. Satu editor aktif per worktree adalah klaim lunak: pengambilalihan kedua terlihat dan ditolak, bukan digabungkan diam-diam.
- Kembalikan. Mengembalikan kendali memposting ringkasan diff terstruktur worktree ke space, mengantrekannya sebagai pengarahan untuk run yang dijeda, melanjutkan run itu, dan menghapus penanda.
Dial otonomi
Bagian berjudul “Dial otonomi”Pengarahan dan pengambilalihan adalah intervensi setelah kejadian. Dial otonomi adalah pengaturan tetap: per space, per agen, ditetapkan dari header space, ia menentukan apa yang terjadi saat agen mencapai tindakan yang digerbangi.
| Tingkat | Nilai wire | Efek pada panggilan alat yang digerbangi |
|---|---|---|
| Hanya usulkan | proposeOnly |
Ditolak langsung, dengan alasan yang harus disampaikan agen — ia dapat menjelaskan tindakan itu tetapi tidak melakukannya |
| Bertindak dengan persetujuan | actWithApproval |
Gerbang persetujuan yang fail-closed: satu konfirmasi muncul ke operator yang terhubung dan tanpa penyetuju berarti ditolak |
| Bertindak bebas | actFreely |
Disetujui sebelumnya, kecuali jika aturan pagar pengaman deny yang keras berlaku — aturan deny selalu menang |
| (tidak ditetapkan) | null |
Sama dengan bertindak dengan persetujuan: bawaan server |
Dua hal berada di luar dial itu ke dua arah. Verba keluaran milik sebuah mode
dipatok dan tidak pernah bisa ditolak, apa pun kata dial itu — mode orkestrasi
pernah secara struktural tidak mampu mengeluarkan satu-satunya luarannya karena
sebuah preset menolak kelas efek yang dideklarasikan verba tersebut. Dan deny
keras dari pagar pengaman tindakan tidak dapat ditimpa oleh actFreely.
Solo tanpa regresi
Bagian berjudul “Solo tanpa regresi”Semua ini bersifat aditif. Alur kerja operator solo tidak berubah: dengan satu manusia dan tanpa agen, hub kehadiran tidak punya apa pun untuk disiarkan, sehingga jalur itu memancarkan snapshot awalnya lalu menganggur tanpa lalu lintas sama sekali; mesin LWW dan sinkronisasi adalah jalur penulis tunggal yang sama seperti selama ini; dan kunci pemasangan tetap menjadi kredensial perangkat seperti selama ini. Keanggotaan sudah menjadi batas akses — dengan satu manusia hanya ada satu baris owner dan tidak ada elemen antarmuka daftar kehadiran.
Konsep terkait
Bagian berjudul “Konsep terkait”- Ruang kerja dan isolasi: batas yang ditegakkan keanggotaan
- Kontrol jarak jauh dan seluler: sisi kunci pemasangan dan kredensial perangkat dari identitas
- Model agen: separuh agen dari union prinsipal
- Siklus hidup pengiriman agen: run yang dijeda dan dilanjutkan oleh pengarahan dan pengambilalihan
- Pagar pengaman: kebijakan kelas efek yang dipadukan dengan dial otonomi
- Peristiwa domain: bus yang ditumpangi pembaruan langsung