Tovább a tartalomhoz

Többszereplős mód – identitás, tagság és jelenlét

A Control Center egyetlen üzemeltetővel is működik, de a mögötte lévő modell eleve több szereplős. Az emberek és az ügynökök ugyanazokban a terekben üzennek, ugyanazokat a jegyeket szerkesztik, és ugyanazon a névsoron jelennek meg. Hogy ez biztonságos és átlátható legyen, három döntésen múlik: ki számít szereplőnek, mi kapuzza a hozzáférést, és mely állapot megosztott tartósan, illetve csak élőben sugárzott.

Principalok: a felhasználók és az ügynökök egyenrangú szereplők

Szekció neve “Principalok: a felhasználók és az ügynökök egyenrangú szereplők”

Minden, ami rögzíti, hogy „ki tette ezt” – üzenetek, jegyek, átnézések, tervek, futásnaplók, auditbejegyzések –, egy Principalon keresztül oldódik fel: ez a UserPrincipal és az AgentPrincipal lezárt uniója, tömör átviteli formával (user:<id> / agent:<id>). Az attribúció soha nem von össze N embert (vagy N ügynököt) egyetlen sentinelfiókba, így az ügynök által hagyott átnézés és az ember által hagyott átnézés mindenhol megkülönböztethető, ahol csak megjelenik.

Mivel a Principal az identitás egysége, egyben az elkülönítés egysége is:

  • A sebességkorlátok Principalonként értendők, nem munkamenetenként. A távoli eszközhívások túlterhelés-védelme felhasználónként, nem kapcsolatonként számol: egy tag összes eszköze egyetlen közös csúszóablakból gazdálkodik (percenként 120 hívás, amelyből legfeljebb 30 módosíthat), így három eszköz megnyitása nem háromszorozza meg senki keretét, és egy zajos tag sem éheztetheti ki a többieket.
  • A visszavonás is Principalonként működik. Minden kliens műveletnaplója csak azokat a módosításokat rögzíti, amelyeket az ő Principalja hajtott végre. A saját jegyszerkesztését visszavonhatja ⌘Z-vel; egy csapattársáét nem – mire meglátja, a tartós sáv már fel is oldotta azt (lásd alább).

A tagság a hozzáférési határ – nem a párosítási kulcs

Szekció neve “A tagság a hozzáférési határ – nem a párosítási kulcs”

Két külön hitelesítő adat két külön kérdésre válaszol. A párosítási kulcs (lásd: Távoli vezérlés és mobil) egy eszközt hitelesít a szerver felé. A tagság jogosítja fel az adott eszköz felhasználóját, hogy egy munkaterületen belül cselekedjen. Egy párosított eszköz, amelynek felhasználója nem tagja az adott munkaterületnek, sem olvasni, sem módosítani nem tudja azt.

A tagság (munkaterület, felhasználó) páronként egyetlen sor, amelyet az adott munkaterület saját adatbázisfájlja tárol – így a „ki van ebben a munkaterületben?” kérdés közönséges, hatókörre szűkített olvasás, míg a fordított kérdés, hogy „mely munkaterületekben vagyok benne?“, szükségszerűen fájlokon ível át, és azon kevés engedélyezett, munkaterületek közötti szétosztás egyike. Ezt futtatja a munkaterület-választó, mielőtt bármelyik munkaterületet kiválasztanák.

Minden sor egy szerepet hordoz egy ötszintű, rangsorolt létráról:

Szerep Mit tehet
owner Teljes ellenőrzés, a munkaterület törlését is beleértve; munkaterületenként pontosan egy
admin Tagok, meghívók, beállítások és destruktív műveletek kezelése
member Mindennapi olvasás-írás: üzenetek, jegyek, ügynökfutások
viewer Írásvédett a teljes munkaterületen; a titokkizáró globok elrejtik az egyező útvonalakat a kódot tartalmazó felületeken
guest Ugyanaz az írásvédett minimum, mint a viewer esetében, a ranglétra legalján

Minden hozzáférési döntés arra redukálódik, hogy „a hívó szerepe legalább X-e”. A minimum a művelet fajtájából következik, hacsak az kifejezetten nem deklarál mást: egy olvasáshoz guest, egy módosításhoz member, egy destruktív művelethez admin kell. Az alábbi, repónkénti jogosultságokon túli objektumszintű ACL-ek szándékosan kívül esnek a hatókörön.

A meghívókkal lehet tagságot adni, a Beállítások → Munkaterület → Tagok helyen. Az admin egyszer használatos kódot állít ki (hivatkozásként vagy QR-ként), amely alapértelmezés szerint hét nap után lejár; a szerver csak a kód SHA-256-os hash-ét tárolja, magát a kódot pedig pontosan egyszer mutatja meg. Beváltásakor a rendszer JIT-provisionálja a felhasználót, rögzíti a tagságot a meghívó szerepével (soha nem owner – a tulajdonjogot kifejezetten át kell adni, meghívóval soha nem jár), és átadja a folyamatot az eszközpárosításnak. A párosítás után kiállított eszközhitelesítő adatok maguk is 30 napra korlátozottak, így egy párosítás nem állandó kulcs.

A repónkénti jogosultságok a tagság alatt helyezkednek el. Mivel a szerver teljes checkoutokat tart, a munkaterület-tagság önmagában soha nem biztosíthat több jogot, mint a kódhoszt: minden kódot tartalmazó felület – fájlok, difjek, PR-átnézés, kódkeresés – az adott tag azon a repón érvényes jogosultságát ellenőrzi. A jogosultságok (munkaterület, felhasználó, repó) hármasonként értendők, rangsoruk pedig none → read → review → write, ahol a write azt jelenti, hogy olyan ügynökfutásokat vezet, amelyek a repóba írnak. Egy sor hiánya none-t jelent; a tulajdonosok és az adminok minden kapcsolt repón implicit módon write joggal bírnak, és egyáltalán nem hordoznak sorokat.

Az együttműködési állapot két sávja

Szekció neve “Az együttműködési állapot két sávja”

A Control Center két sávra bontja a megosztott állapotot, ellentétes tartóssági szabályokkal, mert a kétféle állapot ellentétes módon romlik el.

A jelenlét – ki van online, hol tartózkodik, mit gépel épp, mit csinál éppen egy ügynök – abban a pillanatban értéktelenné válik, amint elavul. Ha tárolnánk, minden újracsatlakozásnak össze kellene egyeztetnie a valósággal azt, hogy „az adatbázis szerint Sam épp ezt a jegyet szerkeszti”. Ezért a jelenlét soha nem kerül az adatbázisba. Egy szerveroldali, memóriabeli jelenléti központban él: a kliensek a presence.update hívással publikálnak, a társak a presence.watch hívással iratkoznak fel, a bejegyzések pedig három kihagyott szívverés után automatikusan lejárnak (a szívverések 10 másodpercenként futnak, a központ 5 másodpercenként takarít). Nincs mit összeegyeztetni – csak hagyni, hogy elmúljon.

Két tulajdonság teszi megbízhatóvá a sávot:

  • Az identitás a munkamenetből származik, soha nem kliensargumentumokból. A szerver a kapcsolat hitelesített eszközét egy felhasználói azonosítóra képezi le; egy kliens csak a saját jelenlétét frissítheti, így senki nem tudja meghamisítani egy másik résztvevő állapotát vagy tartózkodási helyét. Egy kifejezett offline frissítés (leválás vagy a láthatatlan mód kapcsolója) azonnal eltávolítja a bejegyzést.
  • A névsor a jelenléti központon keresztül jut el mindenkihez. A társak soha nem cserélnek jelenlétet közvetlenül, így minden résztvevő ugyanazt a névsort látja, függetlenül a topológiától. Az ügynököknek nincs kliensük, ezért a szerver szintetizálja a bejegyzéseiket az élő futásállapotból – gondolkodik, fut, jóváhagyási kapunál blokkolva, kész –, és egyetlen reprezentatív futás dönti el az ügynök állapotát és tartózkodási helyét, hogy a párhuzamos futások ne rezegtessék a névsort.

A szétosztás fogyasztónként rétegezett: az asztali és a webes kliens a teljes rétegen utazik (legfeljebb 100 ms-onként egy névsorkibocsátás), a telefon pedig egy összegző rétegen (500 ms-onként), így a kurzorritmusú frissítések nem olvaszthatják meg a PWA-t.

Egy résztvevő tartózkodási helye – hogy épp hol van, egészen az artefaktumig – lezárt unió: Space, File (repó + útvonal + opcionális sor), Pr, Ticket, PlanNode. Nem minden tartózkodási helynek van hova ugrani: nincs fájlmegjelenítő útvonal, ezért a File tartózkodási hely címkeként jelenik meg, nem célpontként. A sáv puha jelzéseket is szállít („Sam épp ezt a jegyet szerkeszti”, „egy ügynök birtokolja ezt a worktree-t”): az ütközés láthatóságát, nem zárolásokat. Az ismeretlen fajtájú tartózkodási helyek null értékre értelmeződnek, így egy régi kliens egyszerűen nem jeleníti meg azt, amit nem ért.

A túlélést igénylő rekordok – jegyek, a tér megosztott Jegyzetek-dokumentuma, üzenetek – az ellenkező utat járják: mérvadók, sorrendezettek és tároltak. A párhuzamos szerkesztéseket az utolsó író nyer elv oldja fel, a szerver beérkezési sorrendje szerint, soha nem kliensórák alapján. A feloldás szándékosan finom felbontású: a jegyszerkesztések oszloponkéntiek, így két ember ugyanazon jegy különböző mezőit szerkesztve is sikeresen érvényesül, és egyikük sem írja felül a másikat (a munkafolyamat-átmeneteknél ehelyett optimista zárolás marad); a tér Jegyzetek-dokumentuma egyetlen oszlop, így a teljes dokumentumra LWW érvényes, és a jelenléti sávon lévő puha jelzések teszik láthatóvá a párhuzamos szerkesztést a zárolás helyett. Ez szándékosan nem CRDT – a bizonyítási teher a CRDT-n van, a beérkezési sorrend szerinti LWW pedig a látható jelzésekkel együtt lefedi a tényleges együttműködési mintákat.

Az „utolsó író” a szerver beérkezési sorrendjét jelenti, soha nem egy kliensórát – egy elállított órájú laptop nem nyerhet meg egy szerkesztést, amelyet elveszített. A tartós sáv mögött a szinkronizációs folyam áll: az SQLite triggerek minden módosítást hozzáfűznek egy munkaterületenkénti változásnaplóhoz, magán az írási tranzakción belül, és ugyanabban a tranzakcióban osztanak ki egy monoton, munkaterületenkénti sorszámot, mint magát a módosítást. Egy szerveroldali szolgáltatás sorrendben, verziózott delta keretekké olvassa ki ezt a naplót. A kliensek a teljes pillanatképektől a delták felé fejlődnek; a sorozatban keletkező hézag inkább pillanatkép-módba ejti vissza az adott tárolót, mintsem hogy hibásan alkalmazza a kereteket.

Követés, irányítás, átvétel, visszaadás

Szekció neve “Követés, irányítás, átvétel, visszaadás”

A jelenléti sáv nem csupán névsor – az együttműködés igéit vezérli:

  • Követési mód. Kattintson egy résztvevőre, és a kliense az ő tartózkodási helyén utazik, úgy navigálva, ahogyan ő navigál. A követés „addig tart, amíg Ön nem cselekszik”: abban a pillanatban, hogy saját magától navigál, a követés leválik. Egy bezárható banner jelzi, amikor egy másik résztvevő épp bemutat egy teret, amelyben Ön is jelen van.
  • Irányítás. A futó ügynöknek küldött üzenet irányítóüzenetként kerül várólistára; az ügynök a következő köre folytatása előtt újraolvassa, így menet közben is terelheti a futást anélkül, hogy leállítaná.
  • Átvétel. Egy beszélgetés irányításának átvétele minden aktív futást szüneteltet a következő tiszta körhatárnál (egy Claude Code-futás, amelynek nincs biztonságos határa, leáll), körönkénti git-pillanatkép mögött, így az átvétel visszafordítható. Egy tartós jelölő blokkolja a térbe induló új küldéseket, és túléli a szerver újraindítását – a szerver soha nem folytatja automatikusan a munkát egy ember félbehagyott szerkesztésébe. Worktree-nként egy élő szerkesztő egy puha jelzés: egy második átvétel látható és elutasításra kerül, nem olvad bele csendben.
  • Visszaadás. Az irányítás visszaadása egy strukturált diff-összefoglalót tesz közzé a worktree-ről a térben, irányítóüzenetként várólistára teszi a szüneteltetett futások számára, folytatja őket, és törli a jelölőt.

Az irányítás és az átvétel utólagos beavatkozások. Az autonómiaszabályzó az állandó beállítás: térenként és ügynökönként, a tér fejlécéből állítható, és eldönti, mi történik, amikor egy ügynök egy kapuzott művelethez ér.

Szint Átviteli érték Hatás egy kapuzott eszközhívásra
Csak javaslat proposeOnly Azonnal elutasítva, egy indoklással, amelyet az ügynöknek tovább kell adnia – leírhatja a műveletet, de nem hajthatja végre
Cselekvés jóváhagyással actWithApproval A hibazáró jóváhagyási kapu: egy megerősítés jelenik meg egy csatlakozott üzemeltetőnél, és ha nincs jóváhagyó, az elutasítást jelent
Szabad cselekvés actFreely Előre jóváhagyva, kivéve, ahol kemény deny korlátszabály érvényes – a deny szabály mindig nyer
(nincs beállítva) null Ugyanaz, mint a jóváhagyással történő cselekvés: a szerver alapértelmezése

Két dolog mindkét irányban a szabályzón kívül esik. Egy mód saját kimeneti igéje rögzített, és soha nem utasítható el, bármit is mond a szabályzó – az orchestrációs mód egykor szerkezetileg képtelen volt kiadni az egyetlen szállítható eredményét, mert egy előbeállítás megtagadta azt a hatásosztályt, amelyet az az ige deklarál. A műveletkorlátok kemény deny-je pedig nem írható felül actFreely-jel.

Mindez additív. Az egyedül dolgozó üzemeltető munkafolyamata változatlan: egyetlen emberrel és ügynökök nélkül a jelenléti központnak nincs mit sugároznia, így a sáv kibocsátja a kezdeti pillanatképét, majd nulla forgalmon tétlenkedik; az LWW- és szinkrongépezet ugyanaz az egyetlen írós útvonal, ami mindig is volt; a párosítási kulcs pedig ugyanaz az eszközhitelesítő adat marad, ami mindig is volt. A tagság már önmagában a hozzáférési határ – egyetlen ember esetén egyetlen tulajdonosi sor létezik, és nincs semmiféle névsorhoz tartozó felületi elem.